Section 6.4. Cross-Platform Development


6.4. Cross-Platform Development

One of the most significant challenges in building web applications is providing an experience that's consistently usable across various platforms. Rails provides tools to help minimize the complexity, but effective cross-platform development still requires awareness and testing.

6.4.1. Realities of Platforms

Platform is a slippery concept. The Web itself is a platforma relatively consistent, standardized environment for developing applications. If only it were so simple!

In reality, each browser has idiosyncrasies, bugs, proprietary features, and slightly different interpretations of the standards. The headaches of cross-platform development are nothing new for experienced web developers. From the earliest days of the Web, no two browsers rendered HTML precisely the same. When Netscape 2 introduced JavaScript and the DOM, web developers enjoyed a brief moment when there was only one implementation; ever since, they've had to content with browsers diverging on another axis. The story repeated itself with CSS, and again with XMLHttpRequest. No doubt the cycle will continue, perhaps with an emerging technology like SVG.

6.4.1.1. What makes a platform

A platform on the Web is more than simply a particular browser brand. It's a particular version of a particular browser, on a particular operating system. In other words, Internet Explorer 5 on Windows is a (very) different platform than Internet Explorer 5 on the Mac (in fact, they share almost no code). And Internet Explorer 6 on Windows is yet another platform, quite different from the other two. On the other hand, in some cases two browsers will actually share most of the same rendering engine. For instance, Firefox, Netscape, and Camino all rely on the Gecko engine, and Safari shares an engine with Konqueror. Given all the possible permutations, building rich Ajax applications that exercise so much of the browser's capabilities can seem daunting.

6.4.1.2. It isn't all bad

Although there are persistent quirks with HTML and CSS rendering across platforms, JavaScript implementations in general are fairly compatible. For Ajax development, the biggest annoyances come not from JavaScript per se, but the DOM. Increasingly, browser makers and web developers recognize the importance of interoperability. As users upgrade, older browsers are slowly becoming less prevalent. And JavaScript frameworks, such as Prototype and script.aculo.us, do much to help unify the platforms' differences.

6.4.1.3. Dealing with platform differences

There are times when you may want to provide some featuresay, a whizzy animated effectbut not every platform can handle it. On one it might look great, on another it might look terrible, and on another it might even crash the browser. Ideally, you'll like to display the effect if the platform is capable, but otherwise simply skip the effect and proceed. There are two basic approaches to the problem. First, you can test for the specific platform by inspecting the user agent string provided by the browser. The advantage here is great specificity: you can find out the precise platform being used. There are a couple of disadvantages, though. One is accuracy: you can't entirely depend on the string to be accurate because some browsers allow the user to intentionally override it. The other problem is that it leads to brittle code. Suppose that you deploy your application, and then a hot new browser is released. It could handle your code, but it won't, since your code doesn't recognize the user agent. The second method for detecting a platform is more direct: test for the existence of objects that support a needed featurein other words, who cares what the browser is; does it support the capabilities you need?

Which approach is best? It all depends on the situation. Prototype and script.aculo.us use both techniques. User-agent detection is often appropriate when you need to compensate for a bug in a particular browser. Here's an example of just that, taken from the Prototype source:

if (navigator.appVersion.match(/\bMSIE\b/))

Capabilities detection, on the other hand, is typically used not to work around a bug, but to determine if a feature is even supported at all. This line from the source of script.aculo.us exemplifies the capabilities detection approach (in this case, used to determine the current scroll bar position, which is implemented differently across browsers):

if (w.document.documentElement && documentElement.scrollTop) {   T = documentElement.scrollTop;   L = documentElement.scrollLeft; } else if (w.document.body) {   T = body.scrollTop;   L = body.scrollLeft; }

Rather than explicitly matching against the browser name, this code checks for the presence of certain objects and proceeds accordingly.

6.4.2. The Rails Way

A good JavaScript library covers a multitude of platform sins, and Prototype and script.aculo.us go a long way in smoothing the wrinkles between platforms. Still, some issues are beyond the libraries' scope. Like Rails in general, Prototype and script.aculo.us are opinionated software. And one of those opinions is that not all legacy browsers are worth supporting.

For example, Netscape 4 (among other browsers) doesn't support the XMLHttpRequest object. But that doesn't mean Ajax is impossible in older browsers. There are other methods available for Ajax-style communication between the client and server, such as dynamically inserting <script> tags and creating hidden IFrames; however, Prototype chooses not to support those alternate Ajax transport methods. In practice, the sacrifice turns out to be small. Users of legacy browsers make a very small, and quickly shrinking, percentage of the market. Adding support for alternate transport would increase the complexity of the code substantially, for very small benefit.

As a Rails developer, I suggest following the example of the framework. Employ the Prototype and script.aculo.us libraries to minimize the effects of platform differences, but don't go overboard. Perfect cross-platform Ajax development is rarely essential.

6.4.2.1. Know your audience

When considering cross-platform development, the first step is to determine which platforms to target. In general, the targeted platforms of Prototype and script.aculo.us are Internet Explorer 6+ on Windows, Firefox 1+, and Safari 1.2+. Whether your application needs to target a smaller or larger audience than that is your decision.

If you're building an internal application that will only ever be used by half a dozen people on a homogeneous platform, you may have the luxury of not worrying about cross-platform issues. It's not uncommon in a corporate environment to have Internet Explorer mandated as the default platform.

On the other end of the spectrum, there are some applications that simply demand to support as many platforms as possible. During the aftermath of the Katrina hurricane in 2005, displaced people could apply for federal aid online from the web site of the Federal Emergency Management Administration (FEMA). Unfortunately, the site employed user-agent detection and restricted access to Internet Explorer 6effectively eliminating all Mac and Linux, and even a large number of Windows, users.

But most projects aren't so simple; instead they live somewhere in the middle. If you are building for a general audience, you'll probably want to test your application with at least IE6+, Firefox, Safari, and perhaps Opera. But ultimately, the decision is one balancing the costs and benefits. Each new platform you target (especially older platforms) adds costs to the projectnot just one-time financial costs, but ongoing ones. Every future change to an application will have a larger testing burden. Larger and more complex code bases will become difficult to maintain and slow to run.

For example, it's increasingly common (especially in Ajax development) to stop supporting Internet Explorer 5, even though it represents a significant (although small and shrinking) percentage of typical users. For many projects, the cost of supporting the platform simply isn't worth the increased audience.

6.4.3. Graceful Degradation and Progressive Enhancement

The terms graceful degradation and progressive enhancement are often heard in web development. They represent two (more or less opposite) ways of approaching the problem of cross-platform web development. Originally the terms were used with regard to CSS development, but they are now used in Ajax development as well.

The concept of graceful degradation is that the Web ought to be first built for the most capable platforms; e.g., those with good CSS support, JavsScript enabled, Flash installed. With that as the foundation, the exceptional cases (i.e., less-capable platforms) could be handled by providing fallback code; e.g., simpler CSS and static images instead of Flash.

The idea of progressive enhancement is to take the reverse approach: focus first on content and structure, and then add layers of enhancement (such as CSS for presentational attributes and JavaScript for behavior attributes). Ideally, the enhancement layers will be loosely coupled to the rest, through external stylesheets and script files.

Creating a link with non-Ajax fallback support is trivial with the link_to_remote helper. For example, here is the standard use of link_to_remote, with no fall-through:

<%= link_to_remote "No fallback", :url => some_url %>

This statement produces the following HTML. Note the # in the href property; if JavaScript is disabled, clicking the link won't have any effect.

<a href="#" onclick="new Ajax.Request('/some_path',  {asynchronous:true, evalScripts:true}); return false;">No fallback</a>

To correct this problem, add a fall-through to the helper, like this:

<%= link_to_remote "With fallback", {:url => some_url}, :href => some_url %>

Now, the generated link has the same URL in the href property as well as the Ajax call:

<a href="/some_path" onclick="new Ajax.Request('/some_path',  {asynchronous:true, evalScripts:true}); return false;">With fallback</a>

Note that in this example clicking the link in a JavaScript-enabled browser would produce a POST request, but if JavaScript were disabled, the request would be made with GET. It is important to remember that when using non-Ajax fall-through, HTTP methods can't be controlled.

While providing fallback support in a link was simple, creating a fall-through for forms is even easier. When using form_remote_tag, no extra work is required:

<%= form_remote_tag :url => some_url %>

If JavaScript is available, the form will be submitted via Ajax; otherwise, it will be submitted traditionally. If the form uses an HTTP method other than POST, it needs to be specified twice to support fall-through:

<%= form_remote_tag :url => some_url, :method => :put,                      :html => { :method => :put } %>

Handling fall-through forms on the server side can be done a couple of ways. First, you can use the request.xml_http_request? method (or its shortcut, request.xhr?). This method returns true if the request's X-Requested-With header contains XMLHttpRequestwhich Prototype includes with every Ajax request. For example:

def handle_fallthrough   if request.xhr?     render :update do |page|       page.alert "You used Ajax"     end   else     render :inline => "You fell through"   end end

If you are using RJS, fall-through can also be handed by the controller with respond_to. This method examines the request's Accept header and delivers the appropriate response. When an Ajax request is created, the header includes text/javascript; when the non-Ajax link is clicked, it doesn't. For example:

def respond_to_test   respond_to do |format|     format.html { render :inline => "You fell through" }     format.js {       render :update do |page|         page.alert "You used Ajax"       end     }   end end

In this example, an Ajaxified request will trigger the JavaScript representation of the responsein this case, an RJS statement. But if JavaScript is disabled in the client, the same request will cause an HTML representation to be delivered instead.




Ajax on Rails
Ajax on Rails
ISBN: 0596527446
EAN: 2147483647
Year: 2006
Pages: 103
Authors: Scott Raymond

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net