EtherPad: Real-time Editing with JavaScript

I had the opportunity, last year, to talk with the team behind AppJet. They're building something quite cool: A simple platform for developing reusable server-side applications written completely in JavaScript.

They've come a long way since I originally wrote about them late last year. They now even provide a copy of their server-side software along with the full source. This, together with Aptana's Jaxer, means that there is, at least, two high-powered, Open Source, JavaScript server platforms.

EtherPad is something new altogether. Building upon their existing platform, and adding in Comet streaming, they've constructed a completely real-time, multi-user, text and JavaScript editor.

I use two editors in my day-to-day work: vim and SubEthaEdit (in fact I'm writing this blog post in SubEthaEdit, at the moment) - and I can say pretty definitively that EtherPad is just like SubEthaEdit.

I had the opportunity to use it last week with four people all simultaneously editing a document. It has the characteristic SubEthaEdit feature: All changes, by any user, occur in near-real-time and are highlighted with that user's chosen color.

Some may wonder how this is different from Google Docs. Let me just say that SubEthaEdit and EtherPad are in a completely different league from Google Docs: I've used all three pieces of software for multiple-editing a document and the responsiveness that you get from SubEthaEdit/EtherPad makes for an unparalleled experience. It's really common to see users start chat discussions within a document simply because it's so easy to see their response and get a discussion going.

EtherPad does have one major distinction from SubEthaEdit, though: The ability to save and restore page revisions. At any point you can hit a large 'Save Now' button on the page to tag a revision - and then go back and restore from it at any point. In many ways this makes the software more like a real-time, multi-user editable, Wiki.

The most exciting thing for me though, and a point which I think is unparalleled, the entire application is built using JavaScript from the bottom up. The server code is in JavaScript, the database is in JavaScript, and the frontend is in JavaScript - it's a complete JavaScript stack. The AppJet team plans on releasing this new server-side software (similar to their previous release but with the addition of Comet functionality and other pieces) completely Open Source as well. I look forward to being able to give it a spin when the time comes.

Tags: rhino, javascript

The March of Access Control

The web is changing. Historically it's been painfully easy to request resources from remote locations (such as stylesheets, scripts, images, and loading pages in iframes) - but this has brought along a whole world of security issues that browsers are continuing to try and resolve.

This openness has come to define what web development is all about: Dead simple sharing of resources and ability to get started. It's very likely that the lack of restrictions placed on these historical page elements will continue to plague browser developers for many years to come.

That doesn't mean that browsers have to make the same "mistakes" going forward.

This is where the new W3C Access Control specification comes into play.

All the new cross-domain-capable technologies that are coming to browsers will be requiring the use of Access Controls from the get-go, including:

The Access Control specification has been one of the most-rapidly-changing specifications that I've seen. I wrote a demo early this year and have had to update it at least twice since then in order to match the updated APIs - and it appears as if they may have even changed again.

Right now the specification requires that any resource that you wish to make accessible in a cross-domain manner must include an extra header specifying which site(s) are allowed to access it.

If you wish to allow any site to access your resource you would use:

Access-Control-Allow-Origin: *

and if you only wanted one other domain to access it you would use:

Access-Control-Allow-Origin: http://ejohn.org

This is important: It now means that site owners must make a conscious decision to enable cross-domain access of their resources (in contrast to images, stylesheets, and scripts which are always made available cross-domain with no way to disable it).

(There are a number of other headers specified by the Access Control specification, for more fine-grained access.)

There is going to be a lot of confusion and anger regarding this large, fundamental, change to the style of these upcoming APIs: They aren't like the web that we know and love!

The best write-up that I've seen, to date, was by Jonas Sicking of Mozilla on the Ogg Mailing lists. This one section, in particular, is particularly poignant:

Why not use the same policy as for <img>?

Yes, we could definitely do the same for <video> as we have for <img>. But it will come with the same downsides. It will mean that we will have to be much more cautious with how we develop the API for

There are already discussions about API features that we could not allow if we allowed cross-site video without Access-Control (or similar) protection. We would not be allowed to have callbacks for captions where the captions are handed to page javascript to be displayed in the page. This would allow an internet site to get captions from board presentation videos hosted on intranet sites, something that is obviously not acceptable.

We could say that the captions callback would work, but only if the video was loaded from same site, or if had the Access-Control-Allow-Origin:* header set. However this will likely result in random bugs like captions sometimes failing since the developer had perfect hearing and so didn't do a lot of testing with captions. In general accessibility is hard enough to get people to do correct that I'm reluctant to add features that work great as long as you don't take accessibility into account, but where you have to take extra steps to get accessibility to work.

Similar arguments goes for accessing the size of the video file (for example through progress events). We can not allow that to work for cross-site loads unless the site has opted in. This is because we likely won't know that it's actually a video that is being downloaded until after the first progress events have been fired. This means that you could use <video> to measure file sizes for arbitrary files that are otherwise protected by firewalls and/or logins.

If we always restrict usage of <video> to the cases when we know that the video is private data we will be much more free to develop APIs and functionality since we won't have to worry about protecting the data inside it, or deal with error conditions when someone tries to use sensitive APIs from a cross-site loaded video that didn't have Access-Control-Allow-Origin:*.

I recommend that you take the time to read his whole piece as it's worth it to gain a full understanding of the problems at play here (especially related to the <video/> tag).

One thing is clear: Security is being addressed center-stage in the new web APIs. This is going to be good as it'll prevent horrible security bugs going forward while, at the same time, change the landscape of web development in a very fundamental way. The web had its fun but now reality is starting to set in - it's time to get to work.



I'm reminded of the recent release of a crazy hack: transmitting data via URL encoded strings in stylesheets, named CSSHttpRequest. It's an insane technique (in the best possible sense of the word) and well outside the realm of most users. Even though the syntax and technique is different, the security/information-leak implications of this are every-bit as real as those presented by JSONP.

Tags: browsers, w3c

JavaScript iPhone Apps

I've been watching, with interest, developers create new applications for the iPhone. Owning one myself - and being knowledgeable in JavaScript - I've been wondering what options there were for creating downloadable JavaScript applications or the iPhone. In doing some research I found a number of solutions, some simpler than others, some requiring more knowledge of Objective-C than others.

Before looking at the options I should note that given the requirements of the platform if you're really serious about getting in to iPhone development you should learn Objective-C. None of the options appear to provide the full range of functionality that a normally-written application would.

JiggyApp

This was an early entry to the JavaScript iPhone application market - arriving back in 2007. It requires a Jailbroken iPhone (likely running version 1.1 of the Operating System).

JiggyApp provides a full API for developing an application - apparently separate from most of the typical APIs. Arguably, though, the code ends up being relatively usable.

Plugins.load( "UIKit" );

var window = new UIWindow( UIHardware.fullScreenApplicationContentRect );
window.setHidden( false );
window.orderFront();
window.makeKey();
window.backgroundColor = [ 0.8 , 0 , 0, 1 ];

var mainView = new UIScroller();
mainView.contentSize = [ window.bounds[ 2 ] * 2 , window.bounds[ 3 ] * 2 ];
mainView.backgroundColor = [ 0 , 0 , 0 , 0 ];

window.setContentView( mainView );

var hello = new UITextLabel( [ 20 , 20 , window.bounds[ 2 ] - 40 , 100 ] );

hello.text = "Hello World!";
hello.backgroundColor = [ 0 , 0 , 0 , 0.25 ];
hello.setFont( new Font( "Trebuchet MS" , 2 , 46 ) );
hello.color = [ 1 , 1 , 1 , 1 ];
hello.centersHorizontally = true;

mainView.addSubview( hello );

The above snippet was from the Getting Started with Jiggy page.

JSCocoa

JSCocoa is a full bridge that maps Cocoa development into JavaScript (instead of the typical Objective-C/Cocoa mapping). The result ends up working in both OS X and on the iPhone.

It's a pretty-clear port of Objective-C style and mannerisms but with a JavaScript syntax. Note some of the differences:

Objective-C/Cocoa:

[[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 40)];

JSCocoa:

NSButton.instance({ withFrame:NSMakeRect(0, 0, 100, 40) }) 

Right now it seems like JSCocoa is more usable for developing OS X applications but the progress moving forward is certainly promising.

"Applications" in MobileSafari

While it's not, technically, a true iPhone application one option is to adapt your existing web applications to be used in a more application-centric manner.

Apple provides a number of tips for improving the style of your web application. The most important points of which are:

  1. Providing a tray icon for the application (to be used when the user saves it).
  2. Providing a full-screen view of the application (with no MobileSafari toolbars showing).

This will give the full appearance of a regular iPhone application (after using some more styling and setup from iui, or similar).

PhoneGap

The next step to making your iPhone web application more native-like is to tap into some of the underlying native APIs. One recent release that will help is that of PhoneGap.

PhoneGap is an application that exposes a few JavaScript APIs to pages running MobileSafari. Right now this includes Geolocation and access to the Accelerometer.

Geolocation:

getLocation();

function gotLocation(lat,lon){
  document.body.innerHTML = "latitude: " + lat +
    " longitude: " + lon;
}

Accelerometer:

function updateAccel(){
  document.body.innerHTML = "accel: " + accelX + " " + accelY + " " + accelZ;   
  setTimeout(updateAccel, 100);
}

They're also working on access to the camera, sound, and vibration tools of the phone.

WebTouch

The other day "Dr Nic" wrote up an article on how he had used a WebKit instance (along with HTML, CSS, and JavaScript) to render a portion of his iPhone application.

I contacted him about the project and wondered if he'd be willing to provide some of the code that backs it. Written up by his co-worker at Mocra, Anthony Mittaz, the result is called WebTouch.

Right now it's just a zip file of sample code but hopefully it'll be expanded at some point.

It's really simple and gives you a good entry point into the world of hybrid HTML/CSS/JavaScript/Objective-C/Cocoa development. If you've been interested in Objective-C this might make for a good starting point, as well.

Bonus

While this isn't something that you can actually use, I think it's pretty cool. This guy ported my Processing.js work to the iPhone, writing his own Canvas implementation using OpenGL ES hooking in to SpiderMonkey.


There are a lot of options available for the discerning JavaScript developer - the most promising of which is, I think, WebTouch. It's pretty obvious that in order to be able to build the best possible iPhone application you would have to know Objective-C. Having a clear path, paved with JavaScript, to that end result should be any JavaScript developer's goal.

Tags: iphone, javascript, apple

MiniAjax.com For Sale

Last fall I had the opportunity to acquire a great domain - one that was already quite popular within the Ajax realm: MiniAjax.com. It made a splash when it was released in early 2007 - and while it, literally, hasn't been updated since it first came out, it continues to draw a large audience.

It embodies a simple concept: Show nice screenshots and simple descriptions of eye-catching JavaScript/Ajax libraries.

That simple premise has drawn some phenomenal numbers:

Any sort of update to the site would be sure to dramatically increase the, already substantial, traffic. There is nothing "powering" the site at the moment - it's just a static HTML landing page, some images, and a static RSS file.

Unfortunately, after owning the domain for just over a year and doing absolutely nothing with it, I've decided to pass it on. I've already received a couple offers by email but I'm open to more. My email address is: jeresig@gmail.com.

Tags: ajax, domains

Accuracy of JavaScript Time

There were two events recently that made me quite concerned.

First, I was looking through some of the results from the Dromaeo test suite and I noticed a bunch of zero millisecond times being returned from tests. This was quite odd since the tests should've taken, at least, a couple milliseconds to run and getting consistent times of "0" is rather infeasible, especially for non-trivial code.

Second, I was running some performance tests, on Internet Explorer, in the SlickSpeed selector test suite and noticed the result times drastically fluctuating. When trying to figure out if changes that you've made are beneficial, or not, it's incredibly difficult to have the times constantly shifting by 15 - 60ms every page reload.

Both of these cases set me out to do some investigating. All JavaScript performance-measuring tools utilize something like this to measure their results:

var start = (new Date).getTime();
/* Run a test. */
var diff = (new Date).getTime() - start;

The exact syntax differs but the crux of the matter is that they're querying the Date object for the current time, in milliseconds, and finding the difference to get to total run time of the test.

There are a lot of extenuating circumstances that take place every time a piece of code is run. There could be other things running in another thread, maybe another process is consuming more resources - whatever it is it's possible that the total run time of a test could fluctuate. How much that test fluctuates is largely consistent, following somewhere along a normal distribution:

(Performance test suites like SunSpider and Dromaeo use a T-distribution to get a better picture of the distribution of the test times.)

To better understand the results I was getting I built a little tool that runs a number of tests: Running an empty function, looping 10,000 times, querying and looping over a couple thousand divs, and finally looping over and modifying those divs. I ran all of these tests back-t0-back and constructed a histogram of the results.

Here's what the results look like for the major browsers on OS X:

The results here are terrific: There's some clumping around 0ms (with some results spread to 1-4ms - which is to be expected) and a bunch of normal-looking distributions for each of the browsers at around 7ms, 13ms, and 22ms. This is exactly what we should expect, nothing out of the ordinary taking place.

I then fired up VMware Fusion to peek at the browsers running in Windows XP:

Huh. The results are much stranger here. There aren't any, immediately, pretty clumps of results. It looks like Firefox 3 and Chrome both have a nice distribution tucked in there amongst the other results, but it isn't completely obvious. What would happen if we removed those two browsers to see what the distribution looked like?

Wow. And there it is! Internet Explorer 8 (I also tested 6, for good measure, with the same results), Opera, Safari, and WebKit Nightly all bin their results. There is no 'normal distribution' whatsoever. Effectively these browsers are only updating their internal getTime representations every 15 milliseconds. This means that if you attempt to query for an updated time it'll always be rounded down to the last time the timer was updated (which, on average, will have been about 7.5 milliseconds ago).

I was worried that these results were from the virtual machine (I also loaded up Parallels but saw similar results to running VMware) so I just loaded Windows XP proper:

Nope, the results are the same as using the VM.

Let's think about what this means, for a moment:

  1. Any test that takes less than 15ms will always round down to 0ms in these browsers. It becomes impossible to determine how much time the tests are taking with consistently zeroed out results.
  2. The error rate for any test run in these browsers would be huge. If you had a simple test that ran in under 15ms the error rate would be a whopping 50-750%! You would need to have tests running for, at least, 750ms before you could safely reduce the error overhead of the browser to 1%. That's insane, to say the least.

What test suites are affected by this? Nearly all of the major ones. SunSpider, Dromaeo, and SlickSpeed are all predominantly populated by tests that'll be dramatically effected by the error rate presented by these browser timers.

I talked about JavaScript Benchmark Quality before and the conclusion that I came to still holds true: The technique of measuring tests used by SunSpider, Dromaeo, and SlickSpeed does not hold. Currently only a variation of the style utilized by Google's V8 Benchmark will be sufficient in reducing the error (since the tests are only run in aggregate, running for at least 1 second - reducing the error level to less than 1%).

All of this research still left me in a rough place, though. While I now knew why I was getting bad results in Dromaeo I had no solution for getting stable times in Internet Explorer. I did a little digging, tried a couple more solutions, and stumbled across ies4osx. Ies4osx is a copy of Internet Explorer 6 running in Wine, running in X11, on OS X. It works 'ok', although I've been able to get it crash every so often. Disregarding that, though, it's stable enough to do testing on.

Running the numbers on it yielded some fascinating results:

ies4osx provides some surprisingly stable results - we even have something that looks like a normal distribution! This is completely unlike the normal version of IE 6/8 running on Windows. It's pretty obvious that the Wine layer is tapping into some higher-quality timer mechanism and is providing it to IE - giving us a result that is even more accurate than what the browser normally provides.

This is fantastic and it's dramatically changed my personal performance testing of Internet Explorer. While I'm not keen on using anything less than "IE running on XP with no VM" for actual testing - this layer of higher-detailed numbers has become invaluable for testing the quality of specific methods or routines in IE.

In Summary: Testing JavaScript performance on Windows XP (Update: and Vista) is a crapshoot, at best. With the system times constantly being rounded down to the last queried time (each about 15ms apart) the quality of performance results is seriously compromised. Dramatically improved performance test suites are going to be needed in order to filter out these impurities, going forward.

Update: I've put the raw data up on Google Spreadsheets if you're interested in seeing the full breakdown.

Tags: time, date, javascript, browsers

CSS Animations and JavaScript

Apple, and the WebKit team, have recently proposed two different additions to CSS: CSS Transitions and CSS Animations.

The two specifications are confusingly named - and it's hard to tell what the difference is between them at first glance. However, to put it simply: CSS Transitions are easy to use, while CSS Animations are made for programmers.

CSS Transitions

CSS Transitions provide you with the ability to force CSS property changing to occur smoothly over a period of time, rather than immediately and coarsely.

For example if you were to set elem.style.width = "500px";, and its current width was 100px then the element would, normally, jump up to 500px wide. With a CSS Transition it would smoothly move from 100px to 500px - the full CSS required would look something like this:

#elem {
  transition-property: width;
  transition-duration: 1s;
}

This would make it such that any manipulation of that element's width would be done as a smooth transition. Note that no other properties are listed and, thus, are not affected. You can list as many properties as you wish, in a list: "width, heigh, opacity" (for example).

CSS Transitions complement the existing tools that we have for working with CSS from JavaScript. Any changes to a CSS property still work - they just happen much more smoothly.

Of course transitions can also be injected dynamically from JavaScript, like so:

elem.style.transitionProperty = "width";
elem.style.transitionDuration: "1000ms";

Since you can hook in these custom transitions it makes it possible to use them directly from JavaScript and within frameworks. Which leads to the question: Can the core of JavaScript animation frameworks be replaced with CSS Transitions, if they exist?

We had this discussion recently on the jQuery dev list and one user, Jonah, implemented a quick proof of concept to demonstrate how it CSS Transitions would work within jQuery. He also wrote up a stress test to see how it scaled.

Give the stress test a try in WebKit (or on the iPhone, if you have access to one) and you'll definitely note an increase in animation smoothness - especially when a large number of animations are being run.

So why not just add in the CSS Transition code today?

There are a large number deal-breaking gotchas:

  1. You can't stop an animation that's already running.
  2. You get no feedback as to how the animation is running - only an event callback once it has completed.
  3. There's no way to synchronize multiple animations.
  4. There's no way to specify custom easing functions.

The inability to stop an animation is absolutely killer - and a huge requirement for any JavaScript framework that would be looking to adapt this as part of their code base.

That being said, the current transition code does have its place (namely within iPhone development) so I wouldn't be surprised to see a solid jQuery plugin popup that iPhone devs start to use.

CSS Animations

CSS Animations are a second proposal from Apple/WebKit that embodies a much-more-complex way of doing animations. To give you an idea of the level of power that's provided observe this quote from the proposal:

"Many aspects of the animation can be controlled, including how many times the animation iterates, whether or not it alternates between the begin and end values, and whether or not the animation should be running or paused. An animation can also delay its start time."

The ability to pause animations is crucial - and immediately makes CSS Animations a more-viable candidate for use from JavaScript frameworks.

Here's an example of how you would set up a CSS Animation, from the proposal:

div {
  animation-name: 'diagonal-slide';
  animation-duration: 5s;
  animation-iteration-count: 10;
}

@keyframes 'diagonal-slide' {
  from {
    left: 0;
    top: 0;
  }
  to {
    left: 100px;
    top: 100px;
  }
}

CSS Animations also provide a greater number of callbacks (letting you know when an animation has started, every step of the animation, and when it has ended) which can be important for doing animation synchronization.

Although the CSS Animation proposal has a number of things going against it:

  1. Its syntax and usability is far more confusing than that of the, relatively simple, CSS Transitions.
  2. It includes the concept of keyframes - while I'm sure this might be useful for someone I just can't see a large enough benefit for such a large feature.

Honestly, at this point, I'd prefer to see CSS Transitions come around, but with a few additions:

  1. The ability to pause or stop transitions.
  2. Animation start, step, and end callbacks (along with information about how far along the animation is).
  3. The ability to provide a custom JavaScript function which would provide a custom easing function.

#1 and #2 are much more important here - but seeing both of those additions would help to make CSS Transitions actually a viable tool for web developers (not to mention that it would provide the best of both worlds - ease of use for non-framework-using developers and power and control for those using frameworks).

Tags: jquery, javascript, animations, css

Picking Time

It's not often that new user interface conventions are born - or popularized. Even less so within the realm of web development. I'd argue that Sparklines and Lightbox are two of the best examples of UI conventions that were popularized on the web.

Recently Maxime Haineault announced a simple jQuery plugin for inputting a new time of day called jQuery.timepickr.js. Its principles are very similar to jQuery itself: Get users to input the time as simply as possible with as little input as possible.

To achieve this he made a "two click" time picker. The first click is within the time field. This activates the display and allows the user to choose the time - all of which is done by moving the mouse over the times that you desire. The final click is anywhere - filling in the time that was chosen. It's hard to explain, you simply have to try it.

One thing that you'll notice using it is that it's fast. Very fast. I'd argue much faster than clicking into the input area, moving to the keyboard for entering the time, typing the time, then moving back to mouse.

But not only is it faster, but it's also quite intuitive - which is rather rare for something that utilizes a completely new user interface convention.

A nice extra point is that the input is completely styled using the jQuery UI style conventions - which means that you'll be able to customize it completely with the jQuery UI Themeroller.

I love the Themeroller and use it all the time to customize UI controls. It beats the pants off of any other UI customization tool that I've seen. Definitely give it a whirl. Consistently styling JavaScript user interface components can be incredibly annoying, but the Themeroller helps to make it sane - which is just perfect.

Tags: javascript, jquery, ui

Deadly Expandos

If I had to rate my least favorite browser bugs I'd have to put this one near the top. A holdover from the old DOM0 days it's a practice where elements with a given name or ID are added as an expando property to another DOM node.

Here are my two favorite examples of this bug in action:

The first is a simple form that does a search on a site. Additionally a link is provided that, when clicked, fills in a search value and submits the form.

<form action="" method="POST" id="form">
  Search: <input type="text" name="search" id="search"/>
  <input type="submit" id="submit"/>
</form>
<a href="#" id="quick">Quick Search 'JavaScript'</a>
<script>
document.getElementById("quick").onclick = function(){
  document.getElementById("search").value = "JavaScript";
  document.getElementById("form").submit();
};
</script>

Before running the example you can spot the problem with a quick run to the address bar:

javascript:alert(document.getElementById("form").submit)
"[object HTMLInputElement]"

The .submit() method (which is available on all Form elements) is overwritten by the input element of the same name. This ends up being a very common problem - with frameworks using id="submit" as a default in their code.

Worst of all this fails in all browsers (preventing you from accessing the overwritten method).

The second example is even more devious. In this case we're going to loop over all the DOM elements in the page and alert out their contents.

<div id="length">12 stories</div>
<div id="makeup">radiation</div>
<script>
var all = document.getElementsByTagName("*");
for ( var i = 0; i < all.length; i++ ) {
  alert( all[i].innerHTML );
}
</script>

This will work in most browsers - but not Internet Explorer. To understand why we return to the address bar.

javascript:alert(document.getElementsByTagName("*").makeup)
"[object]"
javascript:alert(document.getElementsByTagName("*").length)
"[object]"

Oops. All browsers turn elements with specific IDs into expandos of the returned NodeSet. But Internet Explorer goes a step farther and decides to overwrite the built-in .length property as well, breaking current forms of iterating over the DOM elements.

At least within jQuery you'll see a number of cases where, instead of doing the normal array traversal, we do the following in order to work around the issue:

for ( var i = 0; elems[i]; i++ ) {
  // Do stuff with elems[i]
}

It's a little more obtuse but at least it's guaranteed to work against cases of broken NodeSet iteration.

Garrett Smith has a highly technical write-up on the variety of issues that stem from this form of expansion. In short: No browser is immune from these problems. It's unfortunate that this whole system couldn't just be done away with (to avoid these types of issues in the first place) but legacy pages will likely necessitate their inclusion for many, many, years to come.

Tags: dom, browsers, ie

· « Previous entries

Current Projects

jQuery JavaScript Library

jQuery

Comprehensive DOM, Event, Animation, and Ajax JavaScript Library.

Recent Projects

Pro JavaScript Techniques

JavaScript Book

The best techniques for professional JavaScript. Published by Apress.


Hosting provided by the cool dudes at Engine Yard.