可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have observed an undesirable behaviour in Chrome that occurs when one joins two <p>
's by deleting the separation between them. Although the <p>
tags are joined properly, Chrome wraps the right-most <p>
tag's content with a <span>
.
Edit: this happens for all block elements, not just p
tags.
Example:
For example, when the separating </p><p>
are deleted from the following block:
<div contenteditable="true"><p>p one.</p><p>p two.</p></div>
It becomes:
<div contenteditable="true"><p>p one.<span style="font-size: 16px; line-height: 1.44;">p two.</span></p>
Example in a fiddle: Chrome wrapping contents of joined <p>
with a <span>
.
Question:
Is there an easy way to prevent chrome from doing this? It results in horrible markup that I'd like very much to be rid of.
回答1:
There is a way but you need to pro-actively set a few styles. The idea is to tell Chrome that the styles are already taken care of, so it doesn't need to add SPAN to meet the styles requirement.
basically, you need to add the chrome added styles to a span class under your contenteditable div ( see example below).
Edited fiddle
For you example:
- I added an "edit" class to the contenteditable DIV
- I added an
.edit p, span
class in the style
This becomes:
.edit {
border: 1px solid gray;
padding: 10px;
}
.edit p, span {
line-height: 1.44; font-size: 16px;
}
And the DIV:
<div contenteditable="true" class="edit">...</div>
Note that you normally don't need the font-size: 16px;
. I needed to add this one because fiddle defines some font size in contenteditable. On a standalone page I didn't need it.
You need to apply this Chrome 'patch' to any elements where it happens (so if you need UL, OL... then add what is needed following my example logic above)
回答2:
I know it is not really an answer to solve it, but a hint how it could be fixed (but it is to long to be a comment to Petah question how i would solve it)
in general you would check when such bugs could happen. for the case of the span
creation you would listen to all keydown
and keypress
events and check if the key is the backspace/delete key or for every key that inserts chars if it is a real selection.
if this is the case then you need to check the current selection (either the position of the insert mark, or the real selection) then you know which is the next following text-element or node. then you need to check the in the next following keypress
and keyup
if there is a span
created directly after your insert mark. depending on the browser bug you need some further checking. if there is one create unwrap its content again. additionale Mutation
events and helper attributes could be used.
But i need to say that i gave up in doing this myself and switched over to ckeditor 4. most of the it's features i don't need and it is a really big library. but cause of the huge number of such bugs i did not see another solution for me.
EDIT
Here an update of the js fiddle that shows the idea with a Mutable event:
http://jsfiddle.net/THPmr/6/
But that is not bullet proofed, it is just to show how it could be achived ( only tested in chrome 27.0.1422.0, and probably would not work if more then one text element is contained in the second p
)
回答3:
The CSS is influencing how the markup is made inside contenteditable:
div, pre {
border: 1px solid gray;
padding: 10px;
line-height: 1.44;
}
Delete the line-height line and the problem doesn't occur any more.
There are in general several bugs with contenteditable related to default styling : How to avoid WebKit contentEditable copy-paste resulting in unwanted CSS?
EDIT JsFiddle IS indirectly influencing this (tinkerbin behaves differently) because of its' CSS (normalize.css). Try this:
- Run your fiddle
- Inspect a
<p>
- Disable all
font-size
declarations in the CSS stack - including your line-height
- do the backspace
- there is no inline span
Solution 1 : Use classes and id's.
Don't declare font-size for p
or div
but for p.main-content
, or more simply, .main-content
.
If the font-size of your elements inside contenteditable is coming from the browsers' internal default CSS then Chrome won't add extra markup/inline styling.
Solution 2 : Use a Sanitizer.
I'd personally go with #1 as it's never a good practice to specify font-sizes and typo in so generic tags.
回答4:
The best way I found so far is to listen to DOMNodeInserted and check the tagName. If it is a span, you can remove the tag and but leave the contents. This also keeps the cursor at the correct place.
function unwrap(el, target) {
if ( !target ) {
target = el.parentNode;
}
while (el.firstChild) {
target.appendChild(el.firstChild);
}
el.parentNode.removeChild(el);
}
var AutoFix = true;
document.getElementById('editable')
.addEventListener('DOMNodeInserted', function(ev) {
if ( !AutoFix ) {
return;
}
if ( ev.target.tagName=='SPAN' ) {
unwrap(ev.target);
}
});
I've added a boolean 'AutoFix' so you can disable the automatic dom changes when you do need to insert a span, since this event fires on any dom change. E.g. if you have a toolbar that allows the user to insert something like <span class="highlight">...</span>.
The code has no side effects in IE or FireFox as far as I can see.
回答5:
Here is my take on removing the extra spans
document.querySelector('[contenteditable=true]')
.addEventListener('DOMNodeInserted', function(event) {
if (event.target.tagName == 'SPAN') {
event.target.outerHTML = event.target.innerHTML;
}
});
回答6:
This irritated me as well, but I found a solution that works well enough for now.
$('#container span').filter(function() {
$(this).removeAttr("style");
return $(this).html().trim().length == 0;
}).remove();
I simply remove the style tag from the span element and remove it altogether if it's empty. You could probably filter based on the attribute style, but as I'm already doing a loop to check to remove empty spans, I thought it was best to do both at the same time.
It does create a flicker for a microsecond when chrome first tries to insert the style inherited for the span, but you only see that once immediately after deletion.
It isn't perfect, but it's quick and concise.
回答7:
Found this link from a comment posted on someone's blog:
(Fixed bug where the latest WebKit versions would produce span element…)
https://github.com/tinymce/tinymce/commit/8e6422aefa9b6cc526a218559eaf036f1d2868cf
回答8:
Please see the answers here: https://stackoverflow.com/a/24494280/2615633
To fix the problem you may just use this plugin: jquery.chromeinsertfix