Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Tools
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Javascript Snacks, Nibble #1: RTE/WYSIWYG is Built in to your Browser

Pivotal Labs
Wednesday, May 20, 2009

The Label

“Tasty! No Trans-Fats.”

I’ve now worked with a number clients who have a taste for a “rich text” editor
experience. Each time, the team initially looked in to using an
off-the-shelf package, e.g.:

  • TinyMCE
  • FCKeditor
  • WysiHat

Each of these client projects had fairly basic needs.
Pretty much everyone wants “bold”, “italic”, “underline”. Throw in bulleted
and numbered lists and perhaps a few other trinkets and you’ve pretty much
covered the use cases.

It turns out that the existing packages are generally tricky to integrate and
modify or configure per your particular needs. This makes sense. A full-blown
Javascript RTE package needs to have capabilities far in excess of anything
a given project requires, simply in order to meet every project’s
requirements. You end up with a massive library that is not trivially
integrated into your site. What to do some TDD/BDD on the RTE interaction
with your page? Good luck.

So, I’ve generally suggested that we roll our own.

I know, crazy. Why write something new and custom when so many others have
already solved all of the issues with, for example, cursor movement and text
editing and command handling (e.g., making the text “bold”) and image
placement, and…?

Well, it turns out that all of that
behavior is already built in to the browser. Yes, my browser, your browser.
Pretty much every browser you need to care about1.
On top of that, the basics are extremely simple.

To many, this may not be news at all. The basic capability has been around since MSIE 5.5 was released in 2000. On the other hand, I’ve worked with a number of very smart and seasoned web developers who were unfamiliar with the extent to which it is the browser, rather than the libraries, that has taken care of the hard parts.

Ingredients

What you’ll need to make this work2:

// enable editing:
document.contentEditable = true;
document.designMode      = 'on';

// make something bold:
document.execCommand('bold', false, []);

It’s pretty much as simple as that. Give it a try: paste the following
snippet into your browser’s address bar, hit enter, and edit text or resize
images on this page to your tummy’s delight.

javascript: function enable_DM() { document.contentEditable = true; document.designMode = 'on'; }; enable_DM();

Preparation

So, with those ingredients we can make quite a mess of the page we’re visiting,
but we’ve hardly created a delicious RTE. To go the next step, we need a way
grab the HTML representation of our edited content to send with a form
submission.

The basic idea here, which is what every editor out there employs,
is to embed an <iframe />, the document of which is editable, and when
appropriate copy the HTML of that document to a (likely hidden) textarea within
your form.

Why an iframe? There are two important reasons:

  1. You probably want to protect the look and behavior of your edited document
    from the styles and scripts of the rest of your site.
  2. Until version 3, Firefox only supported designMode, which is applicable
    to the document, but not to an element within your page.

There are slight browser differences that will come in to play, e.g. MSIE’s
IFrameElement.document property versus Firefox’s (and the W3C standard)
IFrameElement.contentDocument. As long as your editor remains fairly simple
these intricacies will cause very little trouble.

I’ll leave it to you to hook things up to your liking, but will toss in this
morsel: On a current project, we’re using a home-baked RTE which, from 100
very-nicely-formatted lines of Javascript (not counting the supporting
jQuery and Disco
libraries), is providing…

  • DOM building of the iframe and command toolbar (<ul /> with “buttons”), etc.
  • Document editability
  • Registration and handling of 8 commands (e.g., “bold”, “italic”, “indent”)
  • Content transfer to-and-from an associated textarea
  • Additional helpers (e.g., get the currently-selected text as HTML)

Tasting Notes

  • 1 My apologies to visitors using a
    specialized browser for accessibility.
  • 2 Setting document.designMode
    should be enough, but there are reports of discrepancies in MSIE’s handling
    of the two.

Shopping List

  • An MDC article on Mozilla’s Implementation
  • Another MDC article, highlighting some differences with MSIE
  • An MSDN article on MSIE’s Implementation
  • Mark Finkle on contentEditable in Firefox 3
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

11 Comments

  1. gabriel says:

    Thanks for the tasty snack. I’ve shared it with others: http://queri.ac/commands/pedit

    May 20, 2009 at 12:47 pm

  2. Tom Ward says:

    This is marvellous. Where has this information been hiding all this time?

    May 20, 2009 at 12:57 pm

  3. linoj says:

    All these years, and I never knew about this. A rails / jquery plugin for this would be awesome :)

    May 20, 2009 at 4:28 pm

  4. Alex Chaffee says:

    > On a current project, we’re using a home-baked RTE

    WANT!!!

    May 20, 2009 at 5:55 pm

  5. Corey Innis says:

    Glad you all found some interest.

    @linoj: Can you clarify what it is you’d want to see in a plug-in. Part of what I’m trying to suggest is, this is simple enough that it may make sense to build things to your project’s specific needs. However…

    @Alex: I’ll get something up on The GitHub today and share it here.

    May 21, 2009 at 1:49 pm

  6. Corey Innis says:

    Ready to get your groove on? [http://github.com/coreyti/syncopate](http://github.com/coreyti/syncopate)

    May 22, 2009 at 2:44 am

  7. Evgeny says:

    Wooowoo! :)

    Cool stuff

    May 31, 2009 at 6:35 pm

  8. Louis St-Amour says:

    What I’m looking for, and can’t find *anywhere* is simple:

    The ability to bold, underline, italicize, and apply my own custom CSS styles (ideally with live preview, but that’s tough to get right), remove all styles from selected text, and most importantly: image and link abilities like Gmail. To me, Gmail is the model to emulate, but customize it to fit your site instead of a generic email message.

    Why has no one else, for instance, offered Gmail-style link abilities through a tooltip that automatically appears below a link when your cursor is inside. In that tooltip, you see the full URL you’ve linked to, which is clickable so you can visit it in a new window, along with a button to Edit and another to Remove. Simple.

    Images are trickier, like files, as you will want to style them or treat them differently, sometimes, but not always. For instance, I might want a default behavior to be for an image to be inserted as a left float at where the cursor drags the image. (Or where the cursor is when I click an image button to upload or select an image). Having said that, it’s all styling, pretty much, so I suppose the only interesting image functionality, is like links, the live preview, the ability to pick a new image, and (though this depends on the browser I can imagine) resizing the image.

    While I would then want to add my own things to it further, such as common blocks for formatting, etc., all I really care about are that I can apply styles, remove styles, add links, edit them with a tooltip, and remove them.

    I guess what I’m saying is why hasn’t anyone copied Gmail yet? It’s been at least 2 years that they’ve been doing this, has no one noticed? I know people who literally use Gmail as an HTML editor, and copy and paste the HTML from there into whatever CMS they use. (I actually used the same technique with some Word documents, stripping formatting with Gmail and reapplying some of it, then copying the resulting email.)

    I’ll now take a look at the github you mentioned, Corey, as I’m hoping you’ve done something cool with your link handling. So far, most posts on contentEditable haven’t been as concise as yours, and I’m really hoping that styles, links, images and files aren’t too much to ask for. Of course, I haven’t even started mentioning content filtering server-side. But hey, if Gmail can do it …

    Here’s what I mean (from a Google Images search):

    http://clarkbw.net/blog/wp-content/uploads/2008/07/gmail-links.png

    BTW, while there I saw some other fun posts:

    http://clarkbw.net/blog/2009/05/14/negotiate-with-your-users/

    And the guy works on design for Thunderbird, so the above Gmail image actually has this post for context, where Bryan compares links to attachments, in Facebook, Gmail: http://clarkbw.net/blog/2008/08/21/what-are-attachments/

    Honestly, I think I would take the facebook approach if a site has lots of links, or if I could somehow provide the editor (or even end user?) of the webpage some context – at least for in-site URLs and pages. It would also work amazingly well if linking to photos or something visual, in addition to a textual representation of the URL as in Gmail.

    July 1, 2009 at 11:17 pm

  9. Louis St-Amour says:

    Speaking of writing HTML, you should also copy Gmail here, and make text that begins with http:// a link automatically. Gmail has some fancy rules to ensure that punctuation isn’t considered part of a link also, I believe. Okay, so simplicity like Google’s is tough, but I still don’t see why more people haven’t adopted it. Does it feel too much like re-inventing the wheel?

    I would suggest something like X-Standard, if it only was free/open source, and a bit more Gmail-ish, without being too generic or hard to customize. For instance, to me, the distinction between large and small fonts or even font-faces, and styles, is something that for most website designers or even commenters, you don’t care about. Colours you might care about, but the best choices could be entered in also as styles or classes to mix and match. No need for extra buttons for that… And while a component like XStandard creates perfect XHTML, it requires installation beforehand, and it’s harder to modify too.

    July 1, 2009 at 11:22 pm

  10. Louis St-Amour says:

    I’ll have to play with this idea further, but it appears I can answer my own “How to copy Gmail” question above –

    After peeking at the git for syncopate, I like it. Not sure if I’ll use it, but if I do, I’ll fork it and contribute my changes, I suppose.

    From googling, and without clicking any actual links (yes, often Google result text is all I need), I suspect I can use the “createlink” command to create the link, and then the link that is created — or what is under the cursor — is accessible via parentElement(). I can then imagine a quick absolute-positioned tooltip being created with the parentElement’s href as a clickable link, an Edit button to pull up another editor/modal div, and a Remove button to well, replace the A element with its inner text.

    One small other annoyance: You would have to watch for keystroke presses, to see if the cursor is inside a link (via parentElement) and when the cursor has then left the link. I’m not sure how it interacts if the cursor is on the edge of a link. Based on past Gmail (annoyed) experiences, if at the start, it doesn’t link (argh, sometimes) and if at the end, it will continue a link (double-argh, unless I’m actually editing a link).

    To be honest, I wish there was a way to set a border around a link’s text, and visibly move the cursor from inside the border to outside of it, or vice versa, but I doubt that’s easy or intuitive with current tech. I could be (and knowing HTML, likely am) wrong, and would love to be proven so. ;-)

    July 1, 2009 at 11:39 pm

  11. Louis St-Amour says:

    Wow, I’m so sorry for replying so many times! ;-)

    I tried adding the createlink command, but it didn’t seem to do anything in my browser (Safari 4), despite working in other editors.

    But as I continue on this quest, I’m noticing that in addition to the quirksmode chart of contentEditable compatibility (and tester), a quick google search of *contentEditable createlink parentElement* revealed part 2 of an Opera article:

    http://dev.opera.com/articles/view/rich-html-editing-in-the-browser-part-2/

    And lo and behold, if everything from the **link** heading on down isn’t applicable to what I’d like to do. (But again, note they stick to simple popup boxes rather than doing any more fancy UI work.)

    I particularly liked Opera’s parts under **A custom command**, and a part of me wonders why that isn’t the default way of working with this? I mean, if we already know how to insert links and so on with rich DOM tools, why use strange commands like “createlink”? ;-) I’m curious if undo breaks though …

    It’s neat to think then that if you use the DOM route, you can easily pinpoint the cursor in browsers that support ranges, and for IE, you insert a marker element with a unique ID and can then modify from there. Of course, I wonder if I can capture (in IE) the selected text — perhaps I can’t replace createlink in IE, not that I care much about it, really.

    [To correct myself, it appears from MSDN docs and the code sample Opera provides, that you can get the currently selected text, but there's no way to connect that selection to the DOM, which was the problem the Opera article then works around. So yes, it would be possible to use pure DOM methods, which would mean more consistent HTML output, at least from a web design perspective.]

    BTW, this comment system needs a preview and an edit button. ;-)

    July 2, 2009 at 12:09 am

Add New Comment Cancel reply

Your email address will not be published.

Pivotal Labs

Pivotal Labs

Recent Posts

  • Does the set of all sets contain itself?
  • Standup 3/8/2012
  • Standup 3/7/2012
Subscribe to Pivotal's Feed

Author Topics

riddles (1)
agile (167)
capistrano (2)
rails (26)
movember (1)
git (10)
railsdoc (1)
object-design (1)
bdd (3)
cucumber (3)
linkedin (1)
oauth (1)
ruby (17)
tdd (2)
lvh.me (1)
rails 3.1.1 (1)
selenium (6)
homebrew (1)
mysql (5)
rvm (1)
sproutcore (1)
paperclip (2)
pry (1)
amazon (1)
heroku (1)
rails3 (2)
jasmine (3)
design (3)
process (12)
productivity (8)
learning (1)
olin (1)
migrations (2)
mongodb (2)
devise (2)
javascript (13)
rubymine (4)
ipad (1)
whurl (1)
head.js (1)
pairing (2)
tools (4)
pair programming (1)
rspec (10)
rspec2 (1)
ruby19 (1)
incubation (3)
startup (5)
api (1)
presenter (1)
vanna (1)
pivotal tracker (5)
capybara (1)
fakeweb (1)
webmock (1)
intern (1)
ruby on rails (25)
meetup (1)
textmate (1)
testing (20)
solr (4)
nyc-standup (11)
community (1)
opensource (3)
activerecord (4)
chrome (1)
mp4 (1)
activeresource (1)
flash (3)
neo4j (1)
nginx (1)
rsoc (1)
meta programming (1)
agile standup (7)
government (3)
webos (4)
xss (1)
jquery (1)
bundler (2)
ci (3)
gems (5)
postgresql (1)
geminstaller (1)
gemcutter (1)
cloud (2)
rack (2)
refraction (1)
gem (5)
refactoring (1)
validations (1)
webrat (1)
engine-yard (1)
firefox (2)
jsunit (1)
mongrel (2)
thin (1)
unicorn (1)
facebook (1)
rubygems (5)
jruby (1)
actioncontroller (1)
rails 2.3 (1)
palmpre (1)
autotest (1)
mac (2)
hosting (1)
goruco (11)
database (3)
railsconf (11)
gogaruco (4)
deployment (4)
github (1)
ie (1)
ajax (1)
intellij (1)
json (1)
asset packaging (1)
polonium (1)
character encoding (1)
utf-8 (1)
test (3)
civics (1)
hpricot (1)
rake (3)
sms (1)
unicode (1)
iphone (1)
java (1)
safari (1)
memory leaks (1)
rr (3)
editor (1)
css (1)
nyc (3)
performance (5)
fun (5)
enterprise rails (1)
health (1)
new and cool (1)
general (2)
treetop (1)
errors (1)
stack (1)
trace (1)
cache (1)
cookies (1)
freesoftware (1)
conferences (1)
development (1)
driven (1)
proxy (1)
caching (1)
peertopatent (1)
languages (1)
rest (2)
rubyforge (1)
sake (1)
file (1)
upload (1)
constants (1)
osx (1)
terminal (1)
pairprogramming (2)
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Tools
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >