• File: vfm-inlineplayer.js
  • File size: 8.75 KB
  • MIME-type: text/plain
  • Charset: utf-8
/**
 *
 * VFM inline player
 *
 * Requires SoundManager 2 Javascript API.
 *
 */
var VFMinlinePlayer = null;

(function() {

	/* global soundManager, document, window, navigator, event */

	'use strict';

	function InlinePlayer() {
	  var self = this;
	  var pl = this;
	  var sm = soundManager; // soundManager instance
	  var isIE = (navigator.userAgent.match(/msie/i));
	  this.playableClass = 'sm2_firestarter'; // CSS class for forcing a link to be playable (eg. doesn't have .MP3 in it)
	  this.excludeClass = 'sm2-exclude'; // CSS class for ignoring MP3 links
	  this.links = [];
	  this.sounds = [];
	  this.soundsByURL = [];
	  this.indexByURL = [];
	  this.lastSound = null;
	  this.soundCount = 0;

	  this.config = {
	    playNext: true, // stop after one sound, or play through list until end
	    autoPlay: false  // start playing the first sound right away
	  };

	  this.css = {
	    // CSS class names appended to link during various states
	    sDefault: 'sm2_link', // default state
	    sLoading: 'sm2_loading',
	    sPlaying: 'sm2_playing',
	    sPaused: 'sm2_paused'
	  };

	  this.addEventHandler = (typeof window.addEventListener !== 'undefined' ? function(o, evtName, evtHandler) {
	    return o.addEventListener(evtName, evtHandler, false);
	  } : function(o, evtName, evtHandler) {
	    o.attachEvent('on' + evtName, evtHandler);
	  });

	  this.removeEventHandler = (typeof window.removeEventListener !== 'undefined' ? function(o, evtName, evtHandler) {
	    return o.removeEventListener(evtName, evtHandler, false);
	  } : function(o, evtName, evtHandler) {
	    return o.detachEvent('on' + evtName, evtHandler);
	  });

	  this.classContains = function(o, cStr) {
	    return (typeof o.className !== 'undefined' ? o.className.match(new RegExp('(\\s|^)' + cStr + '(\\s|$)')) : false);
	  };

	  this.addClass = function(o, cStr) {
	    if (!o || !cStr || self.classContains(o, cStr)) return;
	    o.className = (o.className ? o.className + ' ' : '') + cStr;
	  };

	  this.removeClass = function(o, cStr) {
	    if (!o || !cStr || !self.classContains(o, cStr)) return;
	    o.className = o.className.replace(new RegExp('( ' + cStr + ')|(' + cStr + ')', 'g'), '');
	  };

	  this.getSoundByURL = function(sURL) {
	    return (typeof self.soundsByURL[sURL] !== 'undefined' ? self.soundsByURL[sURL] : null);
	  };

	  this.isChildOfNode = function(o, sNodeName) {
	    if (!o || !o.parentNode) {
	      return false;
	    }
	    sNodeName = sNodeName.toLowerCase();
	    do {
	      o = o.parentNode;
	    } while (o && o.parentNode && o.nodeName.toLowerCase() !== sNodeName);
	    return (o.nodeName.toLowerCase() === sNodeName ? o : null);
	  };

	  this.events = {

	    // handlers for sound events as they're started/stopped/played
	    play: function() {
			// pl.removeClass(this._data.oLink, this._data.className);
			// this._data.className = pl.css.sPlaying;
			// pl.addClass(this._data.oLink, this._data.className);
			var stoID = '#'+$(this._data.oLink).attr('id');
			$(stoID).removeClass(this._data.className);
			this._data.className = pl.css.sPlaying;
			$(stoID).addClass(this._data.className);

	    },
	    stop: function() {
			// pl.removeClass(this._data.oLink, this._data.className);
			// this._data.className = '';
			var stoID = '#'+$(this._data.oLink).attr('id');
			$(stoID).removeClass(this._data.className);
			this._data.className = '';
	    },
	    pause: function() {


			// pl.removeClass(this._data.oLink, this._data.className);
			// this._data.className = pl.css.sPaused;
			// pl.addClass(this._data.oLink, this._data.className);
			var stoID = '#'+$(this._data.oLink).attr('id');

			$(stoID).removeClass(this._data.className);
			this._data.className = pl.css.sPaused;
			$(stoID).addClass(this._data.className);

	    },
	    resume: function() {
			// pl.removeClass(this._data.oLink, this._data.className);
			// this._data.className = pl.css.sPlaying;
			// pl.addClass(this._data.oLink, this._data.className);
			var stoID = '#'+$(this._data.oLink).attr('id');
			$(stoID).removeClass(this._data.className);
			this._data.className = pl.css.sPlaying;
			$(stoID).addClass(this._data.className);

	    },

	    finish: function() {
	      pl.removeClass(this._data.oLink, this._data.className);
	      this._data.className = '';
	      if (pl.config.playNext) {
	        var nextLink = (pl.indexByURL[this._data.oLink.href] + 1);
	        if (nextLink < pl.links.length) {
	          pl.handleClick({ target: pl.links[nextLink] });
	        }
	      }
	    }

	  };

	  this.stopEvent = function(e) {
	   if (typeof e !== 'undefined' && typeof e.preventDefault !== 'undefined') {
	      e.preventDefault();
	    } else if (typeof event !== 'undefined' && typeof event.returnValue !== 'undefined') {
	      event.returnValue = false;
	    }
	    return false;
	  };

	  this.getTheDamnLink = (isIE) ? function(e) {
	    // I really didn't want to have to do this.
	    return (e && e.target ? e.target : window.event.srcElement);
	  } : function(e) {
	    return e.target;
	  };

	  this.handleClick = function(e) {
	    // a sound link was clicked
	    if (typeof e.button !== 'undefined' && e.button > 1) {
	      // ignore right-click
	      return true;
	    }
	    var o = self.getTheDamnLink(e);

	    if (o.nodeName.toLowerCase() !== 'a') {
	      o = self.isChildOfNode(o, 'a');
	      if (!o) return true;
	    }

	    if (!o.href || (!sm.canPlayLink(o) && !self.classContains(o, self.playableClass)) || self.classContains(o, self.excludeClass)) {
	      return true; // pass-thru for non-MP3/non-links
	    }

	    var soundURL = (o.href);
	    var thisSound = self.getSoundByURL(soundURL);
	    if (thisSound) {
	      // already exists
	      if (thisSound === self.lastSound) {
	        // and was playing (or paused)
	        thisSound.togglePause();
	      } else {
	        // different sound
	        sm._writeDebug('sound different than last sound: ' + self.lastSound.id);
	        if (self.lastSound) {
	          self.stopSound(self.lastSound);
	        }
	        thisSound.togglePause(); // start playing current
	      }
	    } else {
	      // stop last sound
	      if (self.lastSound) {
	        self.stopSound(self.lastSound);
	      }
	      // create sound
	      thisSound = sm.createSound({
	       id: 'inlineMP3Sound' + (self.soundCount++),
	       url: soundURL,
	       onplay: self.events.play,
	       onstop: self.events.stop,
	       onpause: self.events.pause,
	       onresume: self.events.resume,
	       onfinish: self.events.finish,
	       type: (o.type || null),
	       autoLoad: true,
	       stream: true
	      });
	      // tack on some custom data
	      thisSound._data = {
	        oLink: o, // DOM node for reference within SM2 object event handlers
	        className: self.css.sPlaying
	      };
	      self.soundsByURL[soundURL] = thisSound;
	      self.sounds.push(thisSound);
	      thisSound.play();
	    }

	    self.lastSound = thisSound; // reference for next call

	    if (typeof e !== 'undefined' && typeof e.preventDefault !== 'undefined') {
	      e.preventDefault();
	    } else {
	      event.returnValue = false;
	    }
	    return false;
	  };

	  this.stopSound = function(oSound) {
	    soundManager.stop(oSound.id);
	    soundManager.unload(oSound.id);
	  };

	  this.init = function() {

	    sm._writeDebug('VFMinlinePlayer.init()');
	    // Search all .sm2_button calsses
	    // var oLinks = document.getElementsByTagName('a');
	    var oLinks = document.getElementsByClassName('sm2_button');

	    // grab all links, look for .mp3
	    var foundItems = 0;
	    for (var i = 0, j = oLinks.length; i < j; i++) {
	      if ((sm.canPlayLink(oLinks[i]) || self.classContains(oLinks[i], self.playableClass)) && !self.classContains(oLinks[i], self.excludeClass)) {
	        self.addClass(oLinks[i], self.css.sDefault); // add default CSS decoration
	        self.links[foundItems] = (oLinks[i]);
	        self.indexByURL[oLinks[i].href] = foundItems; // hack for indexing
	        foundItems++;
	      }
	    }
	    if (foundItems > 0) {
	      self.addEventHandler(document, 'click', self.handleClick);
	      if (self.config.autoPlay) {
	        self.handleClick({ target: self.links[0], preventDefault: function() {} });
	      }
	    }
	    sm._writeDebug('VFMinlinePlayer.init(): Found ' + foundItems + ' relevant items.');
	  };

	  this.init();
	}

	// in the event any external script references this.
	window.VFMinlinePlayer = VFMinlinePlayer;

	soundManager.setup({
		debugMode: false,
		// use HTML5 audio for MP3/MP4, if available
		preferFlash: false,
		// useFlashBlock: true,
		// path to directory containing SM2 SWF
		url: 'vfm-admin/assets/soundmanager/swf/',
		// optional: enable MPEG-4/AAC support (requires flash 9)
		// flashVersion: 9,
		onready: function() {
			VFMinlinePlayer = new InlinePlayer();
		}
	});
	// Recall VFMinlinePlayer.init() inside app.js, after dataTables drawCallback
}());