Archive for the ‘JQuery’ Category

REST, WEB API And CORS   2 comments

Introduction

Cross Domain AJAX calls (CORS) on desktop browsers require special processing on both the server side and in the way we call AJAX from within the browser. A general overview of CORS can be found hereASP.Net WEB API allows a couple of fairly straight forward ways to implement REST HTTP endpoints with CORS support.  Using the current release build of WEB API we can code our CORS handlers directly or if you want to use the nightly builds of the WEB API you can use an attribute approach.  This post will concentrate on how to write CORS handlers directly since this is the approach I have this in test right now and this approach allows you more flexibility in implementation and improved debugging options.  I will be concentrating on implementation details and assume you have read the background blogs listed above before we start.  I will also be looking at the browser side implementation of the CORS call and some issues with IE browsers (IE 9 in particular).  We are testing with Windows Server 2012 and are using Firefox, Chrome and IE as our test browsers.

Voice from the future: Brock Allen’s great work on CORS, CORS based CORS Attribute support has now been incorporated into Web API 2.  See here and here for details.

So What’s the Problem.

The W3C defines special procedures required if a browser is going to make an AJAX call to a server which is not in the domain of the page which served the page which is making the call (hence Cross Domain).  To enable CORS the server must implement CORS and the browser must make the AJAX call following some conventions.  In the WEB API framework CORS can be implemented on the method or site level.  We will focus on site level CORS in this post.  The WEB API pipeline allows us to hook in message handlers at several places.  The canonical CORS handler, given by the links listed above looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Tracing;

public class CorsHandler : DelegatingHandler
{
const string AccessControlRequestMethod = “Access-Control-Request-Method”;
const string AccessControlRequestHeaders = “Access-Control-Request-Headers”;
const string AccessControlAllowOrigin = “Access-Control-Allow-Origin”;
const string AccessControlAllowMethods = “Access-Control-Allow-Methods”;
const string AccessControlAllowHeaders = “Access-Control-Allow-Headers”;

       protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken )
{
const string Origin = “Origin”;
bool isCorsRequest = request.Headers.Contains( Origin );
bool isPreflightRequest = request.Method == HttpMethod.Options;
if ( isCorsRequest )
{
//HTTP CORS OPTIONS
if ( isPreflightRequest )
{
HttpResponseMessage response = new HttpResponseMessage( HttpStatusCode.OK );
response.Headers.Add( AccessControlAllowOrigin, request.Headers.GetValues( Origin ).First( ) );
                   string accessControlRequestMethod = request.Headers.GetValues( AccessControlRequestMethod ).FirstOrDefault( );
if ( accessControlRequestMethod != null )
{
response.Headers.Add( AccessControlAllowMethods, accessControlRequestMethod );
}

                   string requestedHeaders = string.Join( “, “, request.Headers.GetValues( AccessControlRequestHeaders ) );
if ( !string.IsNullOrEmpty( requestedHeaders ) )
{
response.Headers.Add( AccessControlAllowHeaders, requestedHeaders+”, AICJWT” );
}

                   TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>( );
tcs.SetResult( response );
return tcs.Task;
}
else
{
//HTTP CORS GET
return base.SendAsync( request, cancellationToken ).ContinueWith<HttpResponseMessage>( t =>
{
HttpResponseMessage resp = t.Result;
resp.Headers.Add( AccessControlAllowOrigin, request.Headers.GetValues( Origin ).First( ) );
return resp;
} );
}
}
else
{
//NOT A CORS CALL
return base.SendAsync( request, cancellationToken );
}
}
}

Lets break this down from the simplest part first.  We create a class derived from DelegatingHandler (since we are implementing at the site level).  We hook this handler into the system within the framework generated class WebApiConfig as

public static class WebApiConfig
{
public static void Register( HttpConfiguration config )
{
//your route code here

           );
config.MessageHandlers.Add( new WebAPI.Handler.CorsHandler( ) );

//other handlers are included here.
}
}

If you have other classes based on DelegatingHandler the order in which they are added in WebApiConfig matters.

In the simplest case where we are not making a CORS call we can simply return the handler without action as:

return base.SendAsync( request, cancellationToken );

When the CORS call is made by the browser the caller should include the standard HTTP header: Origin with a value of the calling pages domain.  The canonical code assumes this and uses the presence of this header to detect a CORS call. Hence the code:

const string Origin = “Origin”;
bool isCorsRequest = request.Headers.Contains( Origin );

If the CORS call is not an OPTIONS call (which the canonical code call preFlight) we see the code:

return base.SendAsync( request, cancellationToken ).ContinueWith<HttpResponseMessage>( t =>
{
HttpResponseMessage resp = t.Result;
resp.Headers.Add( AccessControlAllowOrigin, request.Headers.GetValues( Origin ).First( ) );
return resp;
} );

Here the code returns a required header for the Browser: Access-Control-Allow-Origin with the value taken from the Origin Header of the caller.

We could, if we choice to, have set the value to  the wild card value ( * ) but this openness may make your system administrator nervous.  Notice here that nothing in the W3C specification restricts what other Headers the sender can include in the CORS call.  However certain browsers (IE) and certain Javascript packages (jQuery) restrict the call to standard HTTP request Headers.  In our implementation this gave us some problems but more on this later. The browser code (User-Agent), not the user code, will refuse to accept the return if the Origin Header is missing or does not contain either the wild card or the calling page’s domain in the value for the Origin header.

So What is the Rest of the Handler Code Doing?

Following this document from Mozilla.org, the browser making the call may make an optional CORS OPTIONS call (see here for HTTP verbs if this one is new to you).  This preflight call (as the canonical code names it) has asks the server for details about what may be in the CORS request when it is actually call.  Following the Mozilla explanation here is what needs to happen:

    • 1a. The User-Agent, rather than doing the call directly, asks the server, the API, the permission to do the request. It does so with the following headers:
      • Access-Control-Request-Headers, contains the headers the User-Agent want to access.
      • Access-Control-Request-Method contains the method the User-Agent want to access.
    • 1b. The API answers what is authorized:
      • Access-Control-Allow-Origin the origin that’s accepted. Can be * or the domain name.
      • Access-Control-Allow-Methods a list of allowed methods. This can be cached. Note than the request asks permission for one method and the
        server should return a list of accepted methods.
      • Access-Allow-Headers a list of allowed headers, for all of the methods, since this can be cached as well.

In the canonical code given above here is what happens in the CORS OPTIONS call:

//( 0 )create a response object

HttpResponseMessage response = new HttpResponseMessage( HttpStatusCode.OK );
//( 1 ) build the value string for the Access-Control-Allow-Origin header from the ORIGIN header value of the request

response.Headers.Add( AccessControlAllowOrigin, request.Headers.GetValues( Origin ).First( ) );

//( 3 )build the value string for the Access-Control-Request-Headers from the values in the request
string accessControlRequestMethod = request.Headers.GetValues( AccessControlRequestMethod ).FirstOrDefault( );
if ( accessControlRequestMethod != null )
{
response.Headers.Add( AccessControlAllowMethods, accessControlRequestMethod );
}

//( 4 ) build the value string for the Access-Control-Allow-Headers header from the ORIGIN headers value of the request

string requestedHeaders = string.Join( “, “, request.Headers.GetValues( AccessControlRequestHeaders ) );
if ( !string.IsNullOrEmpty( requestedHeaders ) )
{
response.Headers.Add( AccessControlAllowHeaders, requestedHeaders);
}

//( 5 ) interrupt the pipeline and return the response object to the caller.

TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>( );
tcs.SetResult( response );
return tcs.Task;

Please note that we can put whatever we need into the Header values.  For example if we wanted to limit CORS calls to GET request only we could replace ( 3) with the simple:

response.Headers.Add( AccessControlAllowMethods, “GET” );

To allow a specific domain only to make the CORS call we could replace ( 1 ) with:

response.Headers.Add( AccessControlAllowOrigin, “www.special.com” );

In our case we wanted to allow a specific non-standard Header into the CORS request.  We called this Header AICJWT. So we expanded the key line in ( 4 ) to be:

response.Headers.Add( AccessControlAllowHeaders, requestedHeaders+”, AICJWT” );

The reason we added it explicitly here is due to problems in both JQuery and in IE.  Please note again that the CORS OPTIONS call is optional.  At this point in our development we were using the awesome async Framework 4.5  object: System.Net.Http.HttpClient.  This is a get object and very useful during development BUT there is no User-Agent (browser side code) involved.

The Trouble Begins: Browser Side Code

All seemed swell, till the JavaScript coders tried to call into the system.  JQuery forces a CORS OPTIONS call when it detects a Cross Domain AJAX call.  For reasons which remain unclear JQUERY does not include custom headers in the OPTIONS request.  Some people think this is in the W3C spec for CORS but I don’t see it there, do you?  Some folks out there indicate that the user-agent is forcing the OPTIONS request but this is not true.  If we use a direct AJAX call, not using JQUERY we can make our own CORS OPTIONS request or skip the OPTIONS call completely.  Here is the code to make the call using JavaScript in IE:

function callHttpReq() {
var invocation = new XMLHttpRequest();
var url = ‘
http://whereever/api/Concert?Year=1980′;
    var body = ”;

var token = “myspecialstuff”;
function callOtherDomain(){
if(invocation)
{
invocation.open(‘GET’, url, true);
invocation.setRequestHeader(‘AICJWT’, token);
invocation.setRequestHeader(‘Accept’, ‘application/json’);
invocation.onreadystatechange = httpHandler;
invocation.send(body);
}
}
callOtherDomain();

    function httpHandler() {
if(invocation.readyState == 4) {
var jsonObj = $.parseJSON(invocation.responseText);
if(jsonObj.length > 0) {
htmlStr = “<ul>”;
$.each(jsonObj, function(i,row) {
htmlStr += “<li>” + row.Date + ‘—-‘ + ” ” + row.Venue +”</li>”;
});
htmlStr += “</ul>”;
$(“#responeBody”).append(htmlStr);
}
}
}

}

Note we are skipping JQUERY because we require a custom header in our use case.  This step is not necessary if you are NOT using custom headers in the CORS call.  Note also that if you are not using JQUERY you need to use different AJAX object other than IE’s XMLHttpRequest.  If you can use JQUERY there is a masive amount of documentation about how to make AJAX calls and JQUERY will handle CORS and differences between the IE and other AJAX objects automatically.

IE Blues

OK all is good but when we test with IE 8 or 9 we get back the data from the CORS get BUT the user also gets the dialog box:

image

Microsoft tells us the USER can suppress this IN IE8 and IE9 by following this procedure:

You can check your Security Zone level as well as change this setting by going to Tools, Internet Options, and click Security tab. Your Security Zone level will be listed on this screen, by default this is set to Medium-high. To change the setting for your message click Custom Level , locate the Access data sources across domains under the Miscellaneous section and change the setting from Prompt to a desired setting.

image

We do not have this problem in Chrome or Firefox. Live Free or Die.

One Last Server Side Issue

During our testing, using Windows Server 2012 we ran into one additional problem.  Our CORS OPTIONS calls were not getting to our site but where being intercepted by the HTTP Module prior to the site Delegate Handler.  Without getting into it too deeply we needed to modify the web.config for our CORS site and disable WebDAV (don’t ask) and allow OPTIONS for the ExtensionlessUrlHandler.  See here for details.  As far as we know this is a pure Windows 2012 server issue.

Microsoft MVC 3 and CouchDB – Low Level Get Calls   1 comment

I have written elsewhere on couchdb on Windows and using Ruby on Rails to interface to this system.  These posts can be found here:couchdb

Part 0 – REST, Ruby On Rails, CouchDB and Me

Part 1 – Ruby, The Command Line Version

Part 2 – Aptana IDE For Ruby

Part 3 CouchDB Up and Running on Windows

Part 4 – CouchDB, Curl and RUBY

Part 5 – Getting The Data Ready for CouchDB

Part 6 – Getting The Data Into And Out Of CouchDB

Part 7 – JQUERY,JPlayer and HTML5

In my work life I work in a Microsoft shop which for us means Microsoft servers for the back end and (mostly) pure HTML/AJAX frontends.  We are transitioning towards using Microsoft MVC 3 to provide HTTP end points for our AJAX calls.  Here are some notes from my POC work in this area.  My couch data consists of documents describing Grateful Dead concerts stored on the great site Internet Archive, if you have never visited the Internet Archive, please do so.  I back engineered the meta data of IA’s extensive collection of Dead concerts (over 2,000 concert recordings).  Visit the Grateful Dead Archive Home at the Internet Archive here.

CouchDB Documents and Views

I stored the meta data into a local couchdb (running on Windows XP).  The basic document I am storing is a master detail set for the ‘best’ recording for each Dead concert.  The Master part of the document contains the date, venue and other data of the concert and the detail set is an array of meta data on each song preformed during the concert.  As is traditional with couchdb, the documents are represented as JSON strings.  Here is what the document for the UR recording (1965-11-01) found on the IA:

{

“_id”: “1965-11-01”,tumblr_ld4jfoNw7F1qai6ym

“_rev”: “1-6ea272d20d7fc80e51c1ba53a5101ac1”,

“mx”: false,

“pubdate”: “2009-03-14”,

“sb”: true,

“venue”: “various”,

“tracks”: [

{

“uri”: “http://www.archive.org/download/gd1965-11- 01.sbd.bershaw.5417.sbeok.shnf/Acid4_01_vbr.mp3”,

“track”: “01”,

“title”: “Speed Limit”,

“time”: “09:48”

},

{

“uri”: “http://www.archive.org/download/gd1965-11-01.sbd.bershaw.5417.sbeok.shnf/Acid4_02_vbr.mp3&#8221;,

“track”: “02”,

“title”: “Neil Cassidy Raps”,

“time”: “02:19”

}

]

}

Couchdb allow the creation of views which are binary trees with user defined Keys and user defined sub sets of the document data.  If one wanted to return the venue and the tracks for each concert for a given Month and Day (across all years) the view created in couchdb would look like:

“MonthDay”: {

“map”: “function(doc){emit(doc._id.substr(5,2)+doc._id.substr(8,2),[doc.venue , doc.IAKey, doc.tracks ])}”

}

This view allows us to use and HTTP GET to pass in a monthday key (e.g. “1101”) and get back (as a JSON array)

the date (MMDDYY: doc._id.substr(5,2)+doc._id.substr(8,2))

the venue (doc.venue);

the AI URI of the concert (doc.IAKey); and

an array of track data (doc.tracks)

MVC URL Routing Maps

Although we could call couchdb directly from the browser, we normally work through a gateway system for security, so we will build a shim to sit between the browser and couchdb.  This allows us to flow the authentication / authorization stack separately from couchdb’s security system.  In MS MVC we can create a new HTTP endpoint for AJAX calls (our shim) is a very simple manner. Let’s create an endpoint which will look like:

http:\\{our server path}\DeadBase\MonthDay\{month}\{day}

where vacuum_routing

http:\\{our server path}\DeadBase\MonthDay\111

would request month:11 and day:01 concerts.  In MVC we can declare this routing as:

routes.MapRoute(

“MyMonthDay”,

“{controller}/{action}/{month}/{day}”, 

new { controller = “DeadBase”, action = “RestMonthDay”,null} );

Done.  Interestingly in MVC 3 this route definition will accept either the form:

http:\\{our server path}\DeadBase\MonthDay\{month}\{day} ; or

http:\\{our server path}\DeadBase\MonthDay?month=”??”&day=”??”

In the second form,  parameter order does not matter, but case does; quotation marks are optional and need to be dealt with internally by the action method.

either of these call will resolve to the same controller and method.

MVC Controller and Method HandlerMVC

We now need to create the shim which will be the target for the Http Endpoint.  In C# this looks like:

public class DeadBaseController : Controller

public string RestMonthDay( string month, string day )
{
//our shim code goes here

      }

    }

We able to use string as our return type because we will be calling couchdb which returns a string from of JSON by default.  As a side note if we wanted to use MVC 3 to return JSON from a native C# object our controller method takes a different form:

public JsonResult GetStateList()

{

List<ListItem> list = new List<ListItem>() {

new ListItem() { Value = “1”, Text = “VA” },

new ListItem() { Value = “2”, Text = “MD” },

new ListItem() { Value = “3”, Text = “DC” } };

return this.Json(list);

}

Our AJAX call from the browser does not need to know any of these details.  Here is one way to code the call in JavaScript using JQuery:

var url = urlBase + “?” + args;ajax

$.ajax({

url: url,

dataType: ‘json’,

success: okCallBack,

error: nookCallBack

});

function okCallBack(data) {

gdData = data;

//do something useful here

}

function nookCallBack(xhr, ajaxOptions, errorThrown) {

alert(“ErrorText:” + errorThrown + ” ” + “Error Code:” + xhr.status);

}

}

From Handler to CouchDB in C#

Here is the rest of the generic C# code to go from the Handler to CouchDB and back.

Clean the parameters and pass the call to a generic couchDB GET caller:mvc

image

Format the view name and parameter into couchdb format  and pass to the low level couchDB caller:

image

Classic Framework HTTP code to make the HTTP GET and return the results as a string back up the call stack:

image

We could (and did) take our Browser code from the Ruby on Rails project above and with minimum changes call our MVC shim.

Simple clean and fun.

Occupy your mind2

Ruby On Rails, CouchDB and Me – Part 7 – JQUERY,JPlayer and HTML5   Leave a comment

Part 0 – REST, Ruby On Rails, CouchDB and Me

Part 1 – Ruby, The Command Line Version

Part 2 – Aptana IDE For Ruby

Part 3 CouchDB Up and Running on Windows

Part 4 – CouchDB, Curl and RUBY

Part 5 – Getting The Data Ready for CouchDB  

Part 6 – Getting The Data Into And Out Of CouchDB

Part 7 – JQUERY,JPlayer and HTML5

We have two missions in the current post:

  • Getting Our browser side chops together: Using Javascript, DHTML, CSS Level 3, JQUERY against our JSON feed
  • Using JQuery UI and a JQuery UI Plugin: JPlayer to play songs from Internet Archive based on our JSON feed

Recall that our JSON feed provides concert and track data for concerts preformed on an arbitrary date. The top level data of the feed can be visualized like this:

clip_image001

The field total row refers to the total number of records in the database not the number of rows in this feed. The field offset indicates the entry point in the b-tree of the view used for this feed.  Beats me why these would be useful to the calling program!  Following this ‘header’ data we have each concert listed in Key order. The offsets and values are

  • 0: Venue
  • 1: IAKey
  • 2: Array of Track Data

We can visualize the expanded  track data array as:

image Within each offset of the array we have the fields:

  • uri     – The pointer into IA for the mp3 file
  • track – order in the concert of this track
  • title   – track name
  • time  – Track length as MM:SS

We clearly could iterate through these fields and list the concerts and tracks statically on the web page using standard ROR tools but lets be more dynamic.  Let’s first display the concert dates and venues and then display the tracks for a concert  when the user click on a concert without a round trip to the server (and ROR).

Do You Do JAVASCIPT?

Someone once said that Javascript is the only languare that people use without knowning how. Don’t be one of those people.  The cleanest approach to learning Javascript is Crockfords: Javascript:  The Good Parts – Simple, clean Javascript fun.  (Steal This Book Here) Read this even if you ‘know’ Javascript.  If you don’t like to read, try the movie:

JQUERY: It Puts the Dynamic into DHTML.

JQuery is my favorite Javascript library.  Not necessarily the best or the most common.  Just my favorite.  JQuery accomplishes two goals very well:

  • Eliminating (or at least simplifying) DHTML coding differences between all main stream browsers (and most non-mainstream ones);
  • Simplifying and abstracting the operations necessary to drive DHTML via Javascript.

The design of JQUERY leverages the CSS 3 selector syntax so you will need to understand modern CSS selectors.

DHTML was first introduced as a Microsoft extension.  Netscape (remember Netscape?) soon followed with a similar, but not exact DHTML API of its own.  Further each of these browsers also tended to render certain edge cases differently.  And the CSS Level 3 Selectors and HTML5 specifications were coming down the pike. Both CSS3 and HTML5 are now a reality on Chrome, Foxfire and Safari (and some day, real soon) on IE9.  What to do?  John Resiq had an idea and the idea was called JQUERY.  The BASIC idea is to use the CSS Level 3 selectors to selects sets of HTML Tags and then to preform actions on those tags using a common API which would mask the differences between Browsers (and differences between versions of browsers).  Along the way JQUERY attempts to provide features not available in some browsers as long as those features would appear in the (then emergent) HTML5 specification.  Learning JQUERY is difficult only because the API is abstract and their is no BEST text on JQUERY.  Here is how John explains JQUERY:

OK So Lets See Some Code Already!

Iterating The JSON Object In Javascript And Display Using JQUERY

Please refer to our prior post for a description of how the JSON object is delivered to the page via the Rails mark up in our rb file.  Basically we had a single line:

gdData=<%=  @parm  %> ;

Let’s work with this data to display the structure on the browser screen.

We start with two EMPTY HTML tags on our page:

<div id=”concertdiv“>

<lu id=’track’></lu>

We can iterate this object  using javascript as:

ConcertList2(gdData);

where ConcertList2 is defined as:

function ConcertList2(o){
var iaURL=”http://www.archive.org/details/”
for (ndx = o[“rows”].length – 1; ndx !=-1; ndx–) {
var cdate = o[“rows”][ndx].id;
var venue = o[“rows”][ndx][“value”][0];
var itemID=ndx.toString();
var uri= iaURL +o[“rows”][ndx][“value”][1]
var href=”<a id=”href” href=””+uri+”” target=”_BLANK”>”+” – IA -” +””;
var className=’normal’;
if (ndx==0){
className=’hilite’;
}
var item=”

” + cdate + ‘ – ‘ + venue + href + ‘

‘ ;
$(‘#concertdiv’).after(item);
}
}

The javascript variable “item” for a given concert would contain a string of HTML:

<p id=’0’ class=’concert normal’>1969-08-16 – Woodstock Music <a href=http://www.archive.org/details/gd1969-08-16.sbd.gmbfixed.95918.flac16’/>-IA-</p>

Note that this tag contains two class: ‘concert’ and ‘normal’.

The JQuery code line:

$(‘#concertdiv’).after(item);

consists of a selector:

#concertdiv

an action verb:

after

and an argument:

item

The selector uses CSS 3 syntax so it selects the SET of all tags with the ID of ‘concertdiv’.  In our page this is a set of one item.

Iterating through our JSON object will post-pend our items after the tag associated with concertdiv

The results  looks like this on the Browser Page:

1969-08-16 – Woodstock Music – IA –

1980-08-16 – Mississippi River Festival – IA –

1981-08-16 – MacArthur Court – University of Oregon – IA –

1987-08-16 – Town Park – IA –

1991-08-16 – Shoreline Amphitheatre – IA –

Simple, no?

We can iterate and display the tracks as:

TrackList(gdData,ndx);

where TrackList is defined as:

function TrackList(o,ndx){
$(‘li’).remove();
var ndx1=0;
for(ndx1=o[“rows”][ndx][“value”][2].length – 1;ndx1!=-1;ndx1–){
var title=o[“rows”][ndx][“value”][2][ndx1].title;
var time=o[“rows”][ndx][“value”][2][ndx1].time
var track=o[“rows”][ndx][“value”][2][ndx1].track
var uri=o[“rows”][ndx][“value”][2][ndx1].uri
var item=”<li>” + track + ‘ ‘+ time +’ ‘+title+ ‘</li>’;
$(‘#track’).after(item);
}

}

In this case our ‘item’ variable contains a simple HTML string like:

<li>01 03:08 Stage Announcements, Introduction</li?

The results on the browser page for a given concert will look like this:

  • 01 03:08 Stage Announcements, Introduction
  • 02 02:04 Saint Stephen >
  • 03 02:42 Mama Tried >
  • 04 00:38 High Time false start
  • 05 10:28 Stage Banter. Technical Difficulties
  • 06 19:05 Dark Star >
  • 07 06:10 High Time
  • 08 38:32 Turn On Your Lovelight
  • 09 01:52 Applause, Stage AnnouncementsWe can bind these two display routines together with two simple Javascript functions so that when we click on a concert name the page will refresh the track list without a visit back to the web server.First we will use JQUERY to BIND a function to a click event to the concert class:

    function bindClick(){
    $(‘.concert’).click(function() {
    removehilite();
    $(this).toggleClass(‘hilite’,true);
    TrackList(gdData,$(this).attr(‘id’));
    });
    }

  • This bound function uses the pre-defined function ‘removehilite’ to swap

  • function removehilite(){
    $(‘.concert’).toggleClass(‘hilite’,false);
    $(‘.concert’).toggleClass(‘normal’,true);
    }

    and a simple inline CCS definition:

    <style>
    .normal {color:#0B559B;}
    .hilite {color:#FF0000;}
    </style>

    We pull this all together into a simple driver as:

                gdData=<%=  @parm  %> ;
    $(document).ready(function(){
    ConcertList2(gdData);
    bindClick();
    TrackList(gdData,”0″);
    });

    Got it? Good.  Now let’s use a JQUERY UI plug in allow us to play concerts from our browser page.

    JQUERY UI and JQUERY UI Widgets

    As useful as JQUERY is for dynamic web pages let’s go further use the JQuery UI system and the UI Widget: JPlayer,  to allow us to play the mp3 files which reside on Internet Archive.  JQuery UI  is a system built on top of JQUERY to allow the systematic development of UI Widgets which page developers can deploy which minimize un wanted interactions between widgets.  Further the JQuery UI system (and widgets developed within that system) can use a systematic set of theme classes whose color scheme can be generated with a nice tool called ThemeRoller.  I will not have a lot to say about these products in general (except to say they are free and work great) and you will need to visit the links noted in this paragraph to learn more about these tools.

    HTML5 Audio Tag

    HTML5 has introduced a new tag to allow playing audio without using a plug in.  There are some issues still being worked out since there is NOT common agreement yet about whether the standard should universally support MP4 or OGG files universally.  Currently MP3 is supported by all browsers which support HTML5.  Nominally the new tag looks like this:

    <audio controls=”controls”>
    <source src=”horse.mp3″ type=”audio/mp3″ />
    Your browser does not support the audio element.
    </audio>

    Note that the line after the “source” tags is what is rendered if your browser does NOT support HTML5.  If we replace this line with appropriate code to support a plug-in like Flash we have a control which will play well in both HTML5 and HTM4 environments.  We could develop our own solution but I have been working with JPlayer a very nice JQUERY UI widget and will use that for this post.  I like this widget because JPlayer

    • Is a JQuery widget
    • Works with JQuery Themeroller
    • Has a very active user community
    • Displays graphics and video as well as audio tracks

    I developed my final browser page in this series using a modified version of  the  ‘demo 2’ code example which is downloaded along with JPlayer.  Here is the plan:

    Display the Concert list the same way as above (with a few extras for visual appeal).  Prepare the track list in a way similar to that used above but modified to put it in a form that JPlayer can both display the tracklist for us and load the track list into JPlayer (more on this below).  We are going to modify the RoR rb file but not the underlying R0R code.  We will let the browser do the work.  I follow this strategy since our next phase of the project will allow the user to select the date for which concert data is to be displayed and played using AJAX calls in a RESTful manner (more on this next time) rather than round tripping to the server when we want to load a new date (or date range).

    What changes?

    Two new Javascript files:  one for JPlayer and one to handle preparing the track list for JPlayer to consume; and a reference to the themeroller prepared CSS file:

    <link href=”/skin/jplayer.blue.monday.css” rel=”stylesheet” type=”text/css” />

    <script type=”text/// <![CDATA[
    javascript” src=”
    // ]]>http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js“></script>

    <script type=”text/// <![CDATA[
    javascript” src=”
    // ]]>/javascripts/jquery.jplayer.min.js“></script>

    <script type=”text/// <![CDATA[
    javascript” src=”
    // ]]>/javascripts/Playlist.js“></script>

    Playlist.js is the new file I am contributing to the mix the others are JQuery and JPlayer Javascript files.

    Using Themeroller styles I can generate a completely different style for the page and only chang the link reference to the CSS page to change how the page appears.  There are NO embedded style elements on the page.

    Rather than calling the TrackList method I am going to call a new method makePlayList when a concert is selected. This code  looks like this:

    function makePlayList(selected){

    var ndx1=0;

    var tList=new Array();

    for (ndx1 = gdData[“rows”][selected][“value”][2].length – 1; ndx1 != -1; ndx1–) {

    tList[ndx1] = buildTrack(gdData[“rows”][selected][“value”][2][ndx1].track, gdData[“rows”][selected][“value”][2][ndx1].time, gdData[“rows”][selected][“value”][2][ndx1].title, gdData[“rows”][selected][“value”][2][ndx1].uri, gdData[“rows”][selected].id.substring(0, 4));

    }

    return tList;

    }

    In turn, buildTrack looks like:

    var buildTrack=function(num,time,title,ref,cYear){
    var dwnldicon=’pic/download.png’;
    var    nameFMT=”$0     $1     $2<img src=’$4′>“;   
    var track=new Object();
    var name=nameFMT.replace(“$0”,num);
    name=name.replace(“$1”,time);
    name=name.replace(“$2”,title);
    name=name.replace(“$3”,ref);
    name=name.replace(“$4″,dwnldicon);
    track.name=name;
    track.mp3=ref;
    track.poster=”/pic/”+cYear+”.png”;
    return track;
    };

    All of which is returned to JPlayer as:

    mediaPlaylist.playlist = makePlayList(selected);

    Our core Javascript code now looks like:

    var mediaPlayer=null;

    $(document).ready(function(){

    ConcertList2(gdData);  //displays the concert list at the top of the page

    bindClick();  //binds a click event on a concert to loading a new playlist to JPlayer

    mediaPlaylist = new Playlist(“1”,makePlayList(0) , //jump start with the first concert item

    {

    ready: function() {

    mediaPlaylist.displayPlaylist();  //show the playlist

    mediaPlaylist.playlistInit(false);

    },

    ended: function() {

    mediaPlaylist.playlistNext();

    },

    swfPath: “javascripts”,  //jplayer option

    solution: “flash, html”, //jplayer option

    supplied: “mp3” //jplayer option

    });

    });

    Most of our HTML tags are stolen directly from the JPlayer ‘demo 2’ code and mostly deal with setting up the player controls (play, pause, stop, next, etc).

    OK.  The new browser page looks like this (in two Parts):

    Concert Listing Section:

    clip_image001[1]

    I am using icons for hyperlinks to the Internet Archive Grateful Dead Collection: and the smaller icons to link to all recordings for a given date:.   The bottom half of the screen contains the JPlayer and its user controls as well as a user selectable track list:

    image The image is associated with the track selected (there is a JPlayer bug  with the images.  If the same image is associated with two seccesive tracks the second picture will not be displayed – they are working on this). I use the selected Concert text (in this case “Madison Square Garden: 1987-09-16” as a hyperlink to the page containing the  concert recording on Internet Archive.

    These screen captures are from Chrome (Safari and FireFox look the same).  On IE 8 (and lower) HTML5 is not supported and the player reverts to Flash.  The track list on IE8 is not as pretty and is no longer selectable (although the player controls still work):

    image The Sad IE 8 Track Display

    What more can I say?

REST, Ruby On Rails, CouchDB and Me – Part 0   4 comments

Part 0 – This Post

Part 1 – Ruby, The Command Line Version

Part 2 – Aptana IDE For Ruby

Part 3 – CouchDB Up and Running on Windows

Part 4 – CouchDB, Curl and RUBY

Part 5 – Getting The Data Ready for CouchDB

Part 7 – JQUERY,JPlayer and HTML5

The is the first in asmall series of blog posts concerning what is often known as as Open Source Stack for Web Development.  My interests here are in WEB 2.0 development.  We will be working towards using JQUERY and CouchDB to develop REST(ful) Web sites.  I will start with a focus on Rudy and Ruby on Rails (aka RadRails).   However, I will be using free and open source products not on UNIX but on Windows based systems.  Windows runs on fairly cheap hardware (compared to Apples UNIX based platforms) and Windows is much more accessible to new developers than Linux systems.  I will be working here with Windows XP and Windows Vista but you can play alone on Linux and MAC x86.  To get started let’s get together some software and supporting documentation and begin.

Ruby

Version 1.8.7 is the current stable release but since we are interested in using CouchDB I have installed the required ‘edge’ version 1.9.2.  Either of these version will support Ruby on Rails development. Ruby installations are available from several sites. Until you know exactly what you are doing stick with distributions from RubyInstaller.org since these are the baseline Ruby builds which everyone tests against first.  As you get deeper into it (or if  things get a little more sticky)  you try an integrated open stack like the one offered by BitNami.  At some point you may need to install the DevKit.  This is not as heavy as it sounds (but you will need to work with your system paths to get everything in place).  You can get the DevKit here and installation instructions are here.   Note:  the devkit download is now a Windows MSI file but the instructions are still based on a ZIP file extraction, but it all works trust me.  Don’t install either the BitNami Stack or the DevKit until you know you need it.   If you completely new to Ruby a nice introduction can be found in Why’s Poignant Guide To Ruby.

Ruby On Rails

There are a lot of different options to developing Ruby on Rails applications.  If I was not an IDE freak I could use  a simple text editor (I often use the non-open Primal Script) but being new to Ruby on Rails I wanted the support of and IDE.  For this option I selected the Aptana RadRails Development Environment.  This free development environment is based on the open Eclipse editor.  I downloaded the base Aptana IDE (Studio 2) and then added RADRails as a plug in.  These are available in Linux and Mac x86 installers in addition to windows.  You could install only RADRails but then you would have a crippled version of the Aptana product.  We will be noting Ruby on Rails training materials as we move along.

CouchDB

Although we will be using mySQL or SQLlite for some of our development, our real content manager will be the NOSQL couchDB.  This is our real goal in the project – testing the viability  of a REST(ful) HTTP addressable NOSQL database.  This project is from the Apache organization and is available for Linux, MAC x86 and Windows.  It runs as a service on the Windows OS.  The Windows installer is available here.  There is an excellent open source on line couchDB book available here.  For Ruby on Rails we will be using – CouchRest for our Ruby on Rails work with couchdb.  CouchRest is available as a ruby GEM and can be installed on Linux, MAC x86 and Windows versions of Ruby.

JQUERY

Web 2.0 is not possible with out modern, sophisticated JavaScript libraries.  One of the best of these is JQUERY and not surprisingly couchDB ships with a powerful jquery library (couchdb.js) to facilitate browser side manipulation of couchdb data.  For browser work you should be pulling your JQuery from CDN Host.  For use within Ruby for Rails project you will need to add JQUERY  support to your Aptana IDE.  JQuery works with all modern browsers (and even some which not).PacalII

JQuery 2009 & AJAX Experience 2009   Leave a comment


John Resig
Photo By dlr2008 On FlickR.com

JQuery Conference 2009

This conference took place at the Microsoft Research Center in Cambridge Massachusetts on September 12 & 13, 2009. This was a small but intense gathering of JQuery and JQuery UI core developers and assorted developers working on extensions to JQuery (aka plug-ins). There were about 300 participants most of whom were intensely involved with JQuery. Your humble scribe was one of the least informed participants. JQuery has never looked stronger, the development team is cohesive and motivated, and community support is extensive. John Resig’s numbers indicate that something in excess of 35% of all public sites running JavaScript are using JQuery. The library wars are over. Let the framework wars begin. The conference agenda and speakers list and slides can be found by starting: here.

JQuery core is stable at release 1.3.2 but 1.3.3 is coming “real soon now.” The 1.3 versions have focused on optimization, simplification and (proactive) HTML5 support.John’s talk about recent changes to JQuery Internals can be found here. Next year will see moving JQuery core and open source licenses will be transferred to Software Freedom Law Center. Projects for the next year (think version 1.4) include move JQuery\UI infrastructure into JQuery proper. Significant work has been done within JQuery core to streamline and simplify plug-in development via the Widget Factory ($.widget(…)) (thanks to Scott González for this excellent presentation). For the hard core, Paul Irish gave an excellent presentation on JQuery Anti-Patterns. This was bookended by Yehuda Katz’s excellent Best Practices presentation. Aaron Quint was among the Rubists who are advancing the state of JQuery Art. His Sammy.js project attempts to use JQuery to create a browser side MVC/REST framework. John Nunemaker is also working in this basic area and his presentation can be found here.


The Jupiter Room


Photo By dlr2008 On FlickR.com

The walk away component demonstrated at the conference was the work done by Filament Group employees, Todd Parker and Scott Jehl who developed and maintain the new ThemeRoller CSS generator for use with JQuery/UI components. Outstanding Work!

This year’s conference was sold out at 300 participants and was a mind blowing experience. Two days of the sort of “deep dive” Microsoft presenters can only dream of. All this, plus great food and a T-shirt, for one hundred bucks American. We won’t see this sort of thing until the next big thing comes along. Look for the following event during 2010: one virtual (online) developer conference (similar to JQuery 2009 but without the food) and three ‘bigger’ user conferences (London, Los Angles and Boston). Splendid!

The AJAX Experience 2009

This conference took place at the Boston Airport Hilton on September 14 – 16, 2009. What an ugly hotel. Isolated, bad restaurant, overpriced breakfast, cold design, the hotel truly sucks. The conference itself was much better. If at JQuery 2009 we saw significant evidence of what the web will be in the next two years, The AJAX Experience showed us some of what will not happen:

  • The HTML5 specification will be released too late to mater,
  • ES5 will not change the world, or JavaScript.
  • Browser vendors will implement HTML5 using different API’s and approaches,
  • Conflicts between Security and JavaScript will NOT be resolved anytime soon,
  • JSON is not going away but XML ,
  • JavaScript is not going to be changed in any fundamental way,
  • Page Refreshes are not.

The AJAX Experience is a developer driven conference and uniquely includes presenters from both the standards community (W3C, ES5) and major players (Google, Facebook, Yahoo and Microsoft).


Douglas Crockford


Photo By dlr2008 On FlickR.com

The conference is well worth attending to take the pulse of the AJAX/REST world from a developer perspective. It is a conference with does not have an edge to it.  To be fair, this is a conference with a large number of big faces present and the structure of the conference is oriented towards making these faces easily available for one on one’s.  And for that we thank the folks at AJAX Experience.

On the plus side AJAX and REST continue to hold an enduring fascination for web developers looking for the edge. One of the best attended sessions was Facebook’s overview of how AJAX, careful architectural design, client side caching and REST principles, can be brought together into a workable whole. The presentation slides can be found here. This is an important presentation and should be viewed by anyone who want to ‘go all the way’ with AJAX/REST. If nothing else this presentation shows how little native support there is in the current set of browsers for this effort and how clumsy the basic design of JavaScript is when this advanced work is attempted. Please understand dear reader that the best AJAX/REST web site would have only ONE page load all other data exchange and UI work is done on this canvas. The Facebook folks found that after years of effort they still force unnecessary page loads as the only way to clean up events, timers, namespace debris and memory leaks.

Security

For me the most interesting, and the most depressing presentation was the much anticipated panel discussion: Secure Mashups: Getting to Safe Web Plug-ins

The panelists where Marcel Laverdet (Facebook – FBJS), Mike Samuel (Google – Caja), Scott Issacs (Microsoft – The Open Source Web Sandbox) and Douglas Crockford (adSafe). And the discussion was spirited. The goal here is to develop a method by which a web site (think Facebook for example) can accept browser widgets (think ads or user gadgets) from multiple sources and assure “secure cooperation” between all widgets and with the vendor’s (the page owner) HTML and JavaScript code. Although there are nuances between the different approaches and differences in scope, each of these attempts to mash-up ‘security’ follow the same pattern:

  • Clean incoming HTML for “evil parts”
  • Clean incoming JavaScript for “evil parts”
  • Encapsulate the remaining JavaScript code in wrapper functions which ultimately call methods in:
  • The Vendor’s Security Library

The Security Library purpose is to prevent, at run time, manipulation of HTML belonging to other parts of the system and preventing JavaScript exploits. Each solution provides its own definition of what the “evil parts” are, what constitutes ‘secure’ behavior and what are the limits of the security library. None of the solutions currently support JavaScript libraries. Although, Google and Microsoft made noises like they will attempt to bring third party libraries (read JQuery here) into the tent. There was a lot of discussion around this point. My notebook shows that John Resig’s name was mentioned by panelists eight times during this discussion. The overall goals of the projected solutions vary from forcing no code changes (Web Sandbox) to forcing complete re-writes (adSafe is alone is requiring safe widgets to being written exclusively using ONLY the adSafe library). All four projects are in early beta.
Significantly, there were no presentations which addressed Secure Browser OS projects like Microsoft Gazelle or Google’s Chrome OS.

PS: On the UI side of the house Bill Scott gave a delightful presentation on UI methods. For UI designers his presentations (and books) are not be to be missed.

JQuery And AJAX Experience 2009 – The Movie:



Ninja JavaScript: (function(){})()   Leave a comment

dlr2008

We interrupt our discussion of structured JavaScript to discuss John Resig’s Ninja approach to Javascript. John’s approach to JavaScript places the accent on

  • Leveraging JQuery; and
  • Minimizing the use of global variables; Using
    • Anonymous Functions
    • Closures; and nest everything in the anonymous construct:
    • (function(){})()

Let’s define a real world problem:
Make an AJAX call to a data source every ‘X’ milliseconds (for the life of the page) and update the page UI on
each AJAX
return. (Think Stock Ticker for example). We will use the JQuery to manage

  • the AJAX call;
  • bind and signal events; and
  • UI manipulation.

We will use the JavaScript function setInterval to manage when the AJAX call is made. Along the way we will use

some JSON to help us manage passing arguments to the (JQUERY based) AJAX call. This combination will produce
some very tight code with a minimum of global variables (well no global functions if we want to).
First Here is the SHELL of the code, then I will present the final code and then break it down in detail.

SHELL: Based On Model: (function(){})()

(
function(pTarget, timeout, rootID, successEvent, failureEvent) {
$(‘#’ + rootID).bind(failureEvent, function(e, jsObject) {});
$(‘#’ + rootID).bind(successEvent, function(e, jsObject) {});
var _T = window.setInterval( function() {//setInterval anonymous function
$.ajax(//JQUERY AJAX Call
{//JQUERY AJAX Arguments
AJAXOPTIONS : values,//in this format
error: function(XMLHttpRequest, textStatus, errorThrown) {},//AJAX error function option
success: function(data) {}//AJAX success function option
}//end of arguments to $.ajax
)//end of ajax call
}//end setInterval anonymous function
, timeout //call this every ‘timeout’ milliseconds
); //end setInterval
function x(){}//local inner, private functions go here
} //end outer anonymous function
)//end of outer parentheses
(‘DatapageSecure.aspx’, 5, ‘KeepAlive’, ‘AICAJAXSUCCESS’, ‘AICAJAXFAILURE’ );//constructor arguments

Shell Discussion

OK. We start with our old friend:

(function(){})()

This time we will not create a return interface and we will not assign the output of this construction to
a (global) variable (or any other namespace).  We try for a pure Ninja approach.  Get in, set up the functionality and leave behind no trace in the JavaScript namespace.

Brief Overview:

  • (function(arguments) {})(arguments);
    • create an anonymous function (a closure) and pass the values of the constructor arguments to this function
    • Passing the (outer) argument list into the anonymous function preserves these fields (and there values) locally within the function closure
  • Now let’s focus on the anonymous function within the parentheses:
    • (function(arguments) {})(arguments)
  • Within this function we set up two event sinks (bind) to be used by the AJAX calls which will fire (trigger) these events on success or failure
    • $(selector).bind(eventName, function(e,argument) {});
    • These event sinks create anonymous functions (closures) to handle the work preformed when an event is caught.
    • See my notes below on how these functions leverage the properties of these closures.
  • Now we set up the repeating calls to the AJAX function using the (standard) JavaScript setInterval function
    • In abstract form call setInterval call looks like:
    • var t=context.setInterval(function(){},timeperiod);
    • See my notes below for additional comments on the setInterval function
  • Note that I am using another anonymous function as the target for the setInterval call.
    • By doing this the function has access, (if it needs them) to all of the local fields of the enclosing anonymous function
    • We are going to place the JQuery AJAX function within the anonymous function called by setInterval.
  • Take a moment to ponder that at this point we have created four anonymous functions
    • One each for the two bind events;
    • An outer anonymous function; and
    • an additional anonymous function nested inside of that.
  • We are going to nest two additional anonymous functions (closures) within.
    • In symbolic form the JQuery AJAX function takes the form:
    • $.Ajax({JSON FORMATTED Options})
    • See my comments below for additional comments on the $.Ajax function.
    • The JSON Formatted options take the form of optional arguments
      • such as type: ‘GET’ which determine the type of call to make (Get vs Post)
    • For our purposes here the most important options to discuss are the two (optional) functions which are called when the AJAX call returns
      • these are not anonymous functions
      • they have names: success and error
      • Since these functions are expressed in JSON format they act as nested closures in their own right
        • With access to any local fields
          • Local to $.Ajax and to the outer anonymous functions in our example.
    • The essential work of these functions (in this design) is to trigger events we have already defined, and
    • to pass data from the AJAX call to these event sinks
    • In symbolic form the success function looks like:
      • success: function(data) {
      • //do any necessary internal work then call the appropriate event
      • $(selector).trigger(event name, argument);
      • }
  • Ok at this point our work is done and all we need to is add the correct number of brackets and parenthesis
  • to close all of this work.
Take a break then come back and look at the full version of the code and my additional usage notes.
Mississippi River Home - New Orleans

Final Code

01            //local variables added to make this code read more clearly for this blog post
02            var rootID = ‘KeepAlive’; //parameter, major UI DIV ID
03            var targetURL = ‘DatapageSecure.aspx’; //parameter
04            var timeoutInSeconds = 1140; //parameter
05            var AJAXSuccessEvent = ‘AICAJAXSUCCESS’; //EVENTNAME
06            var AJAXFailureEvent = ‘AICAJAXFAILURE’; //EVENTNAME
07          (function(pTarget, timeout, rootID, successEvent, failureEvent) {
08              $(‘#’ + rootID).bind(AJAXFailureEvent, function(e, jsObject) {
09                    var tmp=’ Failure. ‘+new Date() +” HTTPRequest Status: “+jsObject.status;
10                    $(this).find(‘#’ + ‘KeepAliveFalure’).html(tmp);
11              });
12                $(‘#’ + rootID).bind(AJAXSuccessEvent, function(e, jsObject) {
13                    var stmp = ‘User: ‘ + jsObject.UserName + ” Calls: ” + jsObject.Calls ;
14                    $(this).find(‘#’ + ‘KeepAliveChat’).html(stmp);
15                });
16                timeout = timeout * 1000; //upgrade to miliseconds
17                var _Hits = 0;
18                var _T = window.setInterval(
19                            function() {
20                                $.ajax(
21                                            {
22                                                url: pTarget,
23                                                type: ‘GET’,
24                                                data: ”,
25                                                dataType: ‘HTML’,
26                                                timeout: timeout / 2,
27                                                error: function(XMLHttpRequest, textStatus, errorThrown) {
28                                                    window.clearInterval(_T);
29                                                    var x={};
30                                                    x[“status”]=XMLHttpRequest.status;
31                                                    x[“textStatus”]=textStatus;
32                                                    $(‘#’ + rootID).trigger(failureEvent,XMLHttpRequest);
33                                                },
34                                                success: function(data) {
35                                                    _Hits++; //for debuging
36                                                    var jsObject = ExtractData(data);
37                                                    jsObject[“Calls”] = _Hits;
38                                                    jsObject[“TimeStamp”] = new Date();
39                                                    $(‘#’ + rootID).trigger(successEvent, jsObject);
40                                                }
41                                            }//end of arguments to $.ajax
42                                        )//end of ajax call
43                            } //end setInterval anonymous function
44                              , timeout); //end setInterval
45              function ExtractData(data){
46                  //code omited as not relavent to blog post
47                  }//end of local function
48            } //end outer anonymous function
49                )(targetURL, timeoutInSeconds, rootID, AJAXSuccessEvent, AJAXFailureEvent);   //DO IT

Notes On Specific Features

Binding events:

1.     $(‘#’ + rootID).bind(failureEvent, function(e, jsObject) {
2.     var tmp=' Failure. '+tmp1 +" HTTPRequest Status: "+jsObject.status;
3.     $(this).find('#KeepAliveFalure').html(tmp);
4.     });

Line 1: JQuery is built up using selectors which simulate CSS selectors. Here $(‘#’+rootID) seeks within the DOM all
HTML elements with an ID equal to the value of the variable ‘rootID’. The “bind” JQuery verb binds an event (here a
custom event with a name contained in the variable ‘failureEvent’) with an anonymous function:
function(e, jsObject){}. JQuery normalizes the binding of events between major browsers so we do not need to
concern our code with what vendors agent we are running within. The bind verb will pass two arguments from
the signal event: ‘e’ which is the standard event object and any optional arguments provided by the signaler. In this
case the second argument is a JavaScript object with a (user defined) set of properties.
Line 3: This is a very nice example of terse JQuery script. The selector: $(this) refers to whatever was defined as the
selector in Line 1. The ‘find’ verb applies a selector (in this case looking for the ID ‘KeepAliveFalure) within the children
of the primary selector (in this case ‘this’). The ‘ html’ verb replaces the innerHTML of the find selector with the value of the variable ‘tmp’.
This is tight, no?

Calling AJAX with JQUERY


JQuery defines several ways to make AJAX calls I am using one of these ( $.ajax) here. The structure of this call is:
Line 1. $.ajax(
Line 2. {}
Line 3. );
Line 2 is of course the meat it is a JSON formatted argument list containing, in our case:
Line 1. url: pTarget, //the url to call
Line 2. type: 'GET', //call type
Line 3. data: '', //Query String Arguments to pass to the target URL
Line 4. dataType: 'HTML', //return datatype
Line 5. timeout: timeout / 2,//how long to wait for a response
Line 6. error: function(XMLHttpRequest, textStatus, errorThrown) {...},
Line 7. success: function(data) {...}
Note: Line 4 defines the type of data returned from the AJAX call. In this case use HTML since we do not want any post
Processing of the data to occur . We could use the key word ‘JSON’ if we expect a JSON response and we want
JQUERY to hydrate the JSON string back into a JavaScript object prior to passing the data to the success anonymous function.
Line 6 defines an anonymous function to be called when the call times out or if the call returns an HTTP code => 400.
JQuery defines and handles the three arguments passed to the error function.
Line 7 defines an anonymous function to be called on a successful AJAX call and the argument ‘data’ is the
actual text returned (subject to the constraint imposed in Line 4).

Processing the AJAX Return

Let’s look at the anonymous success function (given as Line 6 above). In the actual code example we are using
Line 1. success: function(data) {
Line 2. _Hits++; //for debuging
Line 3. var jsObject = ExtractData(data)
Line 4. jsObject["Calls"] = _Hits;
Line 5. jsObject["TimeStamp"] = new Date();
Line 6. $('#' + rootID).trigger(successEvent, jsObject);
Line 8. }
Line 2. ” _Hits” is a local variable defined in the full code example. This is a local variable. Local to the closure of the outer
Anonymous function. It is visible there and to both the success and error anonymous functions but is not visible globally.
I am using it here as a simple debugging device to count the number of the AJAX calls made.

Line 3 takes us Outside of the scope of the current blog and is used to extract some of the data from the return stream and
to create a Javascript object to hold that data. In the working code it is defined as a local non-anonymous function The code has been omitted from our example code since this takes us way outside of the scope of this blog.
Lines 4 and 5 define additional properties of jsObject (used for debugging in our example).
Finally, in Line 6, we use JQUERY to trigger an event and pass the locally created JavaScript object to it. Some things to note about this
Very terse line of code:

  • $(‘#’+rootID) The JQuery selector for the DOM element to trigger to event against. AKA the event sink. See the section on Binding Event Above.
  • .trigger The JQuery trigger event verb, this is a browser neutral event trigger
  • successEvent A variable which contains the name of the event being triggered.
  • jsObject The JavaScript Object containing the local data to pass to the event sink.

Setting Up the setInterval Function Call

The JavaScript function “setInterval” controls calling a function repeatedly every “X” milliseconds. Its form is:
var _T = owner.setInterval(function(){},timeout);
where:
owner is the context which ‘owns’ the setInterval
_T is the handle for the setInterval.
Function(){} is the anonymous function to call; and
Timeout is the milliseconds between invocations of the anonymous function.
Once launched, setInterval will continue to be called for the life of the page or until a call is made to cancel the setInterval cycle:
owner.clearInterval(_T);
Note: the handle (_T here) returned by the setInterval function is a simple number if we have
Var _T a.setInterval(function(){},timeout);
and
b.clearInterval(_T);
the original setInterval will not be cleared and no error is generated with the call.
One could write
var _T = setInterval(function(){},timeout);
and
clearInterval(_T);
and HOPE that the context is the same for each call. But better to assure success by specifying the context of both
the setInterval and the clearInterval call. In our example code we assign each call to the “window” context:
var _T = window.setInterval(function(){},timeout);
and
window.clearInterval(_T);
so our context and intent is clear.

So What’s The Down Side?

We get some very compact code here with NO side effects and a very minimal global namespace impact when we use John’s Ninja approach. The downside is the syntax is very complex and very fragile. A typo anywhere in the code is likely to get you a general syntax error message, generally in the last line of the (function(){})(); construct. Not very helpful that. We are mixing standard JavaScript syntax with JSON syntax together and it is easy to get lost without good planning. Personally we never make syntax errors, but for others this may be a problem! An additional downside is debugging anonymous functions by setting break points in your running code will not work. I work in a team environment and when I move this solution into production, I will likely break out some of the anonymous functions into normal (inner functions) to make it easier for other team members see the intent of the code, to ease making code changes and to simplify debugging. If I was shipping code to be worked on only by myself or by a (very) limited sized team I would leave it just as it and watch it fly.

Home
%d bloggers like this: