<pre> 内部内容可编辑,将 <br> 替换为 \r\n

mad*_*kay 1 jquery contenteditable rangy

我有一个内容可编辑的 div。在此我插入一个<pre>some code</pre>标签。此标签旨在允许用户输入格式化代码,类似于 SO。

我遇到的问题是 FF 正在插入<br>标签来代替 \r\n,这在正常的 Html 中是正确的,但在 pre 我实际上想要 \r\n。

我尝试将委托附加到父 contenteditable。但这不会为嵌套的 dom 元素触发。所以

$('#contenteditablediv').delegate('pre', 'keyup', function() { ... });
Run Code Online (Sandbox Code Playgroud)

不火。我还尝试处理父 div 上的正常 keyup,并用 \r\n 替换 pre 标签中的所有 brs。但这会弄乱插入符号并且很笨重。

有没有首选的方法来做到这一点?

我可能不得不求助于剥离它们的服务器端,但我宁愿不这样做。

非常感谢

mad*_*kay 5

我实际上已经找到了解决方案。它并不完美,我正在考虑按照Mrchief 的建议尝试集成codemirror。唯一的问题是我当前的解决方案允许我编辑将保存在后端并稍后显示的标记。这确实是所见即所得。我应该提到我的编辑器是一个更大的 contenteditable 文章的一部分,我想在其中添加一些代码片段。

使用像 codemirror 这样的编辑器会很棒,但是我必须在保存之前将其删除,并且我的代码块必须显示为 textarea(不像 pre 那样对 RSS 友好)。

无论如何,对这里感兴趣的任何人都是我的解决方案/黑客。


您可以委托<pre>contenteditables 中嵌套标签等的事件,只要它们包含在带有contenteditable="false". 所以而不是插入:

<pre>some code</pre

我插入:

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

然后我像这样添加了一个代表。

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');
    });
Run Code Online (Sandbox Code Playgroud)

此事件触发。我添加了一个点击/模糊删除来切换内部 pre 标签上的 contenteditable ,所以这之后不会被保存下来,但这可以在服务器端完成。这允许我在 tab 键上插入 \t 字符,并在 br 的位置插入 \r\n。