Tuesday, September 22, 2009

Implementing a Rich Text Editor with contentEditable

Now that the Gecko Engine (Firefox) has support for the HTML5 contentEditable attribute, it's become a heck of a lot easier to roll your own rich text editor.

I'm doing that very thing, and will comment on each gotcha I discover, beginning with this one.

contentEditable Gotcha #1:

In Firefox 3.5, Justification commands (justifyLeft, justifyRight, justifyFull, and justifyCenter) are broken for the first chunk of text in a dynamically created DIV tag with contentEditable="true".

I creating the following HTML using a combination of document.createElement() and Element#innerHTML:
<div contenteditable="true">
Test content
</div>

When firing the "justifyRight" command via document.execCommand(), this nasty error is thrown:

[Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMNSHTMLDocument.execCommand]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: https://localhost/editor.js :: anonymous :: line 8" data: no]

Egads! This is such a simple test case that I had to have been doing something wrong. All justification commands on the original content failed. However, if I pressed enter and typed a new paragraph, the justification commands worked perfectly.

The Workaround

Because only the first DOM node in the editable DIV could not be justified, I simple inserted a dummy element:

<div contenteditable="true">
<!-- begin gecko fix -->
<div></div>
<!-- end gecko fix -->
Test content
</div>


Yes, it's entirely gross; but it works. Hopefully the Firefox team will fix this in the future.

Saturday, August 22, 2009

"Do We Have a Setlist?"

http://dowehaveasetlist.com/

Perhaps due to the lack of creative adventures at work the past few weeks, I decided to write a working web app in 5 days (mornings + evenings only, no cheating during working hours).

I've been fascinated lately with collaborative authoring and the impact that we may see from Google Wave, due to both it's collaborative nature and the introduction of temporality to conversations. Watching a discussion morph over time by replaying it like a movie is fascinating at both social and technological levels.

So, for you Agile nerds, here was my user story:

"As a musician, I want a way to easily write, share, edit and print a set list so that I don't freak out at the last minute before a show and go hunting for a paper pad and half-working pen from a bartender."

The "done criteria" are:
  1. No authentication, login, or process that gets in the way of the product
  2. Many band members can edit the set list at one time without locking or error messages
  3. As keyboard-driven as possible
  4. Ability to "replay" the set list's authoring process to see decisions made over time
  5. An effective stylesheet for print media

It surprised me in a way, because the end product may not apply only to music set lists but any simple collaborative writing in general. For example: this morning, Jenny used it to write me a note illustrating her intense desire for me to put down the coffee and go on a bike ride with her. Watching the replay of the note showed me a glimpse of her thought process.

Technical Details


The app is built with Rails, MySQL, and a decent batch of JavaScript. The realtime updates are done through Juggernaut, a push server for Ruby & Rails.

I've tested it in Firefox 3+ and the latest Safari. Because this is a personal experiment, I have no interest at the moment in making it work in IE6 or IE7.

Tuesday, June 23, 2009

Slackers

This article had me rolling this morning:

The Seven Habits of Highly Effective Slackers


Does anyone else feel called out?

Wednesday, June 3, 2009

Buttons in Physical and Virtual Environments

While using the self-service postage machine at the Post Office today, I noticed what appeared to be a pretty high latency between when I punched a button on the keypad (a real keypad, not touchscreen) and when my action was acknowledged and processed. The feedback came in the form of a "chck" sound, much like an old typewriter.

Eventually, I realized that the "latency" was due to the fact that button presses were not registered until my finger came up, as opposed to when the key was depressed. The system was behaving exactly how it was designed, but it presented a false sense of latency and sluggishness.

Why?

Event handling on the automated postage machine was that of a virtual button, where click events are not fired until the button is released (think: onmouseup). Conversely, a physical button's click event is fired when it's pressed (think: onmousedown). Don't believe me? Open up TextEdit/Notepad and press a key on your keyboard. Imagine if the keypress didn't register until the button popped up; wouldn't that be annoying as hell?

Here's an example. The following button uses the virtual button event paradigm:



Notice how you can move the mouse off of the button before it pops back up, and the event is cancelled.

This button uses the physical button event paradigm:



Kind of annoying, huh?

Using the physical paradigm in a virtual environment doesn't give the user a way to change their mind. Using the virtual paradigm in a physical environment adds the effect of latency.

Why do I think about stuff like this? I'm weird, I guess.

Wednesday, May 13, 2009

Building Better Mockups

A mockup or simple prototype is the first chance stakeholders have to get a grasp of a designer's vision. First impressions are everything, so you wanna do this right.

Here are some tips I've learned (the hard way) over the years:

1. JavaScript is your friend.

As a designer, half of your job is to convey an Experience. Don't be afraid to spice up your work with interactivity; leverage a framework such as Prototype, Script.aculo.us, or jQuery. If your design involves an expanding or collapsing component, then hard-code the animation. If your design involves an AJAX call, "fake" the call by displaying a spinner for 2 seconds.

A modern mockup should involve HTML, Images, JavaScript and CSS.

2. Widgets Suck.

When writing fake copy text, avoid the term "Widgets" like the plague. Everybody has, sells or needs widgets. I suggest using Cats or Weasels.

3. It's OK to write imperfect code.

The mockups I build typically work in only one browser. The lifespan of a set of mockups is so short that you don't need to stress about too many inline styles, HTML tables, un-namespaced JavaScript functions, etc.

And, you know those custom CSS directives, like -moz-border-radius? Use'em!

The goal of a mockup is simply to convey a design and degree of usability; the code driving it will be scrapped and rewritten when the project begins.

4. Copy Text is more important than you think.

What's wrong with "[ blah blah copy text here blah blah ]"?

The answer is two-fold. One, it fails to convey a level of usability. If copy text is required in order for the user to understand how the page works, this forces your design reviewers to conceptualize what that copy text should say before they can accurately review your design.

Second, and more importantly, mistakes happen. Sometimes placeholder copy is unknowingly pushed to production without being rewritten. This makes your company look like amateurs. Amateurs, dude.

Ultimately, you want your stakeholders to understand your design as fast as possible. Fake or unclear copy text inhibits this process.

5. Jettison your ego.

It's inevitable that people will disagree with you; you're not a Design Princess. Know when to take criticism with a grain of salt, and know when to listen and react.

And above all, be able to rationally justify your ideas.