2012-05-11 4 views
1

모든 Rangy Q &을 조사했지만이 경우에는 아무런 변화가 없습니다.Rangy는 contenteditable 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 
} 

나는이 포럼에 다른 글에서 저자가 제시 한 다음 돌아 다니기에 알맞은 기반 기능을 사용 : 내가 문자를 삭제하려고 할 때까지

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 : 두 번째 코드 블록은 문자 인덱스 기반 저장 및 선택 복원을 수행하므로 'innerHTML'교체 후 보이는 텍스트가 변경되지 않는 한 작동해야합니다. –

+0

@TimDown 지금 무슨 뜻인지 알기 전에 그 부분을 방금 건너 뛴 것입니다. 나는 아직도이 일에 대한 나의 의구심을 가지고있다. 정규식 중 일부는 깨진 마크 업을 만드는 것처럼 보입니다. "".replace (/ (<([^>) +)>) /, '') // "" –

답변

0

작동하는 것처럼 보입니다. 선택을 복원하기 전에 메서드를 사용하여 내용 편집 가능 <div> 메서드를 호출하는 것처럼 간단 할 수 있습니다.

+0

안녕하세요, 귀하의 제안에 따라 다음을 추가했습니다 : \t \t $ ('# area').초점(); \t \t restoreSelection (el, savedSel); }하지만 여전히 삭제를 누르면 작동하지 않습니다. 마지막 문자를 삭제하고 div 시작 부분에서 점프합니다. 그것은 당신이 타자를 치는 때 완벽하게 작동하므로 이상합니다. 그것은 빈에 블록이 생성되고 첫 번째 Range.StartContainer.nodeName = "SPAN"이 삭제 된 것 같습니다. 이것이 원인이 될까요? – Gian

+0

업데이트 :이 문제는 다른 문제와 관련이 있다고 생각합니다. Shift + 오른쪽 화살표를 누르면 앞으로 나오는 문자가 정확하게 강조 표시됩니다. 왼쪽 화살표를 사용하려고하면 한 문자를 강조 표시 한 다음 커서를 왼쪽으로 이동하고 다른 문자를 강조 표시합니다. 삭제 또는 뒤로 향하게하는 것과 같은 거꾸로 동작이 마음에 들지 않는 논리가 있다고 생각합니다. 감사. – 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); 
}; 
​ 

희망을.