2014-07-19 3 views
7

Sto tentando di sostituire tutte le istanze di /any thing in here/ con <b>/any thing in here/</b> al volo, poiché le modifiche vengono apportate in un div contenteditabile.Modificare il testo in un div contentedabile senza resettare la posizione del cursore (01)

La mia attuale implementazione funziona, ma ad ogni pressione di tasto il cursore viene spostato all'inizio di div rendendo l'implementazione inutilizzabile. C'è un modo per mantenere la posizione del cursore mentre si sostituiscono i contenuti del div?

$('.writer').on('keyup', function(e) { 
    $(this).html($(this).html().replace(/\/(.*)\//g, '<b>\/$1\/<\/b>')); 
}); 
+0

C'è un motivo è necessario utilizzare un '' div' con contenteditable' invece di una 'textarea' o qualcosa di simile? – royhowie

+0

@Luxelin: Mi piacerebbe rendere l'html all'interno del div e, per quanto ne so, non è possibile eseguire il rendering di html all'interno di una textarea. – slyv

+0

Anche se dovessi usare una textarea, sono sicuro che il cursore si muoverà ancora. –

risposta

4

provarlo demo

$('#writer').on('keyup', function(e) { 
     var range = window.getSelection().getRangeAt(0); 
     var end_node = range.endContainer; 
     var end = range.endOffset; 
     if(end_node != this){ 
      var text_nodes = get_text_nodes_in(this); 
      for (var i = 0; i < text_nodes.length; ++i) { 
       if(text_nodes[i] == end_node){ 
        break; 
       } 
       end += text_nodes[i].length; 
      } 
     } 
     var html = $(this).html(); 
     if(/\&nbsp;$/.test(html) && $(this).text().length == end){ 
      end = end - 1; 
      set_range(end,end,this); 
      return; 
     } 
     var filter = html.replace(/(<b>)?\/([^<\/]*)(<\/b>)?/g, '\/$2'); 
     console.log(filter); 
     filter = filter.replace(/(<b>)?([^<\/]*)\/(<\/b>)?/g, '$2\/'); 
     console.log(filter); 
     filter = filter.replace(/(<b>)?\/([^<\/]*)\/(<\/b>)?/g, '<b>\/$2\/<\/b>'); 
     console.log(filter); 
     if(!/\&nbsp;$/.test($(this).html())){ 
      filter += '&nbsp;'; 
     } 
     $(this).html(filter); 
     set_range(end,end,this); 

    }); 

    $('#writer').on('mouseup', function(e) { 
     if(!/\&nbsp;$/.test($(this).html())){ 
      return; 
     } 
     var range = window.getSelection().getRangeAt(0); 
     var end = range.endOffset; 
     var end_node = range.endContainer; 
     if(end_node != this){ 
      var text_nodes = get_text_nodes_in(this); 
      for (var i = 0; i < text_nodes.length; ++i) { 
       if(text_nodes[i] == end_node){ 
        break; 
       } 
       end += text_nodes[i].length; 
      } 
     } 
     if($(this).text().length == end){ 
      end = end - 1; 
      set_range(end,end,this); 
     } 
    }); 

    function get_text_nodes_in(node) { 
     var text_nodes = []; 
     if (node.nodeType === 3) { 
      text_nodes.push(node); 
     } else { 
      var children = node.childNodes; 
      for (var i = 0, len = children.length; i < len; ++i) { 
       var text_node 
       text_nodes.push.apply(text_nodes, get_text_nodes_in(children[i])); 
      } 
     } 
     return text_nodes; 
    } 

    function set_range(start, end, element) { 
     var range = document.createRange(); 
     range.selectNodeContents(element); 
     var text_nodes = get_text_nodes_in(element); 
     var foundStart = false; 
     var char_count = 0, end_char_count; 

     for (var i = 0, text_node; text_node = text_nodes[i++];) { 
      end_char_count = char_count + text_node.length; 
      if (!foundStart && start >= char_count && (start < end_char_count || (start === end_char_count && i < text_nodes.length))) { 
       range.setStart(text_node, start - char_count); 
       foundStart = true; 
      } 
      if (foundStart && end <= end_char_count) { 
       range.setEnd(text_node, end - char_count); 
       break; 
      } 
      char_count = end_char_count; 
     } 

     var selection = window.getSelection(); 
     selection.removeAllRanges(); 
     selection.addRange(range); 
    }