/** * SoundManager 2 Demo: Play MP3 links via button * ---------------------------------------------- * * http://schillmania.com/projects/soundmanager2/ * * A simple demo making MP3s playable "inline" * and easily styled/customizable via CSS. * * A variation of the "play mp3 links" demo. * * Requires SoundManager 2 Javascript API. */ /*jslint white: false, onevar: true, undef: true, nomen: false, eqeqeq: true, plusplus: false, bitwise: true, regexp: false, newcap: true, immed: true */ /*global document, window, soundManager, navigator */ function BasicMP3Player() { var self = this, pl = this, sm = soundManager, // soundManager instance isTouchDevice = (navigator.userAgent.match(/ipad|iphone/i)), isIE = (navigator.userAgent.match(/msie/i)); this.excludeClass = 'button-exclude'; // CSS class for ignoring MP3 links this.links = []; this.sounds = []; this.soundsByURL = {}; this.indexByURL = {}; this.lastSound = null; this.soundCount = 0; this.config = { // configuration options playNext: false, // 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_button', // default state sLoading: 'sm2_loading', sPlaying: 'sm2_playing', sPaused: 'sm2_paused' }; // event + DOM utils this.includeClass = this.css.sDefault; 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 false; } o.className = (o.className?o.className+' ':'')+cStr; }; this.removeClass = function(o,cStr) { if (!o || !cStr || !self.classContains(o,cStr)) { return false; } 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); }, stop: function() { pl.removeClass(this._data.oLink,this._data.className); this._data.className = ''; }, pause: function() { pl.removeClass(this._data.oLink,this._data.className); this._data.className = ''; // pl.removeClass(this._data.oLink,this._data.className); // this._data.className = pl.css.sPaused; // pl.addClass(this._data.oLink,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); }, 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 (nextLink1) { // ignore right-click return true; } var o = self.getTheDamnLink(e), sURL, soundURL, thisSound; if (o.nodeName.toLowerCase() !== 'a') { o = self.isChildOfNode(o,'a'); if (!o) { return true; } } sURL = o.getAttribute('href'); if (!o.href || !soundManager.canPlayLink(o) || self.classContains(o,self.excludeClass)) { return true; // pass-thru for non-MP3/non-links } if (!self.classContains(o,self.includeClass)) { return true; } sm._writeDebug('handleClick()'); soundURL = (o.href); thisSound = self.getSoundByURL(soundURL); if (thisSound) { // already exists if (thisSound === self.lastSound) { // and was playing (or paused) thisSound.togglePause(); } else { // different sound thisSound.togglePause(); // start playing current sm._writeDebug('sound different than last sound: '+self.lastSound.id); if (self.lastSound) { self.stopSound(self.lastSound); } } } else { // create sound thisSound = sm.createSound({ id:'basicMP3Sound'+(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) }); // 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); if (self.lastSound) { // stop last sound self.stopSound(self.lastSound); } thisSound.play(); } self.lastSound = thisSound; // reference for next call return self.stopEvent(e); }; this.stopSound = function(oSound) { soundManager.stop(oSound.id); if (!isTouchDevice) { // iOS 4.2+ security blocks onfinish() -> playNext() if we set a .src in-between(?) soundManager.unload(oSound.id); } }; this.init = function() { sm._writeDebug('basicMP3Player.init()'); var i, j, foundItems = 0, oLinks = document.getElementsByTagName('a'); // grab all links, look for .mp3 for (i=0, j=oLinks.length; i0) { self.addEventHandler(document,'click',self.handleClick); if (self.config.autoPlay) { self.handleClick({target:self.links[0],preventDefault:function(){}}); } } sm._writeDebug('basicMP3Player.init(): Found '+foundItems+' relevant items.'); }; this.init(); } var basicMP3Player = null; soundManager.setup({ preferFlash: false, onready: function() { basicMP3Player = new BasicMP3Player(); } });