4

I am using a contentedittable field as user input so that I can exploit text formatting. Unfortunately I have found that when a user pastes into the field a massive amound of unnessessary html comes with it. I only want the plain text from the clipboard.

Why is this happening?!

A Truncated Example:

<div><br></div><div><span class="Apple-style-span" style="font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 13px; line-height: 12px; color: rgb(0, 0, 0); "><table style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; border-collapse: collapse; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; background-position: initial initial; background-repeat: initial initial; "><tbody style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; background-position: initial initial; background-repeat: initial initial; "><tr style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; background-position: initial initial; background-repeat: initial initial; "><td class="votecell" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: top; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; width: 60px; background-position: initial initial; background-repeat: initial initial; "><div class="vote" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 13px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; text-align: center; background-position: initial initial; background-repeat: initial initial; "><span class="vote-count-post" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 31px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; display: block; color: rgb(128, 129, 133); font-weight: bold; background-position: initial initial; background-repeat: initial initial; ">1</span><a class="vote-down-off" title="This question does not show any research effort; it is unclear or not useful (click again to undo)" style="margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 1px; vertical-align: baseline; background-image: url(http://sstatic.net/stackoverflow/img/sprites.png?v=3); background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: rgb(0, 119, 204); text-decoration: none; cursor: pointer; overflow-x: hidden; overflow-y: hidden; display: block; width: 41px; height: 25px; text-indent: -9999em; background-position: 0px -300px; background-repeat: no-repeat no-repeat; ">...
wilsonpage
  • 17,341
  • 23
  • 103
  • 147

2 Answers2

9

You can only get the plain text using a hack. Recent versions of both TinyMCE and CKEditor use this technique on their iframe-based editors:

  1. Detect a Ctrl-v / Shift-Insert event using a keypress event handler
  2. In that handler, save the current user selection, add a textarea element off-screen (say at left -1000px) to the document, turn contentEditable off and call focus() on the textarea, thus moving the caret and effectively redirecting the paste
  3. Set a very brief timer (say 1 millisecond) in the event handler to call another function that stores the textarea value, removes the textarea from the document, turns contentEditable back on, restores the user selection and pastes the text in.

Note that this will only work for keyboard paste events and not pastes from the context or edit menus. The paste event would be better but by the time it fires, it's too late to redirect the caret into the textarea in most browsers.

Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Hmmmm sound a little tricky and I do need to accommodate for users that right click paste. Perhaps a regex replace for invalid tags? – wilsonpage May 16 '11 at 21:06
  • @pagewil: I'd avoid using regular expressions to parse HTML if I were you. Another option is to pop up a dialog containing a textarea when for teh user to paste into when the `paste` event fires. – Tim Down May 16 '11 at 22:51
  • why is regex not recommended? – wilsonpage May 17 '11 at 07:21
  • 2
    @pagewil: While it's possible to deal with a strictly limited set of HTML string with regex, it's not in general possible to parse HTML with JavaScript regular expressions, and with content pasted in from outside sources, the HTML could be anything. Here's a couple of links on the subject: http://stackoverflow.com/questions/590747/using-regular-expressions-to-parse-html-why-not and the classic http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 – Tim Down May 17 '11 at 08:48
2

You're getting all that extra nonsense because a contenteditable element supports the text/html MIME type. When you paste something from the clipboard, there is often a content negotiation phase:

  • The paste target says "I support these content types: ...."
  • The clipboard manager then discusses that list with the data source to get the pasted data in a suitable format for the paste target.
  • And finally, the data gets dumped in your contenteditable element as text/html with all that extra noise.

The process may not be exactly like the above but it will be similar. Your best bet would probably to add a handler for the paste event and use that handler to convert the pasted data to text/plain.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • Can you suggest the best way to target only the pasted data? I don't want to strip html tags from the text that may already be in the field. – wilsonpage May 16 '11 at 21:03
  • @pagewil: Have a look at Tim Down's approach. You could also grab TinyMCE or CKEditor and see how they handle pasting through the menu. I don't manage my own `contenteditable` elements, I've always used one of the existing editors for that sort of thing. – mu is too short May 16 '11 at 21:23