如何在Firefox ContentEditable中强制换行

时间:2011-10-26 10:19:49

标签: html firefox wysiwyg

我在网站上运行了一个JavaScript WYSIWYG编辑器(与CKEditor不同)。

当你在编辑器中按 Enter 时,它有一个设置让IE创建<br>换行符。

效果很好,但遗憾的是,Firefox(我已经测试过5和7)仍然会生成<p>个元素,并且仅当您使用 Shift + Enter <时才会生成<br>个/ KBD>。

有没有办法让Firefox始终在contentEditable中生成<br>个元素?

4 个答案:

答案 0 :(得分:16)

通过查看标准,看起来这个动作就是它应该被处理的方式。在输入键上没有设置修饰符时,块被破坏,按下shift时使用<br>。 [Source]。

那就是说,这并没有解决你的问题,所以让我们继续努力吧。这行应该

document.execCommand('insertBrOnReturn', false, true);

设置它,以便当您点击返回时,它只会放入<br>标记。这是only supported by FF,所以它不应该影响IE上的任何内容。但是不知道其他浏览器。

注意:如果用户第二次点击 Enter 而没有输入任何内容,则无论如何都会创建一个新的段落标记。为了防止这种情况,您可以使用keypress事件捕获 Enter 并将其停止,或者您可以在继续事件之前插入&nbsp;(我会做什么)推荐)。

本说明的难点在于检查keypress上元素的状态。懒惰的解决方案(我建议除非重要的是不要这样做)是在每个 Enter 键之前插入它。如果你想以另一种方式做,我会检查.innerHTML元素,看看最后几个字符(没有修剪内容)是<br/>(所以可能是{{1}上的正则表达式匹配1}})。

答案 1 :(得分:9)

考虑一下:

HTML:

<div contentEditable id="input"></div>

CSS:

#input {
    border: 3px solid #07c;
    width: 300px;
    height: 200px;
    white-space: pre;
}

JavaScript的:

$( input ).keypress( function ( e ) {
    var sel, node, offset, text, textBefore, textAfter, range;

    sel = window.getSelection();

    // the node that contains the caret
    node = sel.anchorNode;

    // if ENTER was pressed while the caret was inside the input field
    if ( node.parentNode === input && e.keyCode === 13 ) {

        // prevent the browsers from inserting <div>, <p>, or <br> on their own
        e.preventDefault();

        // the caret position inside the node
        offset = sel.anchorOffset;        

        // insert a '\n' character at that position
        text = node.textContent;
        textBefore = text.slice( 0, offset );
        textAfter = text.slice( offset ) || ' ';
        node.textContent = textBefore + '\n' + textAfter;

        // position the caret after that new-line character
        range = document.createRange();
        range.setStart( node, offset + 1 );
        range.setEnd( node, offset + 1 );

        // update the selection
        sel.removeAllRanges();
        sel.addRange( range );
    }
});

现场演示: http://jsfiddle.net/FhEf6/3/

我使用'\n'个字符而不是BR元素(DIV设置了white-space:pre)。因此,按下ENTER时,不会向DIV添加BR或P元素。 DIV中始终只有一个TextNode,所有换行都由'\n'个字符表示。

答案 2 :(得分:0)

//不完全是你问的但是当你想强迫时这个功能可能很有趣 //其他浏览器opera,chrome,internet explorer在输入时插入常规BR。 //可以写得更好但到目前为止工作

enterBR = function(e)
{   
    var iframeElement=parent.window.$("wysiwyg"+n);
    e = e || iframeElement.contentWindow.event;                 // eventhandler inside iframe (!)
    var keyCode= e.keyCode? e.keyCode: e.which;                 // req. for IE below v8

if (keyCode==13)                                // if enter key gets pressed
{ 
     if(IE)      // internet explorer
     { e.preventDefault?e.preventDefault():e.returnValue=false; // block default handling ( i tell yo!)
       iframeElement.contentDocument.selection.createRange().pasteHTML("<br/>");  // insert a br tag
     }

     if(OP||CR)  // opera and chrome
     { 
      iframeElement.contentWindow.document.execCommand('formatBlock',false,'p');
     } // creates a paragraph around a br tag <p><br/></p> replace with regExp

    //here the regExp to replace the unneeded paragraph tags and a detection if you have whatever xhtml compatible <br/>'s or not.
    HTML=iframeElement.contentWindow.document.body.innerHTML;
    HTML=HTML.replace(/<p><br([\/]?)><\/p>/gi,'<br/>');
    HTML=HTML.replace(/<br(.*?|\s*[^\/]+[^>]?)([\/]?)>/mgi,"<br$1/>\n"); 

}
  return false;
}

// finaly add an eventlistener. remember this is used inside an iframe so dont forget to advise the script to work from one dom layer above (parent.window)
// but i think it can be easily rewritten for contenteditable div or something...
addEventListener(parent.window.$("mywysiwygeditor").contentDocument,'keypress',enterBR);

// hf

答案 3 :(得分:0)

我的解决方案在Firefox中完美运行,尽管出乎意料地出现了!我也在Edge和Chrome中测试过它。它基于@Ktash的答案,用三个消失的节点替换nbsp:空的跨度(带有类),中间的console reporter和包含<br>的跨度。

JS:

&nbsp;

CSS:

var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;

document.execCommand('insertBrOnReturn', false, true);

var elements = document.getElementsByClassName('editable');
Array.from(elements).forEach( (el) => {
    el.addEventListener('keydown',function(e) {
        if (e.which == 13) {
            if (isFirefox) {
                document.execCommand('insertHTML', false, '<span class="nbsp-break"></span><br><span>&nbsp;</span>');
                e.preventDefault();
            } else if (!isChrome) {
                document.execCommand('insertText', true, '\r\n');
                document.execCommand('insertHTML', false, "<br>");
                e.preventDefault();
            }
        }
    });

    if (isFirefox) {
        el.addEventListener('input',function(e) {
            var elements = document.getElementsByClassName('nbsp-break');
            Array.from(elements).forEach( (el) => {
                el.parentNode.removeChild(el.nextSibling.nextSibling);
                el.parentNode.removeChild(el);
            });
        });
    }
});