/** * SoundManager 2 Demo: "Page as playlist" UI * ---------------------------------------------- * http://schillmania.com/projects/soundmanager2/ * * An example of a Muxtape.com-style UI, where an * unordered list of MP3 links becomes a playlist * * Flash 9 "MovieStar" edition supports MPEG4 * audio as well. * * Requires SoundManager 2 Javascript API. */ var pagePlayer = null; function PagePlayer() { /* global soundManager, window, document, navigator, setTimeout, Metadata, PP_CONFIG */ 'use strict'; var self = this, pl = this, sm = soundManager, // soundManager instance _event, vuDataCanvas = null, controlTemplate = null, _head = document.getElementsByTagName('head')[0], spectrumContainer = null, // sniffing for favicon stuff, IE workarounds and touchy-feely devices ua = navigator.userAgent, supportsFavicon = (ua.match(/(opera|firefox)/i)), isTouchDevice = (ua.match(/ipad|ipod|iphone/i)), cleanup; // configuration options // note that if Flash 9 is required, you must set soundManager.flashVersion = 9 in your script before this point. this.config = { usePeakData: false, // [Flash 9 only]: show peak data useWaveformData: false, // [Flash 9 only]: enable sound spectrum (raw waveform data) - WARNING: CPU-INTENSIVE: may set CPUs on fire. useEQData: false, // [Flash 9 only]: enable sound EQ (frequency spectrum data) - WARNING: Also CPU-intensive. fillGraph: false, // [Flash 9 only]: draw full lines instead of only top (peak) spectrum points allowRightClick: true, // let users right-click MP3 links ("save as...", etc.) or discourage (can't prevent.) useThrottling: true, // try to rate-limit potentially-expensive calls (eg. dragging position around) autoStart: false, // begin playing first sound when page loads playNext: true, // stop after one sound, or play through list until end updatePageTitle: true, // change the page title while playing sounds emptyTime: '-:--', // null/undefined timer values (before data is available) useFavIcon: false // try to show peakData in address bar (Firefox + Opera) - may be too CPU heavy }; 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.sounds = []; this.soundsByObject = []; this.lastSound = null; this.soundCount = 0; this.strings = []; this.dragActive = false; this.dragExec = new Date(); this.dragTimer = null; this.pageTitle = document.title; this.lastWPExec = new Date(); this.lastWLExec = new Date(); this.vuMeterData = []; this.oControls = null; this._mergeObjects = function(oMain, oAdd) { // non-destructive merge var o1 = {}, o2, i, o; // clone o1 for (i in oMain) { if (oMain.hasOwnProperty(i)) { o1[i] = oMain[i]; } } o2 = (typeof oAdd === 'undefined' ? {} : oAdd); for (o in o2) { if (typeof o1[o] === 'undefined') { o1[o] = o2[o]; } } return o1; }; _event = (function() { var old = (window.attachEvent && !window.addEventListener), _slice = Array.prototype.slice, evt = { add: (old ? 'attachEvent' : 'addEventListener'), remove: (old ? 'detachEvent' : 'removeEventListener') }; function getArgs(oArgs) { var args = _slice.call(oArgs), len = args.length; if (old) { args[1] = 'on' + args[1]; // prefix if (len > 3) { args.pop(); // no capture } } else if (len === 3) { args.push(false); } return args; } function apply(args, sType) { var element = args.shift(), method = [evt[sType]]; if (old) { element[method](args[0], args[1]); } else { element[method].apply(element, args); } } function add() { apply(getArgs(arguments), 'add'); } function remove() { apply(getArgs(arguments), 'remove'); } return { add: add, remove: remove }; }()); // event + DOM utilities this.hasClass = 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.hasClass(o, cStr)) { return; // safety net } o.className = (o.className ? o.className + ' ' : '') + cStr; }; this.removeClass = function(o, cStr) { if (!o || !cStr || !self.hasClass(o, cStr)) { return; } o.className = o.className.replace(new RegExp('( ' + cStr + ')|(' + cStr + ')', 'g'), ''); }; this.select = function(className, oParent) { var result = self.getByClassName(className, 'div', oParent || null); return (result ? result[0] : null); }; this.getByClassName = (document.querySelectorAll ? function(className, tagNames, oParent) { // tagNames: string or ['div', 'p'] etc. var pattern = ('.' + className), qs; if (tagNames) { tagNames = tagNames.split(' '); } qs = (tagNames.length > 1 ? tagNames.join(pattern + ', ') : tagNames[0] + pattern); return (oParent || document).querySelectorAll(qs); } : function(className, tagNames, oParent) { var node = (oParent || document), matches = [], i, j, nodes = []; if (tagNames) { tagNames = tagNames.split(' '); } if (tagNames instanceof Array) { for (i = tagNames.length; i--;) { if (!nodes || !nodes[tagNames[i]]) { nodes[tagNames[i]] = node.getElementsByTagName(tagNames[i]); } } for (i = tagNames.length; i--;) { for (j = nodes[tagNames[i]].length; j--;) { if (self.hasClass(nodes[tagNames[i]][j], className)) { matches.push(nodes[tagNames[i]][j]); } } } } else { nodes = node.all || node.getElementsByTagName('*'); for (i = 0, j = nodes.length; i < j; i++) { if (self.hasClass(nodes[i], className)) { matches.push(nodes[i]); } } } return matches; }); this.isChildOfClass = function(oChild, oClass) { if (!oChild || !oClass) { return false; } while (oChild.parentNode && !self.hasClass(oChild, oClass)) { oChild = oChild.parentNode; } return (self.hasClass(oChild, oClass)); }; this.getParentByNodeName = function(oChild, sParentNodeName) { if (!oChild || !sParentNodeName) { return false; } sParentNodeName = sParentNodeName.toLowerCase(); while (oChild.parentNode && sParentNodeName !== oChild.parentNode.nodeName.toLowerCase()) { oChild = oChild.parentNode; } return (oChild.parentNode && sParentNodeName === oChild.parentNode.nodeName.toLowerCase() ? oChild.parentNode : null); }; this.getOffX = function(o) { // http://www.xs4all.nl/~ppk/js/findpos.html var curleft = 0; if (o.offsetParent) { while (o.offsetParent) { curleft += o.offsetLeft; o = o.offsetParent; } } else if (o.x) { curleft += o.x; } return curleft; }; this.getTime = function(nMSec, bAsString) { // convert milliseconds to mm:ss, return as object literal or string var nSec = Math.floor(nMSec / 1000), min = Math.floor(nSec / 60), sec = nSec - (min * 60); // if (min === 0 && sec === 0) return null; // return 0:00 as null return (bAsString ? (min + ':' + (sec < 10 ? '0' + sec : sec)) : { min: min, sec: sec }); }; this.getSoundByObject = function(o) { return (typeof self.soundsByObject[o.id] !== 'undefined' ? self.soundsByObject[o.id] : null); }; this.getPreviousItem = function(o) { // given