Monday, October 22, 2012

RemixSouth: My Talk and My Favs

This weekend, I took a trip to Atlanta, GA to speak at RemixSouth, a conference about mobile, web, design, and startups.

My talk was on "When Mobile Web Browsers Attack!". It was all about the bugs that I encountered in the Android and iPhone Webkit browsers during my foray into PhoneGap hybrid web app development last year, and the weird workarounds I found. Most of my audience hadn't done much mobile web development, so it served as a warning for them of what to watch out for, and for those who had, it was more like group therapy. ☺

I also had the chance to attend others' talks. Some highlights were:

  • Responsive Web Workshop". Ben Callahan put on a 3-hour hands-on workshop about responsive web design. After linking the audience to a git repository, he walked through the very basics of responsive design, using CSS media queries, percentage width, and got attendees to try responsify-ing fixed width pages. He also reviewed the tools that make responsive design easier, like Suzy and Semantic Grid, and Media Query bookmarklet, and went over general guidelines for making sites more accessible across multiple devices and environments (e.g. try your website on a phone outdoors - can you actually read it?). He discussed their agency's website development process, like "content priority mocks", CSS-based prototyping, pricing, and testing. He finished with a review of popular responsive design patterns, like for nav bars and sidebar content. It was a great workshop, and I'm hoping that we can get him to give the workshop in SF sometime this year. I'd love to have our designers attend it.
  • "Eliminating Common jQuery Bugs". Elijah Manor gave a talk where he presented buggy jQuery code, challenged the audience to find the bug, and then walked through what was wrong, what the solution was, and ways to fix it. Most of the bugs were ones that I'm already familiar with, or never run into because I avoid things like jQuery animations, but I still learnt a good deal about jQuery's implementation idiosyncrasies. If you'd like to challenge yourself, try out the lab before you review the slides.
  • "CSS3 Animations". Josh Netherton gave an introduced to CSS3 animations. He finished with two Doctor Who related examples, an animated weeping angel and a really cool rotating, spinning Tardis that magically fades in. I still have no immediate plans for CSS3 animations in my everyday life, but it's sweet to see what they can be used for, when that day comes.
  • "Welcome to the Social". Bill Buxton, Principal Researcher at Microsoft Research, gave a thought-provoking talk on apps and devices, and how apps and devices are eventually indistinguishable from one another - i.e. my Kindle is the same app as my Kindle reader app on my iPhone, just with slightly different hardware. He envisions a future where devices are "social" and know more about the other devices around them, so, for example, I might walk up to a digitally projected ad one day, my phone can connect to it, and then I can use the ad as my own canvas. Now, instead of an ad in my app, there's my app in the ad, and the ad<->app relationship is reversed. Really interesting stuff.

It was a fantastic conference, and it was great to meet the web community of Atlanta. Thanks to the organizers for inviting me out!

Tuesday, October 9, 2012

Using Transloadit with Bootstrap

As I discussed in a previous post, one of my first projects at Coursera was implementing social profiles. A big part of our motivation for adding user profiles is to add a sense of community and intimacy to classes, particularly in the place where students interact with each other the most - our forums. The forums were just long streams of text before, and there was one little thing we could add that would break up those streams of text and instantly make them feel like a social experience: user photos!

Upload Strategies

So, in our new profile editor form, the photo upload area is at the very top, and it's the first part of the form that I worked on. Based on my experience from EatDifferent, I knew that photo upload (or file upload generally) wasn't an easy thing to get working across all the different browsers, and I decided immediately that I did not want to rewrite cross-browser file upload from scratch. I started playing around with the popular jQuery upload library, but then I realized that I also had to solve the second part of the upload equation: once I had the photos, where would I store them on the server, how would I resize them, and how would I get them back out? We store many of our assets in Amazon S3, so I started looking at how to use Python to do image manipulation and S3 upload.

Client-side Uploads with Transloadit

Before I got too far down that path, I remembered that there's a new startup that would do all of that for me: Transloadit. They take care of file manipulation (like image resizing and cropping) and file storage (like to S3 and Youtube), and best of all, they provide a jQuery plugin that will do all of that for you, with no server-side scripting on your side. (There's also a very similar startup FilePicker.io, but I happened to meet the co-founder of Transloadit while wandering the streets of Lyon, France, so of course, I was a bit biased in my selection.)

The Transloadit Plugin

Transloadit designed their plugin so that you attach it to a form, and then it listens to the submit, processes the file inputs, optionally throws up a progress indicator, and notifies you with JSON results when it's done. That wasn't quite the experience that I wanted for our profile form, however. I wanted users to select a file to upload and immediately see it uploaded and displayed, while they continue filling out the form. I changed the Transloadit plugin so that it attaches to any DOM node, and processes the file inputs inside whenever a change event is fired for them.

My Bootstrap Plugin

Both because I didn't like the modal nature of the Transloadit progress indicator and because I wanted a more cohesive look & feel to the upload, I came up with my own Bootstrap-based HTML and CSS for the uploader, which includes a progress bar and a hack for actually letting users click a nice pretty button instead of the default (ugly) file input control.

To tie the HTML, CSS, and JS together, I wrote a small Twitter Bootstrap plugin. In that file, I call the Transloadit plugin on the form, specifying options to wait for results, disable the modal, not submit the form after file upload, and also defining various event callbacks. When the user first picks a file, I change the button text and show the progress bar, and as the upload progresses, I increase the progress bar width. Finally, when the file has uploaded, I fade the progress bar and display the image for the user to see. If the user wants to replace the image, they re-click the button and the progress begins again. Behind the scenes, I store the generated S3 URLs (for 3 different resized versions plus the original) in hidden inputs in the form, and that's what goes into our database.

You can see that flow here:



Improvements?

This isn't the perfect photo upload UI, of course. I'd love to give users the ability to crop the photo on the client (like Twitter has now implemented in their avatar upload UI), and I think I could make it more obvious how to change the photo. But, it has served us well enough so far for the profile form, so we're now using the plugin in our admin interface as well, for accepting all the course, university, and instructor media assets.

Fork It!

To make it easier for others to use Transloadit together with Bootstrap like I have, I've put all the code into a git repository along with examples, which show how to use it for both photos and files.