Over the past few months I have been discussing progressive enhancement with some of my clients. For some reason there seem to be real friction about how to safely integrated JavaScript to provide web 2.0 style web design but to ensure that the site provide a similar experience for users with older browsers or with JavaScript disabled.

While this is a bit of a mute point as pretty much consistently over the past 5 years 90% of browsers have JavaScript enabled, it is essential to be aware of progressive enhancement for accessibility reasons.

So here is a quick example using asp.net MVC and jQuery to provide overlay style popups which degrade to a post back model if JavaScript is disabled.

View Code HTML

<!-- Create a link labeled 'show overlay' which uses the 'ShowOverlay' action of the 'home' controller-->
<p><%= Html.ActionLink("Show overlay", "ShowOverlay", "Home")%></p>

<!-- Above the closing body tag include the following code -->

<% if ((bool)ViewData["ShowOverlay"] == true)
   { %>

        <div id="panel">
            <div id="Div1">
                <%= Html.ActionLink("Close", "CloseOverlay", "Home")%>
            </div>
            <div id="content">
                <h2>Overlay header</h2>
                <p>Dulce et decorum est pro patria mori</p>
            </div>
        </div>
        <div id="mask"></div>
<% }%>

View Code - JavaScript

/*On page load bind the 'ShowOverlay' function to click 
  events of the 'show overlay' link and close link. */

var PageReady = function() {

    var ShowOverlay = function(State) {
        if (State.data.show == true) {
            jQuery("body").append('[Panel HTML]);
            jQuery(".close").bind("click", { show: false }, ShowOverlay);
        } else {
            jQuery("#panel").remove();
            jQuery("#mask").remove();
        };
        return false;
    };

    jQuery(".overlay").bind("click", { show: true }, ShowOverlay);
};

jQuery(document).ready(PageReady);

Essentially this is all the code you need to degrade the user experience. If JavaScript isn’t available the click events will never be bound to the link and therefor the page. will degrade to use a post back model.

However we need to create some code in our ‘home’ controller to show or hide the overlay on post back.

Controller - Actions

public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewData["ShowOverlay"] = TempData["ShowOverlay"] == null ? _
                false : TempData["ShowOverlay"];
            return View();
        }

        public ActionResult ShowOverlay()
        {
            TempData["ShowOverlay"] = true;
            return RedirectToAction("Index");
        }

        public ActionResult CloseOverlay()
        {
            TempData["ShowOverlay"] = false;
            return RedirectToAction("Index");
        }
    }
}

There are a couple of thing happening in the his example i’d like to discuss.

When we click ‘ShowOverlay’ the action ShowOverlay is invoked but i don’t want the URL to change to ‘home/showoverlay’ to get round the automatic URL rewriting I set TempData[“ShowOverlay”] to true and return to the ‘index’ action.

Currently the only way i know how to pass data between controller actions is to store the value in TempData, which i can then pass into ViewData in the target controller action to return to the view.

The second in the controller action is a lazy piece of code which sets ViewData[“ShowOverlay”] to false if TempData[‘ShowOverlay’] is null i.e. we never clicked the show or close links.

And that’s it - all you need to know to degrade a web 2.0 style overlay using progressive enhancement.

Take a look at an example page, where you can download the JavaScript and CSS.

Something truly remarkable has happened.

Scott Gu has announced that jQuery is to be shipped with Visual Studio.

"I'm excited today to announce that Microsoft will be shipping jQuery with Visual Studio going forward. We will distribute the jQuery JavaScript library as-is, and will not be forking or changing the source from the main jQuery branch. The files will continue to use and ship under the existing jQuery MIT license.

We will also distribute intellisense-annotated versions that provide great Visual Studio intellisense and help-integration at design-time.

We will also extend Microsoft product support to jQuery beginning later this year, which will enable developers and enterprises to call and open jQuery support cases 24x7 with Microsoft PSS."

Well I'm glad to hear that Microsoft have finally caught on. I personally have been using jQuery as my JavaScript framework of choice since version 1.0.4.

For those of you who haven't heard of jQuery, it's a very lightweight cross-browser framework that easily allows you to manipulate the DOM to create JavaScript transitions etc.

For example, if you wanted to add some error text to a div you would write:

 var ShowJqueryError = function() {
    $('#ErrorMessage ul')
        .append('<li>Please enter your login name</li>')
            .parent()
                .show();
 };

This piece of jQuery will find the UL element which is a child of divErrorMessage and append the li error message to the list.

The quickest way to achieve the same effect with native JavaScript is:

var showError = function() {
    var errorDiv = document.getElementById("ErrorMessage");
    if (errorDiv !== null) {
        var errorList = errorDiv.getElementsByTagName("ul")[0];
        errorList.innerHTML += '<li>Please eneter your login name</li>'
        errorDiv.setAttribute("style","display:block");
    }        
 }

The two main reasons I chose to adopt jQuery as my JavaScript framework of choice were:

  1. It's cross-browser compatible out of the box, which means I don't have to write bucket loads of code to ensure a consistent browser spread.
  2. The selector style language (ID and class named base) is so close to CSS that the overhead of adopting it was low.

An added bonus is that it's quite fun to use too. Making it, for me at least, the best tool for the job.

Microsoft's support for jQuery is monumental, indicating a further shift in their attitude away from a command and conquer mind-set to creating the best development environment, whatever the tools.

Once upon a time the internet was quite a simple little place where every interaction required synchronous transaction between the client and the server.

You entered some information in to a form, pressed a button and the page was sent to a server somewhere for processing. The results were returned to you when the page reloaded.

Life was simple: Post - get response - reload page and move forward on your merry way.

Then JJG decided to blow the whole model apart by creating a cool name for XMLRPC (AJAX).This very simple act changed the 'transactional' nature of the web. It was no longer cool to wait for a the whole page to refresh; people expected portions of web page to load asynchronously.

This new world of website has created a bit of a headache for the security bods because accompanying this new transaction model was a 'hailstorm' of new web services; little code islands a developer can contact to get information on everything from book reviews to weather forecasts to bank statements.

The thing that troubled the security bods now was how to ensure the credentials of the web sites connecting to a web service.

The answer was to enforce a sand box in the browser to prevent websites outside of the domain to connect to the web service. Very cool, except most web developers want to use web services from Amazon etc.

One easy way to get round this was to use Flash as a conduit for the AJAX request. However, Adobe have been very busy updating the Flash Plugin to enforce a tighter security model. This process started by requiring the presences of a crossdomain.xml file on the web service root.

At first, all you were required to do was include the following lines of code:

<cross-domain-policy>
    <allow-access-from domain="*" secure="true|false"> 
</cross-domain-policy>

So, OK, you can provide a domain name or IP address in the domain attribute to only allow access from a specific domain, for closed access.

With the introduction of Flash Player 9, Adobe have started to tighten the security model. Now you are required to specify accepted request headers:

<cross-domain-policy>
    <allow-access-from domain="*" secure="true|false" />
    <allow-http-request-headers-from domain="*" headers="*" secure="true|false" />
</cross-domain-policy>

And with the launch of Flash Player 10 the security is going to be even tighter. The culmination of all these changes is that a lot of Flash applications have the potential to stop working if the crossdomain.xml file hasn't been updated in line with the changes to Flash's security model.