如何强制
Firefox ContentEditable 中的换行符

发布于 2024-12-11 20:32:52 字数 346 浏览 0 评论 0原文

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

它有一个设置,当您在编辑器中按 Enter 时,IE 会创建
换行符。

这很好用,但不幸的是,Firefox(我已经用 5 和 7 进行了测试)仍然会生成

元素,并且仅在以下情况下生成
:您使用Shift + Enter

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

I have a JavaScript WYSIWYG editor (not unlike CKEditor) running on a site.

It has a setting that makes IE create <br> line breaks when you press Enter in the editor.

That works great, but unfortunately, Firefox (I've tested with 5 and 7) will still generate <p> elements, and generate <br> s only if you use Shift + Enter.

Is there a way to make Firefox always generate <br> elements in a contentEditable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

想念有你 2024-12-18 20:32:52

从标准来看,这个动作似乎是应该被处理的。当回车键上没有设置修饰符时,块会被破坏,并且当按下 Shift 时,会使用
。 [来源]。

也就是说,这并不能解决您的问题,所以让我们解决这个问题。此行应该执行

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

Set 操作,以便当您按回车键时,它只会放入
标记。这是仅受 FF 支持,因此它不会影响 IE 上的任何内容。不过不知道其他浏览器怎么样。

注意:如果用户再次按 Enter 且未输入任何内容,则无论如何都会创建一个新的段落标记。为了防止这种情况,您可以使用 keypress 事件捕获 Enter 并停止它,或者您可以在之前插入  继续活动(我的建议)。

对于此注释来说,最困难的部分是检查按键上元素的状态。懒惰的解决方案(也是我推荐的解决方案,除非不这样做很重要)是在每个 Enter 键之前插入它。如果您想以其他方式执行此操作,我将检查元素的 .innerHTML 并查看最后几个字符(不修剪内容)是否为
< /code> (所以可能是 /\
$/
上的正则表达式匹配)。

From looking at the standards, it looks like this action is the way it is supposed to be handled. Blocks are broken when no modifier is set on an enter key, and <br>'s are used when shift is pressed. [Source].

That said, that does not solve your problem, so let's work on that. This line should do

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

Set's it so that when you just hit return, it only puts in a <br> tag. This is only supported by FF, so it shouldn't affect anything on IE. Don't know about other browsers though.

Note: If the user hits Enter a second time, without typing anything, it creates a new paragraph tag no matter what. To prevent this, you can catch the Enter using the keypress event and stop it, or you could insert in a   before you continue with the event (what I'd recommend).

The tough part for you with this note is checking on the state of the element on keypress. The lazy solution (and the one I would recommend unless it's important to not do this) is to just insert it before every Enter key. If you want to do it the other way, I would check the .innerHTML for the element and see if the last few characters (without trimming the content) are <br/> (so maybe a regex match on /\<br\s?\/?\>$/).

巴黎盛开的樱花 2024-12-18 20:32:52

考虑一下:

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 时,不会将 BR 或 P 元素添加到 DIV 中。 DIV 内始终只有一个 TextNode,所有换行符均由 '\n' 字符表示。

Consider this:

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 );
    }
});

Live demo: http://jsfiddle.net/FhEf6/3/

I use '\n' characters instead of BR elements (the DIV has white-space:pre set). As a result, no BR, or P elements are added to the DIV when ENTER is pressed. There is only one TextNode inside the DIV at all times and all new-lines are represented by '\n' characters.

染火枫林 2024-12-18 20:32:52

// 不完全是你所问的,但当你想强制时这个函数可能会很有趣
// 其他浏览器 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

// not exactly what you asked but this function may be interesting when you want to force
// the other browsers opera,chrome,internet explorer to insert a regular BR on enter.
// could be better written but works so far

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

玩套路吗 2024-12-18 20:32:52

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

JS:

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> </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);
            });
        });
    }
});

CSS:

.nbsp-break + br + span {
    font-size: 0;
}

My solution works perfectly in Firefox, although it came around quite unexpectedly! I've also tested it in Edge and Chrome. It's based on the answer of @Ktash, replacing the nbsp with three disappearing nodes: an empty span (with a class), a <br> in the middle and a span containing  .

JS:

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> </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);
            });
        });
    }
});

CSS:

.nbsp-break + br + span {
    font-size: 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文