/**
*
* 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
}());