­Almanac ui

We’re nearing the end of another community almanac development cycle, where we changed the ui quite a bit. Here are some of my thoughts on it.

The operation that we wanted to optimize for was contributing a page to an almanac. We used to call them “stories” but we tried to stress the book/page metaphor a little bit more now. We also tried to make sure that adding a simple page was very easy, while also providing flexibility for the user.

Previously, we had taken a wizard-like approach for this case. A user was presented with a series of questions, taking them through the process of adding their story. This forced the user to go through the process of adding a story in a very strict way, and presented more questions to the user than was usually necessary, at least for the simple cases.

A different approach

This go around, we took an approach that feels a bit like basecamp. Instead of providing a wizard, or series of questions that the user should enter, the user is presented with a set of tools that control the type of content that the user is contributing. This allows the user to add the type of data that they are interested in, without forcing the concept of “metadata” to the user.

An advantage with this model is that it offers more flexibility for creating pages. Users can add the types of data that they want, in a way that makes the page flow more naturally. They can now have several locations, descriptions, or none at all. It also feels a lot more like what the site should be all about: adding pages to a community’s almanac.

Under the hood

Implementation wise, this means that we have to be able to generate lots of forms on demand through javascript. There are a couple of ways to manage this, but we decided to have the server generate these forms, and the client side would issue ajax requests to send/receive all data. This keeps the javascript simple, with the server handling most of the logic.

This is similar to how we handled opencore’s javascript. The client sends a request to the server (usually getting the url from an anchor or the form that the object is in), and knows how to handle a couple of different responses in a generic fashion. Usually the variations are simply to take some html returned from the server and put it somewhere, either by replacing an element, or adding it somewhere else on the page.

There was an additional complication on the almanac side, which was that we needed to apply some side effects for the content to be displayed properly. This is sort of like the “breathe life” problem, except we needed it to simply display the content properly, as opposed to interacting with additional events. For example, when a map is returned, some javascript needs to run to display the map correctly, with the right features displayed on it. For audio playback, some flowplayer behavior needs to get applied to it before it can play in the browser through flash. We did also have to tackle adding behavior as well (so the forms that got returned where submitted through ajax), but we were able to use jquery’s live events for a lot of it.

Always something

Since we’re loading a lot of javascript on page loads as well, we ran into an issue where you could click on a link before it got its document.ready behavior applied to it. The user gets presented with a download dialog box, asking to download the json return value. We worked around this by having empty onclick handlers in the markup itself, which prevented the dialog boxes. Ideally we would have non-javascript fallbacks everywhere, but we didn’t focus on dealing with that issue because a large portion of the site deals with map interactions, which isn’t really feasible without javascript. You can say that you can have page loads for each click, like panning or zooming, but drawing features on a map without javascript is tough.

Thoughts for the future

The similarities of the ajax approaches of both almanac and opencore got me thinking if these are both more specific instances of a general pattern. Kss as a solution comes to mind. What worries me about kss however is that it seems focused on completely removing all javascript from the application. But on the other hand, it seems like the concept of applying js behavior to elements in the same kind of way as style is applied to elements is a reasonable approach. And kss is a way of standardizing the behaviors, in the same sort of way that styles standardize on the display. In fact, most of the javascript that I write involves selecting some elements, and applying a simple behavior to them. Behavior will probably vary a bit more than style, but I definitely prefer having a solution for most cases than no solution at all. In any case though, I definitely think kss is a cool concept.

­

Filed June 26th, 2009 under best-practices, programming, ui

­­­

­­­­­­Inspired by Doug, and the fact that I’ve promised myself that I’d blog more this year, here’s my much-delayed return to blogging.

I’ve been thinking a lot about the importance of consistency and predictability in terms of software usability, specifically with respect to Xinha. Web-based WYSIWYG editors face particularly tough challenges when it comes to consistency, since they must deal with a slew of cross-browser (and cross-browser version) incompatibilities, quirks, bugs, or whatever else you what to call all of the little and not-so-little issues that arise when trying to write modern web applications.

If cross-browser inconsistencies are bad, intra-browser inconsistencies — that is, user-facing inconsistent behavior in the same version of the same browser — are really bad. To make things concrete, here’s an example of what I’m talking about: bolding text. This is an exceedingly basic task that any rich text editor is going to need to be able to handle. Yet as far as I know there is not yet a single online WYSIWYG editor that handles bolding both consistently and properly.1

This issue stems from the fact that visual text selections do not have a one-to-one mapping to ranges in the DOM. For example, consider the following text as rendered in a browser:

unselected_text.png

The markup for this snippet looks like this:

example1.png

Now, imagine that a user selects the second occurrence of the word “this” in the sentence as follows:

selected_text.png

And this is where the trouble starts. Depending on how the browser has chosen to ha­ndle selections, this selection could actually correspond to either of two different ranges in the DOM. The core question is whether or not the selection includes the opening STRONG tag. If it does include the tag, the selection looks like this:

example2.png

Alternatively, the range could include the tag:

example3.png

(If the selection extended to the end of the sentence, the situation would be even worse, since the range could include or not include the closing tag. In this case the visible selection could map to up to four distinct ranges.)

Now, for many cases minor discrepancies like these do not matter. However, there are several where these differences greatly affect how the application actually works.

For instance, if the user proceeds to type a word to replace the selection, the outcome will be different depending on the boundaries of the range.2 For example, in Xinha, TinyMCE, and Google Docs under Firefox 3 and IE 7, the behavior is “correct” in that it does what I think most users would expect: The resulting word is still bold. That is, if the user types “THIS” the resulting markup is,

example4.png

Safari, however, produces the following markup:

example5.png

Another place where this issue crops up is cursor placement. Continuing with our example above, if a user puts the cursor at the beginning of the bolds section (i.e., just before the first bolded letter), the expected behavior is to not bold whatever the user types next. If on the other hand he places the cursor after the final bolded letter, the expected behavior is that the text typed at that point is bolded. Unfortunately, the behavior is inconsistent and sometimes unexpected. For example, Firefox shows consistent behavior, however, it is anything but obvious to novice users or those unfamiliar with HTML markup. Firefox determines whether the cursor is inside or outside of the tag depending on how the cursor got there. Approach an opening tag from the left (e.g., by using the arrow keys), and it will be outside of the tag; approach the opening tag from the right, and the cursor will be inside the tag. This means it’s possible to press the left arrow key and then the right arrow key and end up in the same visible location but in a different point in the DOM.3

The issue here is that in order to know what will happen when you start typing, you have to know something about the past — you have to know how the cursor got to be where it currently is. There is no way to know whether your text will be bold simply by looking at the ­current state of the editor.

None of these issues are deal-breakers; there are ways around all of them, and users tend to discover such workarounds over time. My concern is that the cumulative effect of all of these little annoyances is significant: It puts an undue burden on the user (to remember if/when the editing behavior differs from the rest of her computing experience, and to know how it differs between browsers if she switches or uses a friend’s computer), and it subtly teaches people to distrust the software. As I’m primarily interested in writing software that people will love — and I would argue that it’s nearly impossible to love a program you can’t trust — I think these “minor” issues are actually real barriers. As such, I’m hoping that after getting the upcoming release of Xinha out the door, I will be able to spend a real amount of time ironing out these inconsistencies. The result will I hope not just better software, but more enjoyable software.

 

­

  1. Note that by “properly” I mean “how the vast majority of users expect things to work.” Realistically, this means — for better or worse — working the way that Microsoft Word works and most other word processors work.
  2. Unless, of course, the editor’s developers have made a special effort to take these distinct cases into account and alter the browser’s default behavior if it differs from what they want it to be.
  3. Note that this behavior is not a “bug” in Firefox, since it is sometimes helpful to be able get in/out of a tag. However, that does not mean that this isn’t very confusing to users, and inconsistent with most of their experience using other types of rich-text editors.

­

Filed January 12th, 2009 under wysiwyg, ui, xinha

­­­­Robert Marianski and I have been working on adding the ability to import and export data from listen mailing lists*. Specifically, we’ve been working on exporting mailing list subscribers to CSV files, exporting messages as mbox files, and importing mbox files into the mailing list archive.

By far the most interesting of these is importing mbox files into the mailing list archive. First (along with exporting) it allows for a new use case: Transitioning from one list to another. This gives users more flexibility and helps to avoid lock-in.

Second, it presents some challenging design problems. Importing can be seen in some respects as a relatively “dangerous” operation, as in the process it’s possible to accidentally import the wrong file or even import a corrupt file (this is in fact is something that’s gotten me in the past while migrating from one mail client to another; my “solution” involved manually deleting a lot of messages and then editing the source of the mbox file to fix the errors, hardly something that most users would ever want to do). In either case, your mailing list archive is now polluted with a bunch of messages you don’t want there. Worse, listen doesn’t currently support deleting messages from the archive, meaning once messages are in the archive, there’s no getting them out.

The question is, how do you prevent this from happening? One way to at least mitigate the issue is to give a confirmation warning before actually importing the messages into the archive. This may help in the event that the user accidentally selected the wrong file, but it’s hardly ideal and it’s still quite possible something could go wrong. Even better would be to show a preview of the messages that would be imported and let the user look at them to make sure they are correct. But this brings with it its own set of questions: How large should the preview be? Should the full messages be shown or just some of the headers? Do you make the user submit the file twice (once initially, once again when confirming) or do you store it on the server? What happens if the user never clicks anything on the confirmation page? What happens when the user confirms and then changes his mind?

Rob and I quickly realized that this was a case of using a warning when we really meant undo. What would be most useful for a user would be to be able to undo any import — at any time.

From a technical standpoint, this is actually not too complicated (save for a few nasty and hard to isolate Zope bugs, which I won’t bore you all with here…). All we had to do was store the message IDs, along with some other meta data (e.g., the time of the import), and provide an interface for removing just those messages from the archive. And this is exactly what we did: You can now remove any messages associated with any past import, even if you’ve subsequently imported other messages after them.

 The branch we worked on is here, and here’s a screenshot to give you a better idea of what we did:

import.png

* There were a few days a couple weeks ago that I’ve missed chronicling so far. During those days Anil and I worked on the Feed Me plugin for WordPress, which makes it easy to incorporate feeds from Delicious, Flickr, and YouTube into any WordPress blog. The plugin has been used by Streetsblog for a while , but we generalized it and added a handy admin interface that lets you easily customize the number and type of feeds used. Check out the project page.

Filed August 4th, 2008 under listen, ui

I spent most of my second week doing some Xinha UI work with Doug. Our broad directive was to improve the Xinha user experience, so we started by talking with Sonali and Bryan about known interface bugs and quirks, and got a good idea of where some of the major usability shortcomings are. My general thoughts on WYSIWYG editors for HTML-based content are that they’re almost always mediocre and are hard to do well as full-fledged desktop applications, and are even tougher to do well as web-based apps. To date, I’ve never seen any browser-based WYSIWYG editor that didn’t require me to either fight its idiosyncricities or delve into the source to get it to do exactly what I wanted it to. Xinha has come a long way, but there’s definitely still a lot of work to be done.

We decided to start by concentrating on Xinha’s popup dialogs, which are used in plugins all over the place, e.g., for adding a link or inserting an image. Since many people find popups annoying, not to mention the fact that they interfere with people’s popup-blockers, we decided to look into converting the existing popups into lightboxes. Not wanting to reinvent the wheel, we looked at several different options for lightbox libraries. I hadn’t realized just how many lightbox libraries have (no pun intended) popped up over the past year or two. Unfortunately, many of them have significant downsides: some aren’t released under free licenses, and more than a few appear to no longer be under active development. We ultimately opted to give nyroModal a shot, since it has had more than one release, uses JQuery, is relatively full-featured, and is released under an MIT license.

Not long after we started using nyroModal, however, we came across a branch of Xinha called new-dialogs that was started a few months ago by one of the core Xinha developers. As its name suggests, the branch is a major update to Xinha’s dialog system and has had a significant amount of work put into it. Details of its development can be found in the change history for ticket #1176. In short, it does almost exactly what we were hoping to do, and overall, does it quite well.

Interestingly, new-dialogs does not use any of the aforementioned libraries for its lightboxes. Instead, it includes its own lightbox code written from scratch. Its dialogs are resizable, draggable, and even dockable, though I’m not sure how necessary (or even desirable) the first two are for a modal system.

Much of what’s left to do with new-dialogs is to transition all of the plugins that use the old popup dialogs over to the new system. Doug and I have started working on this process by updating the UnFormat plugin.  Doug has since done the BackgroundImage plugin and I’ve done the Abbreviation and FindReplace plugins. There are still quite a few plugins to go, but once the rest are updated there shouldn’t be much holding us back from making the jump to a popup-free Xinha.

Filed June 30th, 2008 under ui, xinha