开发者

<pre> inside content editable, replace <br> with \r\n

开发者 https://www.devze.com 2023-03-22 22:36 出处:网络
I have a content editable div. Within this I am inserting a <pre>some code</pre> tag. This tag is designed to allow the user to enter formatted code, similar to SO.

I have a content editable div. Within this I am inserting a <pre>some code</pre> tag. This tag is designed to allow the user to enter formatted code, similar to SO.

The problem I am having is that FF is inserting <br> tags in place of \r\n which in normal Html would be correct but in a pre I actually want the \r\n.

I have tried attaching a delegate to the parent contenteditable. But this does not fire for nested dom elements. So

$('#contenteditablediv').delegate('pre', 'keyup', function() { ... });

Does not fire. I've also tried handling the normal keyup on the parent div and replacing all brs in pre tags with \r\n. But this messes up the caret and is clunky.

Is there a preferred way of doing this?

I may have to resort to stripping them server side but I'd rather 开发者_如何转开发not.

Many thanks


I have actually found a solution. It isn't perfect and I am considering having a go at integrating codemirror as suggested by Mrchief. The only problem is that my current solution alows me to edit the markup that will be saved in the back-end and displayed later. It is truly WYSIWYG. I should have mentioned that my editor is part of a greater contenteditable article, in which I want to add some code fragments.

Using an editor like codemirror would be awesome but Id have to strip it out before saving and my code blocks would have to be displayed as textarea (not as RSS friendly as pre).

Anyways for anyone that's interested here is my solution/hack.


You can delegate events from nested <pre> tags etc in contenteditables as long as they are wrapped in an element with contenteditable="false". So instead of inserting:

<pre>some code</pre

I inserted:

<code contenteditable="false"><pre>code snippet here</pre></code>

I then added a delegate like so.

var getFirstRange = function() {
    var sel = rangy.getSelection();
    return sel.rangeCount ? sel.getRangeAt(0) : null;
}

contenteditablediv
    .delegate('pre', 'keydown', function(event) { 
        switch(event.keyCode) {
            case 13:
                var range = getFirstRange(), 
                    added = false,
                    newline = document.createTextNode('\r\n');

                if (range) {
                    range.insertNode(newline);              
                    range.setEndAfter(newline);
                    range.setStartAfter(newline);
                    var sel = rangy.getSelection();
                    sel.setSingleRange(range)
                    added = true;
                } 

                if (added) {
                    event.preventDefault();
                }
                break;
            case 9:
                // insert a tab
                var range = getFirstRange(),
                    tab = document.createTextNode('\t');
                if (range) {
                    range.insertNode(tab);
                    var sel = rangy.getSelection();
                    range.setEndAfter(tab);
                    range.setStartAfter(tab);
                    sel.setSingleRange(range)
                } 
                return false;   
        }
    }).delegate('pre', 'click', function() { 
        $(this).attr('contenteditable', true);
    }).delegate('pre', 'blur', function() {
        $(this).removeAttr('contenteditable');
    });

This event fires. I have added a click/blur delete to toggle contenteditable on the inner pre tag so this doesn't get saved down after but that could be done server-side. This allows me to insert \t characters on tab key and \r\n in place of br.


Simple answer: Do it server side. Anything inside contentEditable div is just text. Hence your delegate will never fire.

I would also suggest looking at codemirror plugin which may be handling all this already.

0

精彩评论

暂无评论...
验证码 换一张
取 消