Upgrade to Pro — share decks privately, control downloads, hide ads and more …

contenteditable

 contenteditable

A talk I gave at DublinJS about contenteditable and its related JS APIs. The accompanying video is at https://www.youtube.com/watch?v=zB3PexOSvhg

Pat O'Callaghan

December 02, 2014
Tweet

More Decks by Pat O'Callaghan

Other Decks in Programming

Transcript

  1. Agenda • What is contenteditable? • History • Editing APIs

    • execCommand • Selection APIs • Paste • Editor case studies
  2. What is contenteditable? • designMode document.designMode = ‘on’; • Make

    document or elements editable • contenteditable <div contenteditable></div>
  3. The APIs specified here were originally introduced in Microsoft’s Internet

    Explorer, but have subsequently been copied by other browsers in a haphazard and imprecise fashion. Although the behaviour specified here does not exactly match any browser at the time of writing, it can serve as a target to converge to in the future ! - W3C HTML Editing APIs, Feb 2014
  4. contenteditable • Add a contenteditable attribute and away you go

    • Same set of operations in different browsers can lead to different markup • When you hit enter, what does it create?
  5. contenteditable • What about backspace? • <p> has a line-height

    of 1.5em Chrome becomes <p contenteditable> d|d </p> <p contenteditable> d|<span style="line-height: 1.5em;”>d</span> </p>
  6. contenteditable • And there are numerous other “bugs” like this

    • Markup isn’t generated consistently in different browsers • Makes it difficult to use HTML as a data format • A markup sanitisation step is a necessity
  7. document.execCommand • Provides commands to manipulate an editable region document.execCommand(command,

    showUI, value) document.execCommand(‘createLink’, false, ‘http://www.intercom.io')
  8. document.execCommand • Lots of commands with varying degrees of cross-browser

    support Inline Commands backColor bold createLink fontName fontSize foreColor hiliteColor italic removeFormat strikethrough subscript superscript underline unlink Block Commands delete formatBlock forwardDelete indent insertHorizontalRule insertHTML insertImage insertLineBreak insertOrderedList insertParagraph insertText insertUnorderedList justifyCenter justifyFull justifyLeft justifyRight outdent Miscellaneous Commands copy cut defaultParagraphSeparator paste redo selectAll styleWithCSS undo useCSS
  9. Inline commands • Bold and Italic document.execCommand(‘bold’)
 document.execCommand(‘italic’) • <b>

    and <i> tags in Safari, Chrome & Firefox • <strong> and <em> tags in Internet Explorer :(
  10. Inline commands • fontSize and fontName document.execCommand(‘fontSize’, false, 7)
 document.execCommand(‘fontName’,

    ‘Times’) <font size=“7” face=“Times”> Selected Text </font> <span style="font-family: Times; font-size: -webkit-xxx-large;”> Selected Text </span>
  11. Block commands • insertParagraph document.execCommand(‘insertParagraph’) • Might not actually insert

    a paragraph • How the “paragraph” is inserted differs between browsers
  12. Block commands • formatBlock document.execCommand(‘formatBlock’, false, ‘<H2>’) • Converts a

    block level element to another • IE caveats • only supports H1-H6, PRE and ADDRESS • requires block to be pre-formatted
  13. Miscellaneous commands • undo and redo document.execCommand(‘undo’)
 document.execCommand(‘redo’) • undo

    works in all browsers, but redo does not work in IE • Inserting custom content will mess up the undo stack
  14. Selection APIs • Selection and Range • Used in combination

    to read and create text selections, and control the caret • Use the Range API to add nodes to a range • Add range to a Selection to show it on screen
  15. Selection API ! • Get the current text selection var

    selection = window.getSelection(); • Find out where the selection starts and ends: ! ! ! ! • It’s a caret if the nodes and offsets are the same selection.anchorNode selection.focusNode selection.anchorOffset selection.focusOffset
  16. Selection offsets • ELEMENT_NODE • Offset is its index in

    its parent’s childNodes collection • Example: • node is <i>index 1</i>, offset is 1 <p> <b>index 0</b> <i>index 1</i> </p>
  17. Selection offsets • TEXT_NODE • Offset is its index in

    its own textContent string • Example: • node is “index 1”, offset is 2 <p> <b>index 0</b> <i>index 1</i> </p> |
  18. Manipulating the selection var selection = window.getSelection();
 var range =

    document.createRange();
 range.setStart(startNode, offset);
 range.setEnd(endNode, offset);
 selection.removeAllRanges();
 selection.addRange(range); ! • You can now • Apply an execCommand on the selection • Save the range with selection.getRangeAt(0), do some work, re-add the range and it will be reinstated. • Collapse the selection to a caret with selection.collapse() • Get position of the selection or caret with selection.getBoundingClientRect()
  19. Selection issues • In general, the API works fine cross-browser

    • …except for a crappy bug in Chrome • Can’t place your cursor inside empty nodes |<p></p> • Zero-width spaces to the rescue! <p>&#8203;|</p>
  20. Paste • 2 approaches 1. Let the paste happen and

    sanitise afterwards 2. e.preventDefault the paste event, sanitise and input the pasted content yourself
  21. Paste To get access to formatted HTML for Safari &

    IE 1. Create an offscreen contenteditable div 2. On the beforepaste event redirect your caret to the offscreen <div> 3. Don’t e.preventDefault the paste event as your pasted content will now be sent to the offscreen <div> 4. You now have the formatted version of the pasted content
  22. Paste - Google Docs • Can detect when it’s Google

    Docs by the presence of: id=“docs-internal-guid-234234” • bold and italic styles are inlined rather than using <b> and <i> elements • Some Google Doc styles are hard to detect
  23. Paste - Microsoft Word • Chucks <o:p> tags throughout the

    content • Easier to translate than Google Docs as they use HTML classes • MsoTitle
 MsoSubtitle
 MsoNormal -> <p>
 MsoQuote -> <blockquote>
 <h1> -> <h6>, <b>, <i>, <a>
  24. Microsoft Word - Online version • Microsoft Word’s Online version

    has different markup and classes than the desktop application • Lists again are typically mental
  25. So if you contenteditable et al. are so to work

    with, what are the alternatives?
  26. Google Docs • Don’t use contenteditable at all • Google

    created their own layout engine to overcome its limitations • Caret is a 2px <div>, text selection highlighting is a <div> • They intercept all keyboard inputs and insert into an area offscreen • Calculate where to put it onscreen
  27. Intercom Composer v1 • v1 in production: Leans heavily on

    contenteditable behaviour and execCommand • Lots of cross-browser headaches and jumping through hoops to sanitise the output • Hard to do automated testing • We are currently undergoing a rewrite of our editor
  28. • Have taken a similar approach to Medium.com • Use

    contenteditable backed by a model of the document • Have a mapping between the DOM and our model • Define a set strict of editing operations • Map user input and key events to these editing operations • Flush the DOM frequently so the Model and DOM is in sync Intercom Composer v2
  29. Wrap up • contenteditable, a cool technology but beware. Know

    what you’re getting yourself into. • Possibly leverage an open source library to save you the pain • If going the pure contenteditable route, DOM sanitisation is a must • There are ways of leveraging the useful bits of contenteditable (selections and events) and minimising the “bad” parts
  30. Links • http://www.quirksmode.org/dom/execCommand.html • https://blog.whatwg.org/the-road-to-html-5-contenteditable • https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html • http://w3c.github.io/selection-api/ •

    https://annevankesteren.nl/2005/07/more-contenteditable • https://annevankesteren.nl/projects/whatwg/spec • contenteditable: Roll for sanity by Garann Means http://vimeo.com/76219173 • https://github.com/guardian/scribe/blob/master/BROWSERINCONSISTENCIES.md • http://features.jsomers.net/how-i-reverse-engineered-google-docs/ • http://googledocs.blogspot.ie/2010/05/whats-different-about-new-google-docs.html • https://medium.com/medium-eng/why-contenteditable-is-terrible-122d8a40e480 • http://garann.github.io/contenteditable/