views:

1194

answers:

4

On Internet Explorer, a contentEditable DIV creates a new paragraph (<p></p>) each time you press Enter whereas Firefox creates a <br/> tag.

As discussed here, it is possible to use JavaScript to intercept the Enter keyPress and use range.pasteHTML to create a <br/> instead. But doing this breaks the Undo menu; once you hit Enter, you can no longer Undo past that point.

How can I force the contentEditable element to create single line breaks on Enter without breaking Undo?

+1  A: 

It may be impossible to get this right. However, it is possible to make the <p> tags look like single line breaks, by removing the built-in margin around paragraph tags, using CSS:

p { margin: 0; }

There is a drawback to this approach: if the user needs to copy/paste text in the contentEditable element, the text may appear to be single-spaced inside the element but double-spaced outside the element.

Worse, in at least some cases, IE will automatically detect double-line breaks during paste, replacing them with <p> tags; this will mess up the formatting of the pasted text.

Dan Fabulich
Meta aside: I'm normally loathe to post an answer to my own bounty, but it's been four days and no response; I'd hate to see those points disappear into the ether...
Dan Fabulich
+4  A: 

Not an exact solution, but another workaround. If you use the markup:

<div contenteditable="true">
<div>
content
</div>
<div>

Then pressing enter will create new div tags instead of p tags.

Joel Potter
Interesting! I'd read about that elsewhere, but for some reason I couldn't get the technique to work before. Tried it just now in a simple HTML page and it worked great in IE6 IE8 FF36 GC4. However, if the user manages to delete the inner DIV, it reverts back to `<p>` breaks.
Dan Fabulich
True, and I don't know how you can avoid that. Originally `contenteditable` was a Microsoft proprietary attribute that they implemented in whatever way they wanted, some of which makes sense but most of which has far too many bugs. The FF implementation is less buggy but does some non-standard things (enter really should create new paragraphs). Here's hoping that IE9 reconsiders this feature. To achieve any semblance of consistency between them you really have to consider javascript.
Joel Potter
+2  A: 

Presumably you are going to post the editable content back to a server. Therefore, you shouldn't really care whether you have paragraph or break tags in place while the user is editing, because you can parse the HTML before submission (or on the server, if you like) and replace instances of paragraphs with breaks. This keeps the UNDO queue in operation for the user, but lets you have your HTML as clean as you want it.

I'll further presume that you're going to know exactly which DIV elements are going to be contentEditable. Before the form is submitted, you can run each contentEditable div through a function like this:

function cleanContentEditableDiv(div) {
  var htmlString = div.innerHTML;
  htmlString     = htmlString.replace(/<\/p>/gim,"<br/>");
  htmlString     = htmlString.replace(/<p>/gim,"");
  return htmlString;
}

And you call this in a loop (which iterates through all contentEditable DIVs, using an array I will call ceDivs), like this:

ceDivs[i].contentEditable = false; // to make sure IE doesn't try to coerce the contents again

and then:

ceDivs[i].innerHTML = cleanContentEditableDiv(ceDivs[i]);

An improvement on this (especially if you don't want to do this right at submit time), might be to clean the contents of each such div any other time you like (onblur, whatever) and assign the contents of each ceDiv to its own invisible form element for later submission. Used in combination with your own CSS suggestion above, this might work for you. It doesn't preserve your literal requirements to the letter (i.e., it doesn't get Javascript to make IE behave differently than it has been coded under the covers to behave) but for all practical purposes the effect is the same. The users get what they want and you get what you want.

While you're at it you may also want to clean space strings in IE as well. If the user types multiple spaces (as some still do after periods), what is inserted by IE is not [space][space] but [space]&nbsp;, an initial space character (String.fromCharCode(32)) plus as many &nbsp; entities as there are left in the space run.

Robusto
I'm working on a client-side editor. Copying and pasting into and out of the editable element is very important, so it *does* matter whether line breaks are preserved.
Dan Fabulich
Robusto makes a very good point on cleaning up the html. Contenteditable produces some of the worst html your eyes ever seen. Sanitizing the html on the server side in any case is a good idea. That is as far as using html for client side markup is ever a good idea. We gave up on supporting clients wanting to copy paste from word in the long run noone gets any happier :$
Martijn Laarman
I agree that cleaning the HTML is a good idea, but once I clean the HTML, you can no longer use the Undo menu to undo the changes! That's the whole point of my question.
Dan Fabulich
Dan, two points: 1. In the scheme I suggested, your line breaks *are* preserved. They're just rejiggered after the fact.2. If you leave the cleaning until the form is submitted, you leave the user with the entire UNDO queue. There should be no expectation of having that saved *after* form submission.
Robusto
Robusto, I'm trying to generate single-spaced lines at the very moment the user hits the Enter key, without breaking Undo every time the user hits Enter. Cleaning server-side is good practice, but irrelevant to my problem.
Dan Fabulich
+3  A: 

Hold down shift when you press enter for breaks, don't hold it down for full paragraphs. This behaviour is the same by default in Firefox, given a contenteditable area containing a paragraph: i.e.

<div contenteditable="true">
    <p>If you are typing here</p>
<div>
Sohnee
That's a good point, but I can't expect my users to remember to do that consistently.
Dan Fabulich
People may know the convention if they use Word Perfect, Open Office or even Microsoft Word as these all behave the same. A note to this effect to accompany the editor should suffice. Promote the convention rather than try to break it.
Sohnee
I totally agree :) It's a trick that my users seldom forget once they learn it. It's in the same space as Ctrl-Click to select individual lines in a spreadsheet.
Brendon Muir