简体   繁体   English

防止contentedable模式创建<span>标记</span>

[英]prevent contenteditable mode from creating <span> tags

When I use the browser contenteditable=true on a div in order to let the user update the text in it, I run into this problem (using Chrome): 当我在div上使用浏览器contenteditable = true以便让用户更新其中的文本时,我遇到了这个问题(使用Chrome):

When using the delete backspace key to remove a line break (jump back up a line) the browser inserts a tag with inline style set, around that text. 当使用delete backspace键删除换行符(跳回一行)时,浏览器会在该文本周围插入一个带内联样式集的标记。

This is really frustrating because not only does it do that, it also adds an inline style to that span tag, for example if my font color is currently black, it adds a style="color:black" to that span tag. 这实在令人沮丧,因为它不仅会这样做,还会为该span标记添加内联样式,例如,如果我的字体颜色当前为黑色,则会为该span标记添加style =“color:black”。

The result is that I can no longer edit the color of that text with my toolbar, since it has been set hard to the span tag by the inline style. 结果是我无法再用我的工具栏编辑该文本的颜色,因为它已通过内联样式很难设置为span标记。 Same thing happens with font size if I do this same thing backing up a line with the delete key. 如果我使用删除键备份一行,同样的事情发生在字体大小上。

Anyone here that could teach me a thing or two about contenteditable, or suggest a way to remove the span:s, if it isnät possible to prevent this browser behaviour.. 这里的任何人可以教我一两件关于满足的事情,或建议一种方法来消除跨度:s,如果它不可能阻止这种浏览器行为..

** To reproduce this problem ** - Create a div in the browser, set inline style on it with for instance font-size:36px - Edit the div's text with content editable in the browser, write a couple of lines with manual linebreaks. **要重现此问题** - 在浏览器中创建一个div,在其上设置内联样式,例如font-size:36px - 使用浏览器中可编辑的内容编辑div的文本,写一些带有手动换行符的行。 - Now put cursor IN FRONT OF / BEFORE a paragraph of text and hit backspace. - 现在将光标放在FRONT OF / FRFORE的一段文本中并点击退格键。 A span tag should now be generated around the text that is IN FRONT OF your cursor, and the style of it changed. 现在应该在光标前面的文本周围生成一个span标记,并改变它的样式。

UPDATE * * So I have tried a few different solutions with limited success. 更新* *所以我尝试了几种不同的解决方案,但收效甚微。 First I tried to remove all tags, but then I lost all linebreaks as well (maybe a better regexp could solve this, I am no expert on regExp writing). 首先我尝试删除所有标签,但之后我也丢失了所有的换行符(也许更好的正则表达式可以解决这个问题,我不是regExp写的专家)。

All functions below were first called upon keyup event, but then I attached them to unselecting the textbox. 下面的所有函数首先调用keyup事件,但后来我将它们连接到取消选择文本框。 How to fire below functions is irrelevant to the question. 如何解雇以下功能与问题无关。

        //option to remove all tags
        var withTags = $(textObject).html();
        var withoutTags = withTags.replace(/<(?:.|\n)*?>/gm, '');       
        $(textObject).html(withoutTags);

My second attempt was more successful, by removing style tags of objects underneath the textbox (the divs ans spans inside the textbox that chrome added), here was my first code 我的第二次尝试更成功,删除文本框下面的对象的样式标记(div添加了文本框内的divs),这是我的第一个代码

        //option to remove style of elements
        $(textObject).children().each(function() {
            $(this).removeAttr('style');
            console.log('removing style from first level element: '+this);

        });

Then I realized that every time I edit a textbox, chrome might add a new nested level of div/span tags that the above code won't reach, so I did this: 然后我意识到每次编辑文本框时,chrome都可能会添加一个新的嵌套级别的div / span标签,上面的代码将无法达到,所以我这样做了:

        //option to remove style of elements
        $(textObject).children().each(function() {
            $(this).removeAttr('style');
            console.log('removing style from first level element: '+this);

            //And of course it would be all too easy if chrome added only one level of elements...
            $(this).children().each(function() {
                $(this).removeAttr('style');
                console.log('removing style from second level element: '+this);
            });

        });

But that isn't enough since the amount of nesting could theoretically be unlimited. 但这还不够,因为嵌套的数量理论上可以是无限的。 Still working on a better solution. 仍在努力寻找更好的解决方案。 Any input is appreciated =) 感谢任何输入=)

The problem is, actually, that not only it inserts span's and p's, but if you happen to copy a table it will insert the whole table with tbody and rows there. 实际上,问题是它不仅插入了span和p,而且如果你碰巧复制了一个 ,它将那里插入整个表格,其中包含tbody和rows So, the only option to handle this that I've found working for me is this: 所以,我发现为我工作的唯一选择就是:

$(document).on("DOMNodeInserted", $.proxy(function (e) {
        if (e.target.parentNode.getAttribute("contenteditable") === "true") {
            with (e.target.parentNode) {
                replaceChild(e.target.firstChild, e.target);
                normalize();
            }
        }
}, this));

Yes, it somewhat affects the overal page performance, but it blocks inserting tables and stuff into the contenteditables. 是的,它有点影响了整个页面的性能,但它会阻止将表和内容插入到满足的内容中。

UPDATE: 更新:
The script above handles only basic cases, when the content you wish for is wrapped in one level of span/p tags. 当您希望的内容包含在一个span / p标记级别时,上面的脚本只处理基本情况。 However, if you copy from, say, Word, you may end up copying even the whole tables. 但是,如果从Word复制,则最终可能会复制整个表格。 So, here is the code that handles everything i've thrown at it so far: 所以,这是代码,它处理我迄今为止所抛出的所有内容:

$(document).on("DOMNodeInserted", $.proxy(function (e) {
    if (e.target.parentNode.getAttribute("contenteditable") === "true") {
        var newTextNode = document.createTextNode("");
        function antiChrome(node) {
            if (node.nodeType == 3) {
                newTextNode.nodeValue += node.nodeValue.replace(/(\r\n|\n|\r)/gm, "")
            }
            else if (node.nodeType == 1 && node.childNodes) {
                    for (var i = 0; i < node.childNodes.length; ++i) {
                        antiChrome(node.childNodes[i]);
                    }
            }
        }
        antiChrome(e.target);

        e.target.parentNode.replaceChild(newTextNode, e.target);
    }
}, this));

Also, feel free to modify the regex in the middle any way you like to remove symbols that are particularly hazardous in your case. 此外,您可以随意修改中间的正则表达式,以删除在您的情况下特别危险的符号。

UPDATE 2 更新2
After thinking for a little while and googling, I've just wrapped the code above into simple jQuery plugin to ease the usage. 在思考了一段时间并使用谷歌搜索之后,我将上面的代码包装成简单的jQuery插件以简化使用。 Here is the GitHub link 这是GitHub链接

For now, I am using 现在,我正在使用

        $(textObject).find('*').removeAttr('style');

upon deselect of the editable region. 取消选择可编辑区域。

It could also be used upon keyup. 它也可以用在keyup上。

Here is how I solved this 这是我解决这个问题的方法

jquery remove <span> tags while preserving their contents (and replace <divs> and <p>:s with <br>) jquery删除<span>标签,同时保留其内容(并用<br>替换<divs>和<p>:s)

I preserve the text of all div, span and p tags, remove those tags, and substitute all div and p with a br. 我保留所有div,span和p标签的文本,删除那些标签,并用br替换所有div和p。 I do it on blur, optimal would be to do it on every keydown, but that is eating too much cpu since I have to loop through all these %#¤¤% & (you said it) nested elements. 我是在模糊的情况下做的,最好是在每次keydown上都这样做,但是因为我必须循环遍历所有这些%#¤¤% &(你说的)嵌套元素,因此吃了太多的cpu。

Add style display:inline-block; 添加样式显示:inline-block; to contenteditable, it will not generate div, p, span automatic in chrome 为了满足要求,它不会在chrome中自动生成div,p,span

Man, the timing on this question is crazy. 伙计,这个问题的时机是疯狂的。 What I'm doing with contenteditable is forcing all the content to be within paragraph tags, of the contenteditable div. 我正在做的与contenteditable一起强迫所有内容都在段落标签内,这是可信的div。

So the way I handle this bullshit spans that get created is by flattening every <p> on every keystroke. 所以我处理这个废话跨度的方式是通过在每次击键时弄平每个<p>

Since .text() selects ALL the text of an element, including its subelements, I can just set (in coffeescript) 由于.text()选择元素的所有文本,包括其子元素,我可以设置(在coffeescript中)

t = $(element).text()
$(element).children().remove()
$(element).text(t)

Which solves my problem. 这解决了我的问题。 As an aside, these browser implementers really botched contenteditable pretty bad. 顺便说一句,这些浏览器实现者确实非常糟糕。 There is a massive opportunity here to make this easy, because it really is the future of the web. 这里有一个很大的机会让这很容易,因为它确实是网络的未来。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM