Times are a changin’ and my department knew that we needed something more than the Flash based players we had been using for quite some time. One of the bigger forces that drove us to need an HTML 5 player was the rise in ‘iDevices’, such as the iPhone and iPad by Apple. The charge was given to me to create a player that would work nice with the existing infrastructure and able to deliver media in both video and audio formats.
I chose to use jPlayer, a jQuery plugin. The reasons that I chose it was because it could work with both video and audio, it is skinable, and had hooks that I could use to my advantage. I then wrote a wrapper around jPlayer that added the missing functionality that was necessary for my department, with included keyboard controls, links to transcripts, and captioning. To help keep things consistent, the HTML 5 player uses the same transcripts and captions that the Flash player does.
I first created created a mock-up of the controls bar in Photoshop. The player was inspired by a custom player audio skin at Premium Pixels. I then took the design and ran with it to make it work for our needs. Other than the play and speaker icons, the icons where created for this purpose.
I then wrote the HTML, CSS, and JavaScript to implement the mock-up. I then created a sprite file that allowed all of the elements to be located on one PNG file. This helps avoid any loading flash with elements that change state when rolled over.
The final results look like the following:
Here is a snippet of the JavaScript wrapper used to control the player:
// create a self extrating function to run everything in and keep all of my code out of the global scope // bring in the global window object by default (function(window,undefined){ var document = window.document; // get the global document object. var $ = window.$; // get the jQuery object if(window.vp5 == undefined) { // vp5 has not been defined yet var vp5 = {}; // the vp5 player namespace } else { // we have already loaded this script, lets not load and run it again. return true; } vp5.defaults = { // default options for our players playerRoot: '/~d-ctel/mediaPlayerTest/', fileRoot: this.mediaRoot + 'scripts/JavaScript/', mediaRoot: '/~d-ctel/filesForMedia/', coursesFolder: 'courses/', captionXmlName: 'captions.xml', pNumber: 1 // for unique number for the players }; vp5.mediaTags = new Array(); // make mediaTags an array to store our players, kinda like a catalog // create our media player object to store our stuff in var mp5 = function() { //var me = this; //this._init(); //alert(me); }; // this fires when jQuery is ready $(document).ready(function(){ $('.mediaContainer_1').each(function(index, element) { vp5.mediaTags[vp5.defaults.pNumber] = new mp5; // each player gets its a mp5 object so we can build its own jplayer object. The array allows us to catalog each player on the page vp5.mediaTags[vp5.defaults.pNumber].pNumber = vp5.defaults.pNumber; // capture the player number for this perticular player vp5.mediaTags[vp5.defaults.pNumber].href = location.pathname; // the current url. This will possible change if/when multiple players are implemented on a page, or if the player is embeded //alert($(this).find('div').is('.video-jp-box')); if($(this).find('div').is('.video-jp-box')) { // we have a video tag vp5.mediaTags[vp5.defaults.pNumber].findMediaInfo(this, 'video'); vp5.mediaTags[vp5.defaults.pNumber].buildVideoInterface(); // build the jPlayer video user interface html } else if($(this).find('div').is('.audio-jp-box')) { // we have an audio tag vp5.mediaTags[vp5.defaults.pNumber].findMediaInfo(this, 'audio'); vp5.mediaTags[vp5.defaults.pNumber].buildAudioInterface(); // build the jPlayer audio user interface html } vp5.mediaTags[vp5.defaults.pNumber]._init(); // initialize the current player object so the events will work vp5.defaults.pNumber++; // incrament pNumber by one }); /***** Generic Events *****/ // enables using the keyboard to control the players // we have to find which player was in focus and generated the event, so we can pass the event to it $('.mediaContainer_1').keydown(function(event) { //vp5.keyEvents(event); var nodeName = event.target.nodeName; var mediaContainerId = $(nodeName + ' div[id^="jp_container_"]').attr('id'); var num = mediaContainerId.substr(mediaContainerId.lastIndexOf('_') + 1); vp5.mediaTags[num].keyEvents(event); }); // this helps the user understand which player has focus $('.mediaAnchor').focus(function(event) { $(this).addClass('activePlayer'); }).blur(function(event){ $(this).removeClass('activePlayer'); }); /***** End Generic Events *****/ });