Shifting HTML code design to App Architectures – a demo.

This entry is part 1 of 2 in the series DynamicMediaDemo

For the last nine months I’ve been focused on the potential of HTML5 as an application development platform. When I first started talking about HTML5 for building apps, it seemed like very few people really “got” what it meant. Rather that HTML simply being something that gets spewed out by your server. HTML5 and it’s companion technologies, themselves became a platform.

In fairness, there were lots of developers that were starting to add “richness” to their HTML / client side work, predicated in no small part on the change in web development perspective that was catalyzed by the whole “Ajax” phenomenon.

More and more people seem to be embracing what the HTML5 wave of technologies could mean to development of all sorts. I say “could” mean because I believe HTML5 is in its “usable” infancy.

I recently asked my readers how important they think “off-line” support for HTML5 apps is.

The answers were great and showed how far developers as a group have advanced their perspective on where HTML development is going.

During my years at Microsoft I spent much time helping developers change the way that they looked at ASP.NET based web development by authoring patterns and practices that were focused on developing web applications that used real client / server interactions. With the advances Mozilla is making with it’s HTML5 Apps platform and the Firefox OS, it seems like a good time to apply that same kind of guidance to apps focused patterns and architectures.

So here is the beginning of a demo project for apps.

Understand that this app is a learning project and it’s focused on MozApps and Firefox OS apps. That means I’m writing the sample specificity for Gecko based run-times. If you were writing a cross browser app supporting Gecko, Webkit and Microsoft browsers you would have to do some feature detection and code against the features that are available in your browser. Perhaps I’ll write some samples to demonstrate that in the near future but for now I’ll focus on apps for one of the Gecko run-times.

Here is what the user interface of the demo looks like. I’ve only implemented the first feature for demonstrating “sometimes connected” architecture, but we’ll build on this app over the coming weeks.

Dynamic Media Demo

You can run the page here http://www.misfitgeek.com/demo/mediaget/ – just remember that this demo targets the Gecko run-time so if you’re not using a current version of Firefox you’re sort of on your own.

This page will play video files but what is a bit different about this page than you would have found in “old school” HTML page design is that the page contains a single media element and that HTML video tag has no video source specified.

This might be a common scenario in an HTML5 app (Think YouTube or Netflix). One would not, really could not, embed all the videos that the end user “might” want to watch.

In this case, we will not download any videos by default when the page is loaded, we’ll wait until the user selects a video to watch and then DYNAMICALLY fetch that video. When it was been retrieved we’ll play it. In our sample the user can choose from three videos but that number could be 100s of videos since none of the choices are actually downloaded until the user selects a video to watch.

At the top of the UI the user has three videos that they can choose from to watch.


</pre>
<h3>Videos Available For Viewing</h3>
<div class="gallery">
<div class="photo"><a href="javascript:loadMedia('demo-vid.webm');">
 <img src="img/foto.jpg" alt="" width="155" height="110" />
 </a>

 <a href="javascript:loadMedia('demo-vid.webm');">Fetch Video 1</a></div>
<div class="photo"><a href="javascript:loadMedia('demo-vid-2.webm');">
 <img src="img/foto.jpg" alt="" width="155" height="110" />
 </a>

 <a href="javascript:loadMedia('demo-vid-2.webm');">Fetch Video 2</a></div>
<div class="photo"><a href="javascript:loadMedia('demo-vid.webm');">
 <img src="img/foto.jpg" alt="" width="155" height="110" />
 </a>

 <a href="javascript:loadMedia('demo-vid.webm');">Fetch Video 3</a></div>
<div class="cleaner"></div>
</div>
<pre>

Notice that clicking on each image causes a bit of JavaScript to execute. (Yes I know there are other, and perhaps better ways to do this, especially if you are a jQuery aficionado but this is a straight forward method for learning simplicity.)

Here is what the loadMedia() method looks like.


function loadMedia(mediaFile) {
   document.getElementById("dlstatus-container").style.display="block";
   var xhr = new XMLHttpRequest();
   var mediaFileLocation = "media/" + mediaFile;
   xhr.open("GET", mediaFileLocation, true);
   xhr.responseType = "blob";      // Set the responseType to blob
   xhr.addEventListener("load", function () {
      if (xhr.status === 200) {
		 document.getElementById("dlstatus-container").style.display="none";
		 document.getElementById("player-container").style.display="block";
         blob = xhr.response;         
         var mediaFile = blob;
         var URL = window.URL || window.webkitURL;
         var mediaURL = URL.createObjectURL(mediaFile);
         var mediaElement = document.getElementById("media-element");
         mediaElement.setAttribute("src", mediaURL);
      }
      else {
		  // Download failed. Stop Download Status.
		  // ToDo: Add Error Handeling.
		  document.getElementById("dlstatus-container").style.display="none";
      }
   }, false);
   
   xhr.send();
}


The function catches a file name to be retrieved and then does an XmlHttpRequest call to fetch the file from the media directory on the server. Not that this method runs on the same thread as the user interface. In a later version we will use “HTML5 Web Workers” to cue the video downloads without blocking the user interface.

The first thing that loadMedia() does is show a hidden div named dlstatus-container. This div contains an animated gif file that indicates the file is being downloaded.


   <div id="dlstatus-container" style="display:none">
      <h2>Downloading Video .......</h2>
      <img src="img/dl-status.gif" alt=""  />
       </br /><br /><hr /><br />
   </div>

I use a free on line tool at AjaxLoad.info to generate the “working” image.

Line 7 in the listing above defines an event listener and line 8 tests to make sure the download was a success.

After that we turn off the status indicator div and the display the div that contains the HTML5 video element.


   <div id="player-container" style="display:none">
      <h2>Media Fetch</h2>
      <video id="media-element" controls="controls" 
             width="520" height="340" autoplay="autoplay">
      </video>
      </br /><br /><br /><hr /><br />
    </div>

Note that autoplay on the video element is on, so that when the video element’s source attribute is populated with the downloaded video on line 16 of the loadMedia() method, the video begins to play.

You can test the feature here – http://www.misfitgeek.com/demo/mediaget/

Note the behaviors.

  • If you start playing one video and then select another video, the first video will continue to play until your second choice is ready.
  • If you play one video, then play a second video, then go back to the fist video you watched – it will begin playing immediately when you select it, since it has been automatically cached by the run-time when it was downloaded.

A simple but meaningful feature.

Stay tuned. We’ll start adding features in the next post in this series.


A First In – First Out JavaScript Queue

This entry is part 2 of 2 in the series DynamicMediaDemo

I recently started building a demo to highlight application design practices that leverage HTML5 features to deliver an “app” experience. The model for this particular demo was that of a video portal and the first step was to to make independent XmlHttpRequest calls to fetch the videos on demand.

Here is where we want to ed up with this app.

  1. The content gets updated with LINKS to new videos.
  2. The user selects videos to be downloaded.
  3. The videos are downloaded in the background without effecting the user interface performance.
  4. The user can select as many videos as they want for download and they will be queued up.
  5. The videos will be stored locally for use later.
  6. The user will be warned if they try to close the app when files are still downloading.

I posted a simple demo of using Web Workers here.

In this post we’ll look at how to stack all of the user’s video download requests in a JavaScript queue object. This is necessary because the user can click on links to videos faster than they can be downloaded. In our previous example if the user clicks on a video to download and then clicks on a different video before the first one has finished downloading – that first video download is simply abandoned and the second video download begins. We need to queue them so that all the videos selected will be asynchronously downloaded in the background.

Lets first look at a simple JavaScript Queue – then we will look at the better way to do solve the problem.

In JavaScript the array is a pretty flexible construct.

To create an instance of an array :


var queue = new Array();

An array in JavaScript can contain any type of data (more on this in a minute) and each item in an array does not have to be of the same type as the others.

There are two sets of ways to add and remove items from an array.

One set works against the beginning of an array and the other works against the bottom.


shift() – Removes the first element of an array, and returns that element
unshift() – Adds new elements to the beginning of an array, and returns the new length


pop() – Removes the last element of an array, and returns that element
push() – Adds new elements to the end of an array, and returns the new length


In order to process a FiFo (First In – First Out) queue, we’ll need to use one of each.

We’ll use push() to add an additional item to the top of the queue and we’ll use shift() to retrieve (and remove)  an item from the bottom of the queue and move all the remaining items down to fill in for the removed item.

Given the following HTML :



<!doctype html>  
<html>  
  <head>  
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  
    <script src="js/code.js"></script>
    <script type="text/javascript">

      function doStackAdd() {
        var inputValue = document.getElementById('txtInput').value;
        if(inputValue) {
          stackAdd(inputValue);
          document.getElementById('txtInput').value = "";
        }
      }
		
      function doStackGet() {
        var returnValue = stackGet();
        document.getElementById('stackResult').innerHTML = returnValue;
      }
    </script>   
    <title>JavaScript FIFO - Worker</title>  
  </head>  
  <body>
    <center>
      <h3>JavaScript Simple FiFo Queue</h3>
      <div id="mainDiv" style="background-color: silver; 
                        width:410px; padding: 20px; text-align: left;">
        Input : <input type="text" id="txtInput" value="">
        <button onclick="doStackAdd()">Add to Stack</button> 
        <br /><br />
        <button onclick="doStackGet()">Get from Stack</button> >>>
        &nbsp;&nbsp;
        <span id="stackResult"></span>
      </div>	           
     </center>
   </body>  
</html>

Which renders the following page…


Note that the button click() event handlers call JavaScript functions defined in the code.js file.


//---------------------------------------------------------------------+
// Code for SIMPLE FiFo Queue (Stack)
//---------------------------------------------------------------------+
var queue = new Array();

function stackAdd(valueToAdd) {

	queue.push(valueToAdd);
}

function stackGet() {
	var retrievedQueueValue = queue.shift();
	if(retrievedQueueValue) {
	   return retrievedQueueValue;
    }
    else {
	   return "Queue is empty.";
	}
}

So, when we add a few items to the queue by entering text and clicking the “add” button…….





We then have a few (three) items on the stack.

Now if we start clicking on he “Get from Stack” button we can see that the items we entered come off the stack in the order we put them on.





When the queue is empty, we report that the queue is empty.



This works, but only allows us to push “single” values onto the stack.

Remember that our use-case for this is to put videos that we want to download into a queue.

Practically speaking, we will want to attach some information to the video to be downloaded. AT a minimum a name for the video, maybe a description.

At first you may consider a JavaScript Hash, also known as an associative array.

But this data structure is not very well suited for this type of usage.

With an Associative Array you store Key / Value Pairs. The key is not really part of the data, it’s the index into that element of an array. As such you use the value of the key to retrieve the item you want.

It makes more sense for us to define a custom type ( a video for download type) and then work with an array of object of that type.

So for the given markup….



<!doctype html>  
<html>  
  <head>  
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  
    <script src="js/code.js"></script>
    <script type="text/javascript">
      
      function doObjArrayAdd() {
        var inputName = document.getElementById('txtInputName').value;
        var inputURL = document.getElementById('txtInputURL').value;
        var inputDesc = document.getElementById('txtInputDesc').value;	
 
        if(inputName && inputURL && inputDesc) {
          objArrayAdd(inputName, inputURL, inputDesc);
          document.getElementById('txtInputName').value = "";
          document.getElementById('txtInputURL').value = "";
          document.getElementById('txtInputDesc').value = "";
         }
       }

      function doObjArrayGet() {
        var returnValue = objArrayGet();
        document.getElementById('vidoObjectResult').innerHTML = returnValue;
      }
    </script>   
    <title>JavaScript FIFO - Worker</title>  
  </head>  
  <body>
    <center>
      <h3>JavaScript FiFo Queue - Object Array</h3>
      <div id="mainDiv" style="background-color: silver; 
                        width:500px; padding: 20px; text-align: left;">
        Name : 
        <input type="text" id="txtInputName" value=""  style="width:300px;">
        <br />
        &nbsp;&nbsp;&nbsp;URL : 
        <input type="text" id="txtInputURL" value="" style="width:300px;">
        <br /><br />
        Desctiption :  
        <textarea id="txtInputDesc" rows="8" cols="68"></textarea> 
        <button onclick="doObjArrayAdd()">Add to Collection</button> 
        <br /><br />
        <button onclick="doObjArrayGet()">Get from Collection</button>
        <br /><br />
        <span id="vidoObjectResult">&nbsp;</span>
      </div>		           
     </center>
   </body>  
</html>

Then in our button click() event handler we will define our custom type and create an array of object instances from our user defined type.


//---------------------------------------------------------------------+
// Code for Object  FiFo Queue 
//---------------------------------------------------------------------+
function VideoObject(name, url, desc)
{
this.name = name;
this.url = url;
this.desc = desc;
} 

var VideoObjectArray = new Array();

function objArrayAdd(nameToAdd, urlToAdd, descToAdd) {
	
   newVideo = new VideoObject(nameToAdd, urlToAdd, descToAdd);  
   VideoObjectArray.push(newVideo);
}

function objArrayGet() {
   var retrievedVideoObject = new VideoObject();
   retrievedVideoObject = VideoObjectArray.shift(); 
	
   if(retrievedVideoObject) {
      return retrievedVideoObject.name + ":" + 
             retrievedVideoObject.url + ":" + retrievedVideoObject.desc;
   }
   else {
      return "VideoObjectArray is empty.";
   }
}

Note that when we use shift() to retrieve an item from our array we can’t don’t pass that object instance to the calling method. It would work here in this example, but when we move this code to a Web Worker, this code will be called via a Web Worker message and the calling code will not have access to the type defined in the referenced .js file.

Now when we run the page and add an item to the queue…..



And then click on the button to retrieve the object….



So there we have an implemented FiFo Object Queue in JavaScript.

What’s next ?

  • Store the videos locally.
  • Implement AppCache to work off line
  • Move the downloading into a web worker
  • Update the UI to destinguish between, available, downloading, and downloaded videos
  • Prevent the user from closing the app while files are still downloading.


** You can download the source code for the above example HERE.