contenteditable and rich text editing


The good (?)

The bad.

The ugly.

Why talk about this?


There were some interesting problems

You may have to dig into this code in the future?

How to use the rich text editor




Use the rich_text_editor helper:
<%= text_area 'post', 'text' %>
<%= rich_text_editor 'post' %> 
(use sparingly, rich text is usually overkill)

Accessing the Javascript API:
 $('#' + textarea_id).data('wysihtml5');

The bare minimum


Check it out:
http://codepen.io/eric-wood/pen/fKwec

Introducing wysihtml5


Surely someone has made this all easier?

Yes, they have.

https://github.com/xing/wysihtml5/

Wysihtml5 basics

  • Complete rich text editor with features and stuff
  • Deals with browser stuff that hurts your brain
  • Really cool markup sanitizing features (in theory)



Cool, we found an all-in-one solution!


...right?






WRONG.

Roadblock #1


From the list of things we need:
"Admins should be able to insert arbitrary HTML"

What wysihtml5 thinks:
"Screw it, let's just remove EVERYTHING."

( people on Github complain, maintainer is very hardheaded about it )

Solution #1


Modify wysihtml5 and make it optional

if(clean) {
  // this is the original method for parsing elements
  // if we want to use it, set "clean" to true (only done for cleaning up pasted stuff)
  returnValue = this.config.parser(htmlOrElement, this.config.parserRules, this.composer.sandbox.getDocument(), this.config.cleanUp);
} else {
  // just return it, don't bother cleaning anything up
  returnValue = htmlOrElement;
}

Cool, now I can add marquee tags.

Roadblock #2

Rich text copy/paste

Users often copy and paste text from all kinds of sources.
Contenteditable areas will accept rich text.

Not a big issue, right?

Example of what Word throws in your clipboard:

http://pastebin.com/DX7wwU85

The Paste event

You can intercept pasting! Neat.

Chrome and Firefox allow access to the clipboard:
elem.onpaste = function(event) {  var html = event.clipboardData.getData('html');  var text = event.clipboardData.getData('text');};

Caveats
  • Does not work in any version of IE
  • Chrome will remove newlines when requesting text version

That won't work. What now?

  • Intercept onpaste event
    • Grab contents of editor
    • Wrap current selection in temporary tag (hack)
    • Clear editor
    • setTimeout
      • (by the time this fires contents of editor are only pasted text)
      • Store pasted text
      • Restore contents of editor and cursor position
      • Sanitize pasted text
      • Set innerHTML of temporary element to pasted text
      • Remove temporary element...
WHEW.

What took so long?


Feature Creep

It's really tempting to keep adding stuff.

Drawing the line is really tough.

(there's no one-size-fits all solution to this problem)

Infinite possibilities


The editor provides users with a million ways to interact.

More interactions = more potential bugs.

More bugs = delayed release :(

Once again, where do you draw the line?
What bugs are critical?
Prioritization is hard.

Use the source, Luke


Don't be afraid to dig into library source code!

Poking around the surface may seem easier,
but it may cost you time in the long-run.

Avoid adding minified versions of libraries
(the asset pipeline exists for a reason)

Shout out


Thank you to the whole QA team for helping me!

The testing sessions were invaluable.

Related links



wysihtml5
http://xing.github.io/wysihtml5/

Bootstrap-wysihtml5
http://jhollingworth.github.io/bootstrap-wysihtml5/

contenteditable
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_Editable
Made with Slides.com