vendor/assets/javascripts/soundmanager2.js in soundmanager-rails-1.0.0 vs vendor/assets/javascripts/soundmanager2.js in soundmanager-rails-1.0.1
- old
+ new
@@ -6,11 +6,11 @@
*
* Copyright (c) 2007, Scott Schiller. All rights reserved.
* Code provided under the BSD License:
* http://schillmania.com/projects/soundmanager2/license.txt
*
- * V2.97a.20130512
+ * V2.97a.20131201
*/
/*global window, SM2_DEFER, sm2Debugger, console, document, navigator, setTimeout, setInterval, clearInterval, Audio, opera */
/*jslint regexp: true, sloppy: true, white: true, nomen: true, plusplus: true, todo: true */
@@ -71,11 +71,11 @@
'wmode': null, // flash rendering mode - null, 'transparent', or 'opaque' (last two allow z-index to work)
'allowScriptAccess': 'always', // for scripting the SWF (object/embed property), 'always' or 'sameDomain'
'useFlashBlock': false, // *requires flashblock.css, see demos* - allow recovery from flash blockers. Wait indefinitely and apply timeout CSS to SWF, if applicable.
'useHTML5Audio': true, // use HTML5 Audio() where API is supported (most Safari, Chrome versions), Firefox (no MP3/MP4.) Ideally, transparent vs. Flash API where possible.
'html5Test': /^(probably|maybe)$/i, // HTML5 Audio() format support test. Use /^probably$/i; if you want to be more conservative.
- 'preferFlash': true, // overrides useHTML5audio. if true and flash support present, will try to use flash for MP3/MP4 as needed since HTML5 audio support is still quirky in browsers.
+ 'preferFlash': false, // overrides useHTML5audio, will use Flash for MP3/MP4/AAC if present. Potential option if HTML5 playback with these formats is quirky.
'noSWFCache': false, // if true, appends ?ts={date} to break aggressive SWF caching.
'idPrefix': 'sound' // if an id is not provided to createSound(), this prefix is used for generated IDs - 'sound0', 'sound1' etc.
};
@@ -187,11 +187,11 @@
this.debugID = 'soundmanager-debug';
this.debugURLParam = /([#?&])debug=1/i;
// dynamic attributes
- this.versionNumber = 'V2.97a.20130512';
+ this.versionNumber = 'V2.97a.20131201';
this.version = null;
this.movieURL = null;
this.altURL = null;
this.swfLoaded = false;
this.enabled = false;
@@ -263,17 +263,18 @@
/**
* a few private internals (OK, a lot. :D)
*/
var SMSound,
- sm2 = this, globalHTML5Audio = null, flash = null, sm = 'soundManager', smc = sm + ': ', h5 = 'HTML5::', id, ua = navigator.userAgent, wl = window.location.href.toString(), doc = document, doNothing, setProperties, init, fV, on_queue = [], debugOpen = true, debugTS, didAppend = false, appendSuccess = false, didInit = false, disabled = false, windowLoaded = false, _wDS, wdCount = 0, initComplete, mixin, assign, extraOptions, addOnEvent, processOnEvents, initUserOnload, delayWaitForEI, waitForEI, setVersionInfo, handleFocus, strings, initMovie, preInit, domContentLoaded, winOnLoad, didDCLoaded, getDocument, createMovie, catchError, setPolling, initDebug, debugLevels = ['log', 'info', 'warn', 'error'], defaultFlashVersion = 8, disableObject, failSafely, normalizeMovieURL, oRemoved = null, oRemovedHTML = null, str, flashBlockHandler, getSWFCSS, swfCSS, toggleDebug, loopFix, policyFix, complain, idCheck, waitingForEI = false, initPending = false, startTimer, stopTimer, timerExecute, h5TimerCount = 0, h5IntervalTimer = null, parseURL, messages = [],
+ sm2 = this, globalHTML5Audio = null, flash = null, sm = 'soundManager', smc = sm + ': ', h5 = 'HTML5::', id, ua = navigator.userAgent, wl = window.location.href.toString(), doc = document, doNothing, setProperties, init, fV, on_queue = [], debugOpen = true, debugTS, didAppend = false, appendSuccess = false, didInit = false, disabled = false, windowLoaded = false, _wDS, wdCount = 0, initComplete, mixin, assign, extraOptions, addOnEvent, processOnEvents, initUserOnload, delayWaitForEI, waitForEI, rebootIntoHTML5, setVersionInfo, handleFocus, strings, initMovie, preInit, domContentLoaded, winOnLoad, didDCLoaded, getDocument, createMovie, catchError, setPolling, initDebug, debugLevels = ['log', 'info', 'warn', 'error'], defaultFlashVersion = 8, disableObject, failSafely, normalizeMovieURL, oRemoved = null, oRemovedHTML = null, str, flashBlockHandler, getSWFCSS, swfCSS, toggleDebug, loopFix, policyFix, complain, idCheck, waitingForEI = false, initPending = false, startTimer, stopTimer, timerExecute, h5TimerCount = 0, h5IntervalTimer = null, parseURL, messages = [],
canIgnoreFlash, needsFlash = null, featureCheck, html5OK, html5CanPlay, html5Ext, html5Unload, domContentLoadedIE, testHTML5, event, slice = Array.prototype.slice, useGlobalHTML5Audio = false, lastGlobalHTML5URL, hasFlash, detectFlash, badSafariFix, html5_events, showSupport, flushMessages, wrapCallback, idCounter = 0,
- is_iDevice = ua.match(/(ipad|iphone|ipod)/i), isAndroid = ua.match(/android/i), isIE = ua.match(/msie/i), isWebkit = ua.match(/webkit/i), isSafari = (ua.match(/safari/i) && !ua.match(/chrome/i)), isOpera = (ua.match(/opera/i)), isFirefox = (ua.match(/firefox/i)),
+ is_iDevice = ua.match(/(ipad|iphone|ipod)/i), isAndroid = ua.match(/android/i), isIE = ua.match(/msie/i), isWebkit = ua.match(/webkit/i), isSafari = (ua.match(/safari/i) && !ua.match(/chrome/i)), isOpera = (ua.match(/opera/i)),
mobileHTML5 = (ua.match(/(mobile|pre\/|xoom)/i) || is_iDevice || isAndroid),
isBadSafari = (!wl.match(/usehtml5audio/i) && !wl.match(/sm2\-ignorebadua/i) && isSafari && !ua.match(/silk/i) && ua.match(/OS X 10_6_([3-7])/i)), // Safari 4 and 5 (excluding Kindle Fire, "Silk") occasionally fail to load/play HTML5 audio on Snow Leopard 10.6.3 through 10.6.7 due to bug(s) in QuickTime X and/or other underlying frameworks. :/ Confirmed bug. https://bugs.webkit.org/show_bug.cgi?id=32159
hasConsole = (window.console !== _undefined && console.log !== _undefined), isFocused = (doc.hasFocus !== _undefined?doc.hasFocus():null), tryInitOnFocus = (isSafari && (doc.hasFocus === _undefined || !doc.hasFocus())), okToDisable = !tryInitOnFocus, flashMIME = /(mp3|mp4|mpa|m4a|m4b)/i, msecScale = 1000,
emptyURL = 'about:blank', // safe URL to unload, or load nothing from (flash 8 + most HTML5 UAs)
+ emptyWAV = 'data:audio/wave;base64,/UklGRiYAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQIAAAD//w==', // tiny WAV for HTML5 unloading
overHTTP = (doc.location?doc.location.protocol.match(/http/i):null),
http = (!overHTTP ? 'http:/'+'/' : ''),
// mp3, mp4, aac etc.
netStreamMimeTypes = /^\s*audio\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4||m4v|m4a|m4b|mp4v|3gp|3g2)\s*(?:$|;)/i,
// Flash v9.0r115+ "moviestar" formats
@@ -1007,11 +1008,11 @@
result = html5CanPlay({type:sMIME});
}
if (!result && needsFlash) {
// if flash 9, test netStream (movieStar) types as well.
- result = (sMIME && sm2.ok() ? !!((fV > 8 ? sMIME.match(netStreamMimeTypes) : null) || sMIME.match(sm2.mimePattern)) : null);
+ result = (sMIME && sm2.ok() ? !!((fV > 8 ? sMIME.match(netStreamMimeTypes) : null) || sMIME.match(sm2.mimePattern)) : null); // TODO: make less "weird" (per JSLint)
}
return result;
};
@@ -1610,14 +1611,10 @@
// reference: http://msdn.microsoft.com/en-us/library/ie/ff974759%28v=vs.85%29.aspx
s._a.preload = 'auto';
s._a._called_load = true;
- if (instanceOptions.autoPlay) {
- s.play();
- }
-
} else {
sm2._wD(s.id + ': Ignoring request to load again');
}
@@ -1927,12 +1924,12 @@
// this hasn't been loaded yet. load it first, and then do this again.
sm2._wD(fN + 'Beginning load for from/to case');
s.load({
- // TODO: was _oncanplay. Sounds wrong.
- oncanplay: onready
+ // note: custom HTML5-only event added for from/to implementation.
+ _oncanplay: onready
});
exit = false;
} else if (!s.isHTML5 && !s.loaded && (!s.readyState || s.readyState !== 2)) {
@@ -2024,11 +2021,11 @@
sm2._wD(s.id + ': Cloning Audio() for instance #' + s.instanceCount + '...');
audioClone = new Audio(s._iO.url);
onended = function() {
- event.remove(audioClone, 'onended', onended);
+ event.remove(audioClone, 'ended', onended);
s._onfinish(s);
// cleanup
html5Unload(audioClone);
audioClone = null;
};
@@ -2043,10 +2040,20 @@
audioClone.play();
};
event.add(audioClone, 'ended', onended);
+ // apply volume to clones, too
+ if (s._iO.volume !== undefined) {
+ audioClone.volume = Math.max(0, Math.min(1, s._iO.volume/100));
+ }
+
+ // playing multiple muted sounds? if you do this, you're weird ;) - but let's cover it.
+ if (s.muted) {
+ audioClone.muted = true;
+ }
+
if (s._iO.position) {
// HTML5 audio can't seek before onplay() event has fired.
// wait for canplay, then seek to position and start playback.
event.add(audioClone, 'canplay', oncanplay);
} else {
@@ -2429,10 +2436,14 @@
}
if (!s.isHTML5) {
flash._setVolume(s.id, (sm2.muted && !s.muted) || s.muted?0:nVol);
} else if (s._a) {
+ if (sm2.muted && !s.muted) {
+ s.muted = true;
+ s._a.muted = true;
+ }
// valid range: 0-1
s._a.volume = Math.max(0, Math.min(1, nVol/100));
}
s._iO.volume = nVol;
@@ -2563,24 +2574,25 @@
};
this._processOnPosition = function() {
var i, item, j = onPositionItems.length;
-
+
if (!j || !s.playState || onPositionFired >= j) {
return false;
}
for (i=j-1; i >= 0; i--) {
item = onPositionItems[i];
if (!item.fired && s.position >= item.position) {
item.fired = true;
onPositionFired++;
item.method.apply(item.scope, [item.position]);
+ j = onPositionItems.length; // reset j -- onPositionItems.length can be changed in the item callback above... occasionally breaking the loop.
}
}
-
+
return true;
};
this._resetOnPosition = function(nPosition) {
@@ -2666,11 +2678,11 @@
if (op) {
for (item in op) {
if (op.hasOwnProperty(item)) {
- s.onPosition(parseInt(item, 10), op[item]);
+ s.onPosition(parseInt(item, 10), op[item]);
}
}
}
@@ -2909,13 +2921,15 @@
}
if (!sameURL) {
- // don't retain onPosition() stuff with new URL.
+ // don't retain onPosition() stuff with new URLs.
- resetProperties(false);
+ if (lastURL) {
+ resetProperties(false);
+ }
// assign new HTML5 URL
a.src = instanceOptions.url;
@@ -2932,10 +2946,11 @@
} else {
if (instanceOptions.autoLoad || instanceOptions.autoPlay) {
s._a = new Audio(instanceOptions.url);
+ s._a.load();
} else {
// null for stupid Opera 9.64 case
s._a = (isOpera && opera.version() < 10 ? new Audio(null) : new Audio());
@@ -3273,11 +3288,11 @@
this._oncaptiondata = function(oData) {
/**
* internal: flash 9 + NetStream (MovieStar/RTMP-only) feature
- *
+ *
* @param {object} oData
*/
sm2._wD(s.id + ': Caption data received.');
@@ -3292,11 +3307,11 @@
this._onmetadata = function(oMDProps, oMDData) {
/**
* internal: flash 9 + NetStream (MovieStar/RTMP-only) feature
* RTMP may include song title, MovieStar content may include encoding info
- *
+ *
* @param {array} oMDProps (names)
* @param {array} oMDData (values)
*/
sm2._wD(s.id + ': Metadata received.');
@@ -3317,11 +3332,11 @@
this._onid3 = function(oID3Props, oID3Data) {
/**
* internal: flash 8 + flash 9 ID3 feature
* may include artist, song title etc.
- *
+ *
* @param {array} oID3Props (names)
* @param {array} oID3Data (values)
*/
sm2._wD(s.id + ': ID3 data received.');
@@ -3392,11 +3407,11 @@
* ------------------------------
*/
getDocument = function() {
- return (doc.body || doc._docElement || doc.getElementsByTagName('div')[0]);
+ return (doc.body || doc.getElementsByTagName('div')[0]);
};
id = function(sID) {
@@ -3849,11 +3864,11 @@
progress: html5_event(function(e) {
// note: can fire repeatedly after "loaded" event, due to use of HTTP range/partials
var s = this._s,
- i, j, str, buffered = 0,
+ i, j, progStr, buffered = 0,
isProgress = (e.type === 'progress'),
ranges = e.target.buffered,
// firefox 3.6 implements e.loaded/total (bytes)
loaded = (e.loaded||0),
total = (e.total||1);
@@ -3881,16 +3896,16 @@
// linear case, buffer sum; does not account for seeking and HTTP partials / byte ranges
loaded = Math.min(1, buffered/(e.target.duration*msecScale));
// <d>
if (isProgress && ranges.length > 1) {
- str = [];
+ progStr = [];
j = ranges.length;
for (i=0; i<j; i++) {
- str.push(e.target.buffered.start(i)*msecScale +'-'+ e.target.buffered.end(i)*msecScale);
+ progStr.push(e.target.buffered.start(i)*msecScale +'-'+ e.target.buffered.end(i)*msecScale);
}
- sm2._wD(this._s.id + ': progress, timeRanges: ' + str.join(', '));
+ sm2._wD(this._s.id + ': progress, timeRanges: ' + progStr.join(', '));
}
if (isProgress && !isNaN(loaded)) {
sm2._wD(this._s.id + ': progress, ' + Math.floor(loaded*100) + '% loaded');
}
@@ -3995,12 +4010,13 @@
var url;
if (oAudio) {
- // Firefox likes '' for unload (used to work, but no longer?) - however, may request hosting page URL (bad.) Most other UAs dislike '' and fail to unload.
- url = (isSafari && !is_iDevice ? null : (isFirefox ? emptyURL : null));
+ // Firefox and Chrome accept short WAVe data: URIs. Chome dislikes audio/wav, but accepts audio/wav for data: MIME.
+ // Desktop Safari complains / fails on data: URI, so it gets about:blank.
+ url = (isSafari ? emptyURL : (sm2.html5.canPlayType('audio/wav') ? emptyWAV : emptyURL));
oAudio.src = url;
// reset some state, too
if (oAudio._called_unload !== undefined) {
@@ -4111,11 +4127,11 @@
var a = (Audio !== _undefined ? (isOpera && opera.version() < 10 ? new Audio(null) : new Audio()) : null),
item, lookup, support = {}, aF, i;
function cp(m) {
- var canPlay, i, j,
+ var canPlay, j,
result = false,
isOK = false;
if (!a || typeof a.canPlayType !== 'function') {
return result;
@@ -4255,24 +4271,29 @@
// internal string replace helper.
// arguments: o [,items to replace]
// <d>
+ var args,
+ i, j, o,
+ sstr;
+
// real array, please
- var args = slice.call(arguments),
+ args = slice.call(arguments);
- // first arg
- o = args.shift(),
+ // first argument
+ o = args.shift();
- str = (strings && strings[o]?strings[o]:''), i, j;
- if (str && args && args.length) {
+ sstr = (strings && strings[o] ? strings[o] : '');
+
+ if (sstr && args && args.length) {
for (i = 0, j = args.length; i < j; i++) {
- str = str.replace('%s', args[i]);
+ sstr = sstr.replace('%s', args[i]);
}
}
- return str;
+ return sstr;
// </d>
};
loopFix = function(sOpt) {
@@ -4887,11 +4908,11 @@
if (!mobileHTML5 && sm2.html5PollingInterval) {
if (h5IntervalTimer === null && h5TimerCount === 0) {
h5IntervalTimer = setInterval(timerExecute, sm2.html5PollingInterval);
-
+
}
h5TimerCount++;
}
@@ -5087,11 +5108,14 @@
function initMsg() {
// <d>
- var options = [], title, str = [], delimiter = ' + ';
+ var options = [],
+ title,
+ msg = [],
+ delimiter = ' + ';
title = 'SoundManager ' + sm2.version + (!sm2.html5Only && sm2.useHTML5Audio ? (sm2.hasHTML5 ? ' + HTML5 audio' : ', no HTML5 audio support') : '');
if (!sm2.html5Only) {
@@ -5130,14 +5154,14 @@
}
}
if (options.length) {
- str = str.concat([options.join(delimiter)]);
+ msg = msg.concat([options.join(delimiter)]);
}
- sm2._wD(title + (str.length ? delimiter + str.join(', ') : ''), 1);
+ sm2._wD(title + (msg.length ? delimiter + msg.join(', ') : ''), 1);
showSupport();
// </d>
@@ -5402,10 +5426,31 @@
setTimeout(waitForEI, 1000);
};
+ rebootIntoHTML5 = function() {
+
+ // special case: try for a reboot with preferFlash: false, if 100% HTML5 mode is possible and useFlashBlock is not enabled.
+
+ window.setTimeout(function() {
+
+ complain(smc + 'useFlashBlock is false, 100% HTML5 mode is possible. Rebooting with preferFlash: false...');
+
+ sm2.setup({
+ preferFlash: false
+ }).reboot();
+
+ // if for some reason you want to detect this case, use an ontimeout() callback and look for html5Only and didFlashBlock == true.
+ sm2.didFlashBlock = true;
+
+ sm2.beginDelayedInit();
+
+ }, 1);
+
+ };
+
waitForEI = function() {
var p,
loadIncomplete = false;
@@ -5419,11 +5464,11 @@
}
waitingForEI = true;
event.remove(window, 'load', delayWaitForEI);
- if (tryInitOnFocus && !isFocused) {
+ if (hasFlash && tryInitOnFocus && !isFocused) {
// Safari won't load flash in background tabs, only when focused.
_wDS('waitFocus');
return false;
}
@@ -5446,32 +5491,42 @@
return false;
}
// <d>
if (!didInit) {
+
sm2._wD(sm + ': No Flash response within expected time. Likely causes: ' + (p === 0 ? 'SWF load failed, ':'') + 'Flash blocked or JS-Flash security error.' + (sm2.debugFlash?' ' + str('checkSWF'):''), 2);
+
if (!overHTTP && p) {
+
_wDS('localFail', 2);
+
if (!sm2.debugFlash) {
_wDS('tryDebug', 2);
}
+
}
+
if (p === 0) {
+
// if 0 (not null), probably a 404.
sm2._wD(str('swf404', sm2.url), 1);
+
}
+
debugTS('flashtojs', false, ': Timed out' + overHTTP?' (Check flash security or flash blockers)':' (No plugin/missing SWF?)');
+
}
// </d>
// give up / time-out, depending
if (!didInit && okToDisable) {
if (p === null) {
- // SWF failed. Maybe blocked.
+ // SWF failed to report load progress. Possibly blocked.
if (sm2.useFlashBlock || sm2.flashLoadTimeout === 0) {
if (sm2.useFlashBlock) {
@@ -5485,53 +5540,47 @@
// no custom flash block handling, but SWF has timed out. Will recover if user unblocks / allows SWF load.
if (!sm2.useFlashBlock && canIgnoreFlash) {
- // special case: try for a reboot with preferFlash: false, if 100% HTML5 mode is possible and useFlashBlock is not enabled.
+ rebootIntoHTML5();
- window.setTimeout(function() {
-
- complain(smc + 'useFlashBlock is false, 100% HTML5 mode is possible. Rebooting with preferFlash: false...');
-
- sm2.setup({
- preferFlash: false
- }).reboot();
-
- // if for some reason you want to detect this case, use an ontimeout() callback and look for html5Only and didFlashBlock == true.
- sm2.didFlashBlock = true;
-
- sm2.beginDelayedInit();
-
- }, 1);
-
} else {
_wDS('waitForever');
// fire any regular registered ontimeout() listeners.
- processOnEvents({type:'ontimeout', ignoreInit: true});
+ processOnEvents({type:'ontimeout', ignoreInit: true, error: {type: 'INIT_FLASHBLOCK'}});
}
}
} else {
- // flash loaded? Shouldn't be a blocking issue, then.
+ // SWF loaded? Shouldn't be a blocking issue, then.
if (sm2.flashLoadTimeout === 0) {
_wDS('waitForever');
} else {
- failSafely(true);
+ if (!sm2.useFlashBlock && canIgnoreFlash) {
+ rebootIntoHTML5();
+
+ } else {
+
+ failSafely(true);
+
+ }
+
}
}
+
}
}, sm2.flashLoadTimeout);
};
@@ -5617,15 +5666,14 @@
result = true,
error;
if (!wasTimeout) {
didInit = true;
- if (disabled) {
- error = {type: (!hasFlash && needsFlash ? 'NO_FLASH' : 'INIT_TIMEOUT')};
- }
}
+ error = {type: (!hasFlash && needsFlash ? 'NO_FLASH' : 'INIT_TIMEOUT')};
+
sm2._wD('SoundManager 2 ' + (disabled ? 'failed to load' : 'loaded') + ' (' + (disabled ? 'Flash security/load error' : 'OK') + ')', disabled ? 2: 1);
if (disabled || bNoDisable) {
if (sm2.useFlashBlock && sm2.oMC) {
sm2.oMC.className = getSWFCSS() + ' ' + (sm2.getMoviePercent() === null?swfCSS.swfTimedout:swfCSS.swfError);
@@ -5781,11 +5829,11 @@
// <d>
(function(){
var a = 'sm2-usehtml5audio=',
a2 = 'sm2-preferflash=',
- b = null,
+ b = null,
b2 = null,
l = wl.toLowerCase();
if (l.indexOf(a) !== -1) {
b = (l.charAt(l.indexOf(a)+a.length) === '1');
@@ -5809,11 +5857,11 @@
}());
// </d>
if (!hasFlash && sm2.hasHTML5) {
- sm2._wD('SoundManager: No Flash detected' + (!sm2.useHTML5Audio ? ', enabling HTML5.' : '. Trying HTML5-only mode.'), 1);
+ sm2._wD('SoundManager 2: No Flash detected' + (!sm2.useHTML5Audio ? ', enabling HTML5.' : '. Trying HTML5-only mode.'), 1);
sm2.setup({
'useHTML5Audio': true,
// make sure we aren't preferring flash, either
// TODO: preferFlash should not matter if flash is not installed. Currently, stuff breaks without the below tweak.
'preferFlash': false
@@ -5936,6 +5984,6 @@
*/
window.SoundManager = SoundManager; // constructor
window.soundManager = soundManager; // public API, flash callbacks etc.
-}(window));
\ No newline at end of file
+}(window));