admin管理员组

文章数量:1405621

I am trying to replace any instances of /any thing in here/ with <b>/any thing in here/</b> on the fly, as changes are made in a contenteditable div.

My current implementation works, but at every keypress the caret is moved to the beginning of div making the implementation unusable. Is there some way to keep the caret position while replacing the div's contents?

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

I am trying to replace any instances of /any thing in here/ with <b>/any thing in here/</b> on the fly, as changes are made in a contenteditable div.

My current implementation works, but at every keypress the caret is moved to the beginning of div making the implementation unusable. Is there some way to keep the caret position while replacing the div's contents?

$('.writer').on('keyup', function(e) {
     $(this).html($(this).html().replace(/\/(.*)\//g, '<b>\/$1\/<\/b>'));
});
Share Improve this question edited Oct 10, 2018 at 6:33 Cœur 38.8k25 gold badges205 silver badges277 bronze badges asked Jul 19, 2014 at 21:42 slyvslyv 8381 gold badge10 silver badges18 bronze badges 5
  • Is there a reason you have to use a div with contenteditable instead of a textarea or something similar? – royhowie Commented Jul 19, 2014 at 21:47
  • @Luxelin: I'd like to render html within the div, and as far as I am aware, html can't be rendered inside a textarea. – slyv Commented Jul 19, 2014 at 21:49
  • Even if you were to use a textarea I'm sure the caret would still move around. – Lee Taylor Commented Jul 19, 2014 at 21:53
  • 2 This question may be of use for you, regarding setting the caret position. – royhowie Commented Jul 19, 2014 at 21:54
  • I've answered a very similar question recently: stackoverflow./a/24687874/96100 – Tim Down Commented Jul 20, 2014 at 16:33
Add a ment  | 

1 Answer 1

Reset to default 6

$('#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);
        }
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="writer" contenteditable style="width:300px;height:100px;border:1px solid #ccc;">/input some words here!/</div>

本文标签: javascriptModify text in a contenteditable div without resetting the caret (cursor) positionStack Overflow