2013-04-12 1 views
2

최소한의 JavaScript WYSIWYG 컨트롤을 만들고 있습니다.최소 JavaScript wysiwyg - 이미 존재하는 경우 선택된 텍스트에서 태그 제거

:

, 그것은

여기

는 지금까지 최소 작동 코드를 벗었 한 것입니다 등 브라우저에서 일관성 나는 그것이 임의의 HTML을 허용하지 않기 때문에 document.execCommand을 사용하지 않으

있어

http://jsfiddle.net/2WxQn/1/

<button data-action="strong"><strong>b</strong></button> 
<button data-action="em"><em>i</em></button> 
<button data-action="u"><u>u</u></button> 
<p contenteditable>The quick brown fox jumps over the lazy dog.</p> 
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> 
<script> 
    $(function(){ 
    $('button').on('click', function(){ 
     var selection = window.getSelection();     
     var range = selection.getRangeAt(0);   
     var action = $(this).attr('data-action');    
     var node = document.createElement(action); 
     var frag = range.extractContents(); 
     node.appendChild(frag); 
     range.insertNode(node); 

     return false;   
    }); 
    }); 
</script> 

는 선택의 일부는 이미 강력한 태그가 포함되어있는 경우 (또는 무엇이든), 어떻게 있도록해야합니까 두 번째는 이러한 태그를 제거 버튼을 클릭하는 대신 새로운 강력한와 선택을 포장 꼬리표?

이 질문을 작성하면 나에게 아이디어가 주어집니다. 나는 지금 시도해보고 작동한다면 내 자신의 질문에 답할 것입니다 - 다른 사람이이 문제를 제기 할 경우를 대비하여이 질문이 여기에 있습니다. 그렇지 않으면 나는 유혹 숨 :

편집하여 도움을 기다리고한다 분명히 다른 사람 게시물 작업 솔루션 경우가 더 나은 경우, 나는 오히려 내보다 자신의 대답을 받아 들일 것입니다.

EDIT (2) : 내 아이디어가 나지 않았습니다. 뭔가 (아마 range.insertNode)가 마술처럼 태그의 균형을 잡아줍니다. 선택이 주어진 태그 안에 있는지 항상 알기 위해 selection, range 또는 frag로부터 충분한 정보를 갖고 있지 않은 것 같습니다. 어떤 아이디어?

+0

난 당신이 이렇게 몇몇 코드와 간단한 WYSIWYG 편집기를 만들 수 놀랐다! – Uooo

+0

마술을하는 것은'extractContents()'입니다. DOM 트리에서 범위가 완전히 다른 수준에있을 때 올바른 형식의 문서 조각을 임의의 범위에서 만들고 올바른 형식의 상태로 유지하려면 노드의 일정량 복제가 필요할 수 있습니다. –

+0

안녕하세요 @TimDown - 너 랑지가 쓴거야? - extractContents에서 반환 된 객체에 도움이되는 내용이없는 것 같습니다. 아이디어가 있습니까? 막연하게 내 마음 속에서 모양을 잡는 것은 선택에서 anchorNode 및 focusNode를 가져와 dom의 가장 가까운 부모에게 걸어 가야하고 그런 다음 몇 가지 종류의 참조 계산을 다시 시도해야 할 수도 있다는 것입니다. 태그의 균형을 직접 조정할 수 있습니까? 내가 올바른 길을 가고 있다고 생각하니 다른 아이디어가 있습니까? – nrkn

답변

1

편집 : 이것은 좋은 해결책이 아닙니다. 한 줄의 단순한 텍스트보다 더 복잡한 것으로 완전히 분해됩니다. 나는 해결했고 곧 더 나은 해결책을 게시 할 것입니다.

알아 냈어.

나는 각 텍스트 노드를 wysiwyg 영역에 포함하는 배열과 그 부모 태그의 목록을 만듭니다.

은 그럼 나중에 쉽게 제거 될 수 있도록 사용자 정의 요소의 선택을 포장하고 권장하는대로 그렇게하지 x 축 접두사를 사용하여, 기존의 HTML 요소와 충돌 할 수 있습니다.

그런 다음 wysiwyg 요소의 내용을 해당 목록에서 다시 작성하고 선택 항목의 모든 노드에서 클릭 한 단추의 태그를 모두 제거했으면 단추를 제거합니다. 대부분의 wywiwyg 편집기가이를 처리하는 방법입니다.

http://jsfiddle.net/x7WRZ/

<button data-action="B"><b>b</b></button> 
<button data-action="I"><i>i</i></button> 
<button data-action="U"><u>u</u></button> 
<p contenteditable>The quick brown fox jumps over the lazy dog.</p> 
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> 
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script> 
<script> 
    $(function(){  
    var selectionWrapper = 'X-SELECTION'; 

    function getTextData(element) { 
     function getTextNodesIn(root) { 
     var textNodes = []; 
     var parents = []; 

     function getTextNodes(node) { 
      if(node.nodeType === 3){  
      var text = node.textContent; 
      textNodes.push({ 
       text: text, 
       parents: parents.slice(0) 
      }); 
      } else { 
      if(node !== root){ 
       parents.push(node.tagName); 
      } 
      for(var i = 0, len = node.childNodes.length; i < len; ++i){ 
       getTextNodes(node.childNodes[ i ]); 
      } 
      parents.pop(); 
      } 
     } 

     getTextNodes(element); 

     return textNodes; 
     }  

     return getTextNodesIn(element); 
    } 

    function handleSelection(container, action) { 
     var textData = getTextData(container); 
     container.innerHTML = ''; 

     //if every textNode in the selection has action as a parent, we want 
     //to remove it from all of them. 
     var selection = _(textData).filter(function(data){ 
     return _(data.parents).contains(selectionWrapper); 
     }); 
     var remove = _(selection).every(function(data) { 
     return _(data.parents).contains(action) || data.text.trim() === ''; 
     }); 
     _(selection).each(function(data){ 
     if(remove) { 
      data.parents = _(data.parents).without(action); 
     } else { 
      data.parents.push(action); 
     } 
     }); 

     //rebuild each text node 
     _(textData).each(function(data){ 
     //no need to add empty text nodes 
     if(data.text === '') { 
      return; 
     } 
     //remove duplicates of the same parent tag and remove the selection wrapper 
     var parents = _(data.parents).chain().uniq().without(selectionWrapper).value();    
     var target = container; 
     _(parents).each(function(parent){ 
      var node = document.createElement(parent); 
      target.appendChild(node); 
      target = node; 
     }); 
     var text = document.createTextNode(data.text); 
     target.appendChild(text); 
     }); 
    } 

    $('button').on('click', function(){ 
     var action = $(this).attr('data-action');    
     var selection = window.getSelection(); 

     for(var i = 0; i < selection.rangeCount; i++){ 
     var range = selection.getRangeAt(i);  
     var node = document.createElement(selectionWrapper);      
     node.appendChild(range.extractContents());   
     range.insertNode(node); 
     handleSelection($('p')[ 0 ], action); 
     } 

     return false;   
    }); 
    });  
</script> 
+0

이것은 여전히 ​​최소한의 예입니다. 실제 사용을 위해 할 수있는 많은 추가 기능이 있습니다. - 궁금한 점이 있으면 그들 중 일부를 열거하십시오. – nrkn

관련 문제