/**
* JW Player Source start cap
*
* This will appear at the top of the JW Player source
*
*/
if (typeof jwplayer === 'undefined') {
/**
* JW Player namespace definition
*/
/*global jwplayer:true*/
jwplayer = function() {
if (jwplayer.api) {
return jwplayer.api.selectPlayer.apply(this, arguments);
}
};
jwplayer.version = '6.12.0';
// "Shiv" method for older IE browsers; required for parsing media tags
jwplayer.vid = document.createElement('video');
jwplayer.audio = document.createElement('audio');
jwplayer.source = document.createElement('source');
// Underscore.js
// http://underscorejs.org
// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Underscore may be freely distributed under the MIT license.
// https://github.com/jashkenas/underscore/blob/1f4bf626f23a99f7a676f5076dc1b1475554c8f7/underscore.js
(function() {
var root = this;
// Establish the object that gets returned to break out of a loop iteration.
var breaker = {};
// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
// Create quick reference variables for speed access to core prototypes.
var
slice = ArrayProto.slice,
concat = ArrayProto.concat,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;
// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
var
nativeMap = ArrayProto.map,
nativeForEach = ArrayProto.forEach,
nativeFilter = ArrayProto.filter,
nativeEvery = ArrayProto.every,
nativeSome = ArrayProto.some,
nativeIndexOf = ArrayProto.indexOf,
nativeIsArray = Array.isArray,
nativeKeys = Object.keys;
// Create a safe reference to the Underscore object for use below.
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
};
// Collection Functions
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
// Handles objects with the built-in `forEach`, arrays, and raw objects.
// Delegates to **ECMAScript 5**'s native `forEach` if available.
var each = _.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return obj;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, length = obj.length; i < length; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
var keys = _.keys(obj);
for (var i = 0, length = keys.length; i < length; i++) {
if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
}
}
return obj;
};
// Return the results of applying the iterator to each element.
// Delegates to **ECMAScript 5**'s native `map` if available.
_.map = _.collect = function(obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
each(obj, function(value, index, list) {
results.push(iterator.call(context, value, index, list));
});
return results;
};
// Return the first value which passes a truth test. Aliased as `detect`.
_.find = _.detect = function(obj, predicate, context) {
var result;
any(obj, function(value, index, list) {
if (predicate.call(context, value, index, list)) {
result = value;
return true;
}
});
return result;
};
// Return all the elements that pass a truth test.
// Delegates to **ECMAScript 5**'s native `filter` if available.
// Aliased as `select`.
_.filter = _.select = function(obj, predicate, context) {
var results = [];
if (obj == null) return results;
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
each(obj, function(value, index, list) {
if (predicate.call(context, value, index, list)) results.push(value);
});
return results;
};
// Determine whether all of the elements match a truth test.
// Delegates to **ECMAScript 5**'s native `every` if available.
// Aliased as `all`.
_.every = _.all = function(obj, predicate, context) {
predicate || (predicate = _.identity);
var result = true;
if (obj == null) return result;
if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);
each(obj, function(value, index, list) {
if (!(result = result && predicate.call(context, value, index, list))) return breaker;
});
return !!result;
};
// Determine if at least one element in the object matches a truth test.
// Delegates to **ECMAScript 5**'s native `some` if available.
// Aliased as `any`.
var any = _.some = _.any = function(obj, predicate, context) {
predicate || (predicate = _.identity);
var result = false;
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
each(obj, function(value, index, list) {
if (result || (result = predicate.call(context, value, index, list))) return breaker;
});
return !!result;
};
//returns the size of an object
_.size = function(obj) {
if (obj == null) return 0;
return obj.length === +obj.length ? obj.length : _.keys(obj).length;
};
// Returns a function that will only be executed after being called N times.
_.after = function(times, func) {
return function() {
if (--times < 1) {
return func.apply(this, arguments);
}
};
};
// An internal function to generate lookup iterators.
var lookupIterator = function(value) {
if (value == null) return _.identity;
if (_.isFunction(value)) return value;
return _.property(value);
};
// Use a comparator function to figure out the smallest index at which
// an object should be inserted so as to maintain order. Uses binary search.
_.sortedIndex = function(array, obj, iterator, context) {
iterator = lookupIterator(iterator);
var value = iterator.call(context, obj);
var low = 0, high = array.length;
while (low < high) {
var mid = (low + high) >>> 1;
iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
}
return low;
};
// Return the first value which passes a truth test. Aliased as `detect`.
_.find = _.detect = function(obj, predicate, context) {
var result;
any(obj, function(value, index, list) {
if (predicate.call(context, value, index, list)) {
result = value;
return true;
}
});
return result;
};
// Determine if at least one element in the object matches a truth test.
// Delegates to **ECMAScript 5**'s native `some` if available.
// Aliased as `any`.
var any = _.some = _.any = function(obj, predicate, context) {
predicate || (predicate = _.identity);
var result = false;
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
each(obj, function(value, index, list) {
if (result || (result = predicate.call(context, value, index, list))) return breaker;
});
return !!result;
};
_.contains = _.include = function(obj, target) {
if (obj == null) return false;
if (obj.length !== +obj.length) obj = _.values(obj);
return _.indexOf(obj, target) >= 0;
};
// Convenience version of a common use case of `filter`: selecting only objects
// containing specific `key:value` pairs.
_.where = function(obj, attrs) {
return _.filter(obj, _.matches(attrs));
};
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = function(array) {
var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
return _.filter(array, function(value){ return !_.contains(rest, value); });
};
// Return a version of the array that does not contain the specified value(s).
_.without = function(array) {
return _.difference(array, slice.call(arguments, 1));
};
// If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
// we need this function. Return the position of the first occurrence of an
// item in an array, or -1 if the item is not included in the array.
// Delegates to **ECMAScript 5**'s native `indexOf` if available.
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
_.indexOf = function(array, item, isSorted) {
if (array == null) return -1;
var i = 0, length = array.length;
if (isSorted) {
if (typeof isSorted == 'number') {
i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
} else {
i = _.sortedIndex(array, item);
return array[i] === item ? i : -1;
}
}
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
for (; i < length; i++) if (array[i] === item) return i;
return -1;
};
// Function (ahem) Functions
// ------------------
// Partially apply a function by creating a version that has had some of its
// arguments pre-filled, without changing its dynamic `this` context. _ acts
// as a placeholder, allowing any combination of arguments to be pre-filled.
_.partial = function(func) {
var boundArgs = slice.call(arguments, 1);
return function() {
var position = 0;
var args = boundArgs.slice();
for (var i = 0, length = args.length; i < length; i++) {
if (args[i] === _) args[i] = arguments[position++];
}
while (position < arguments.length) args.push(arguments[position++]);
return func.apply(this, args);
};
};
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
var memo = {};
hasher || (hasher = _.identity);
return function() {
var key = hasher.apply(this, arguments);
return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
};
};
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
// Defers a function, scheduling it to run after the current call stack has
// cleared.
_.defer = function(func) {
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
};
// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = function(obj) {
if (!_.isObject(obj)) return [];
if (nativeKeys) return nativeKeys(obj);
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key);
return keys;
};
// Return a copy of the object only containing the whitelisted properties.
_.pick = function(obj) {
var copy = {};
var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
each(keys, function(key) {
if (key in obj) copy[key] = obj[key];
});
return copy;
};
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) == '[object Array]';
};
// Is a given variable an object?
_.isObject = function(obj) {
return obj === Object(obj);
};
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
_['is' + name] = function(obj) {
return toString.call(obj) == '[object ' + name + ']';
};
});
// Define a fallback version of the method in browsers (ahem, IE), where
// there isn't any inspectable "Arguments" type.
if (!_.isArguments(arguments)) {
_.isArguments = function(obj) {
return !!(obj && _.has(obj, 'callee'));
};
}
// Optimize `isFunction` if appropriate.
if (typeof (/./) !== 'function') {
_.isFunction = function(obj) {
return typeof obj === 'function';
};
}
// Is a given object a finite number?
_.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj));
};
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
_.isNaN = function(obj) {
return _.isNumber(obj) && obj != +obj;
};
// Is a given value a boolean?
_.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
};
// Is a given value equal to null?
_.isNull = function(obj) {
return obj === null;
};
// Is a given variable undefined?
_.isUndefined = function(obj) {
return obj === void 0;
};
// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
return hasOwnProperty.call(obj, key);
};
// Keep the identity function around for default iterators.
_.identity = function(value) {
return value;
};
_.constant = function(value) {
return function () {
return value;
};
};
_.property = function(key) {
return function(obj) {
return obj[key];
};
};
// Returns a predicate for checking whether an object has a given set of `key:value` pairs.
_.matches = function(attrs) {
return function(obj) {
if (obj === attrs) return true; //avoid comparing an object to itself.
for (var key in attrs) {
if (attrs[key] !== obj[key])
return false;
}
return true;
}
};
// If the value of the named `property` is a function then invoke it with the
// `object` as context; otherwise, return it.
_.result = function(object, property) {
if (object == null) return void 0;
var value = object[property];
return _.isFunction(value) ? value.call(object) : value;
};
root._ = _;
}).call(jwplayer);
(function(jwplayer) {
/*jshint maxparams:5*/
var utils = jwplayer.utils = {};
var _ = jwplayer._;
/**
* Returns true if the value of the object is null, undefined or the empty
* string
*
* @param a The variable to inspect
*/
utils.exists = function(item) {
switch (typeof(item)) {
case 'string':
return (item.length > 0);
case 'object':
return (item !== null);
case 'undefined':
return false;
}
return true;
};
/** Used for styling dimensions in CSS --
* return the string unchanged if it's a percentage width; add 'px' otherwise **/
utils.styleDimension = function(dimension) {
return dimension + (dimension.toString().indexOf('%') > 0 ? '' : 'px');
};
/** Gets an absolute file path based on a relative filepath * */
utils.getAbsolutePath = function(path, base) {
if (!utils.exists(base)) {
base = document.location.href;
}
if (!utils.exists(path)) {
return;
}
if (isAbsolutePath(path)) {
return path;
}
var protocol = base.substring(0, base.indexOf('://') + 3);
var domain = base.substring(protocol.length, base.indexOf('/', protocol.length + 1));
var patharray;
if (path.indexOf('/') === 0) {
patharray = path.split('/');
} else {
var basepath = base.split('?')[0];
basepath = basepath.substring(protocol.length + domain.length + 1, basepath.lastIndexOf('/'));
patharray = basepath.split('/').concat(path.split('/'));
}
var result = [];
for (var i = 0; i < patharray.length; i++) {
if (!patharray[i] || !utils.exists(patharray[i]) || patharray[i] === '.') {
continue;
} else if (patharray[i] === '..') {
result.pop();
} else {
result.push(patharray[i]);
}
}
return protocol + domain + '/' + result.join('/');
};
function isAbsolutePath(path) {
if (!utils.exists(path)) {
return;
}
var protocol = path.indexOf('://');
var queryparams = path.indexOf('?');
return (protocol > 0 && (queryparams < 0 || (queryparams > protocol)));
}
/** Merges a list of objects **/
utils.extend = function() {
var args = Array.prototype.slice.call(arguments, 0);
if (args.length > 1) {
var objectToExtend = args[0],
extendEach = function(element, arg) {
if (arg !== undefined && arg !== null) {
objectToExtend[element] = arg;
}
};
for (var i = 1; i < args.length; i++) {
utils.foreach(args[i], extendEach);
}
return objectToExtend;
}
return null;
};
/** Logger */
var console = window.console = window.console || {
log: function() {}
};
utils.log = function() {
var args = Array.prototype.slice.call(arguments, 0);
if (typeof console.log === 'object') {
console.log(args);
} else {
console.log.apply(console, args);
}
};
var _userAgentMatch = _.memoize(function(regex) {
var agent = navigator.userAgent.toLowerCase();
return (agent.match(regex) !== null);
});
function _browserCheck(regex) {
return function() {
return _userAgentMatch(regex);
};
}
utils.isFF = _browserCheck(/firefox/i);
utils.isChrome = _browserCheck(/chrome/i);
utils.isIPod = _browserCheck(/iP(hone|od)/i);
utils.isIPad = _browserCheck(/iPad/i);
utils.isSafari602 = _browserCheck(/Macintosh.*Mac OS X 10_8.*6\.0\.\d* Safari/i);
utils.isIETrident = function(version) {
if (version) {
version = parseFloat(version).toFixed(1);
return _userAgentMatch(new RegExp('trident/.+rv:\\s*' + version, 'i'));
}
return _userAgentMatch(/trident/i);
};
utils.isMSIE = function(version) {
if (version) {
version = parseFloat(version).toFixed(1);
return _userAgentMatch(new RegExp('msie\\s*' + version, 'i'));
}
return _userAgentMatch(/msie/i);
};
utils.isIE = function(version) {
if (version) {
version = parseFloat(version).toFixed(1);
if (version >= 11) {
return utils.isIETrident(version);
} else {
return utils.isMSIE(version);
}
}
return utils.isMSIE() || utils.isIETrident();
};
utils.isSafari = function() {
return (_userAgentMatch(/safari/i) && !_userAgentMatch(/chrome/i) &&
!_userAgentMatch(/chromium/i) && !_userAgentMatch(/android/i));
};
/** Matches iOS devices **/
utils.isIOS = function(version) {
if (version) {
return _userAgentMatch(new RegExp('iP(hone|ad|od).+\\sOS\\s' + version, 'i'));
}
return _userAgentMatch(/iP(hone|ad|od)/i);
};
/** Matches Android devices **/
utils.isAndroidNative = function(version) {
return utils.isAndroid(version, true);
};
utils.isAndroid = function(version, excludeChrome) {
//Android Browser appears to include a user-agent string for Chrome/18
if (excludeChrome && _userAgentMatch(/chrome\/[123456789]/i) && !_userAgentMatch(/chrome\/18/)) {
return false;
}
if (version) {
// make sure whole number version check ends with point '.'
if (utils.isInt(version) && !/\./.test(version)) {
version = '' + version + '.';
}
return _userAgentMatch(new RegExp('Android\\s*' + version, 'i'));
}
return _userAgentMatch(/Android/i);
};
/** Matches iOS and Android devices **/
utils.isMobile = function() {
return utils.isIOS() || utils.isAndroid();
};
utils.isIframe = function() {
return (window.frameElement && (window.frameElement.nodeName === 'IFRAME'));
};
/** Save a setting **/
utils.saveCookie = function(name, value) {
document.cookie = 'jwplayer.' + name + '=' + value + '; path=/';
};
/** Retrieve saved player settings **/
utils.getCookies = function() {
var jwCookies = {};
var cookies = document.cookie.split('; ');
for (var i = 0; i < cookies.length; i++) {
var split = cookies[i].split('=');
if (split[0].indexOf('jwplayer.') === 0) {
jwCookies[split[0].substring(9, split[0].length)] = split[1];
}
}
return jwCookies;
};
utils.isInt = function(value) {
return parseFloat(value) % 1 === 0;
};
/** Returns the true type of an object * */
utils.typeOf = function(value) {
if (value === null) {
return 'null';
}
var typeofString = typeof value;
if (typeofString === 'object') {
if (_.isArray(value)) {
return 'array';
}
}
return typeofString;
};
/* Normalizes differences between Flash and HTML5 internal players' event responses. */
utils.translateEventResponse = function(type, eventProperties) {
var translated = utils.extend({}, eventProperties);
if (type === jwplayer.events.JWPLAYER_FULLSCREEN && !translated.fullscreen) {
translated.fullscreen = (translated.message === 'true');
delete translated.message;
} else if (typeof translated.data === 'object') {
// Takes ViewEvent 'data' block and moves it up a level
var data = translated.data;
delete translated.data;
translated = utils.extend(translated, data);
} else if (typeof translated.metadata === 'object') {
utils.deepReplaceKeyName(translated.metadata,
['__dot__', '__spc__', '__dsh__', '__default__'], ['.', ' ', '-', 'default']);
}
var rounders = ['position', 'duration', 'offset'];
utils.foreach(rounders, function(rounder, val) {
if (translated[val]) {
translated[val] = Math.round(translated[val] * 1000) / 1000;
}
});
return translated;
};
/**
* If the browser has flash capabilities, return the flash version
*/
utils.flashVersion = function() {
if (utils.isAndroid()) {
return 0;
}
var plugins = navigator.plugins,
flash;
try {
if (plugins !== 'undefined') {
flash = plugins['Shockwave Flash'];
if (flash) {
return parseInt(flash.description.replace(/\D+(\d+)\..*/, '$1'), 10);
}
}
} catch (e) {
// The above evaluation (plugins != undefined) messes up IE7
}
if (typeof window.ActiveXObject !== 'undefined') {
try {
flash = new window.ActiveXObject('ShockwaveFlash.ShockwaveFlash');
if (flash) {
return parseInt(flash.GetVariable('$version').split(' ')[1].split(',')[0], 10);
}
} catch (err) {}
}
return 0;
};
/** Finds the location of jwplayer.js and returns the path **/
utils.getScriptPath = function(scriptName) {
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
var src = scripts[i].src;
if (src && src.indexOf(scriptName) >= 0) {
return src.substr(0, src.indexOf(scriptName));
}
}
return '';
};
/**
* Recursively traverses nested object, replacing key names containing a
* search string with a replacement string.
*
* @param searchString
* The string to search for in the object's key names
* @param replaceString
* The string to replace in the object's key names
* @returns The modified object.
*/
utils.deepReplaceKeyName = function(obj, searchString, replaceString) {
switch (jwplayer.utils.typeOf(obj)) {
case 'array':
for (var i = 0; i < obj.length; i++) {
obj[i] = jwplayer.utils.deepReplaceKeyName(obj[i],
searchString, replaceString);
}
break;
case 'object':
utils.foreach(obj, function(key, val) {
var searches;
if (searchString instanceof Array && replaceString instanceof Array) {
if (searchString.length !== replaceString.length) {
return;
} else {
searches = searchString;
}
} else {
searches = [searchString];
}
var newkey = key;
for (var i = 0; i < searches.length; i++) {
newkey = newkey.replace(new RegExp(searchString[i], 'g'), replaceString[i]);
}
obj[newkey] = jwplayer.utils.deepReplaceKeyName(val, searchString, replaceString);
if (key !== newkey) {
delete obj[key];
}
});
break;
}
return obj;
};
/**
* Types of plugin paths
*/
var _pluginPathType = utils.pluginPathType = {
ABSOLUTE: 0,
RELATIVE: 1,
CDN: 2
};
utils.getPluginPathType = function(path) {
if (typeof path !== 'string') {
return;
}
path = path.split('?')[0];
var protocol = path.indexOf('://');
if (protocol > 0) {
return _pluginPathType.ABSOLUTE;
}
var folder = path.indexOf('/');
var extension = utils.extension(path);
if (protocol < 0 && folder < 0 && (!extension || !isNaN(extension))) {
return _pluginPathType.CDN;
}
return _pluginPathType.RELATIVE;
};
/**
* Extracts a plugin name from a string
*/
utils.getPluginName = function(pluginName) {
/** Regex locates the characters after the last slash, until it encounters a dash. **/
return pluginName.replace(/^(.*\/)?([^-]*)-?.*\.(swf|js)$/, '$2');
};
/**
* Extracts a plugin version from a string
*/
utils.getPluginVersion = function(pluginName) {
return pluginName.replace(/[^-]*-?([^\.]*).*$/, '$1');
};
/**
* Determines if a URL is a YouTube link
*/
utils.isYouTube = function(path, type) {
return (type === 'youtube') || (/^(http|\/\/).*(youtube\.com|youtu\.be)\/.+/).test(path);
};
/**
* Returns a YouTube ID from a number of YouTube URL formats:
*
* Matches the following YouTube URL types:
* - http://www.youtube.com/watch?v=YE7VzlLtp-4
* - http://www.youtube.com/watch?v=YE7VzlLtp-4&extra_param=123
* - http://www.youtube.com/watch#!v=YE7VzlLtp-4
* - http://www.youtube.com/watch#!v=YE7VzlLtp-4?extra_param=123&another_param=456
* - http://www.youtube.com/v/YE7VzlLtp-4
* - http://www.youtube.com/v/YE7VzlLtp-4?extra_param=123&another_param=456
* - http://youtu.be/YE7VzlLtp-4
* - http://youtu.be/YE7VzlLtp-4?extra_param=123&another_param=456
* - YE7VzlLtp-4
**/
utils.youTubeID = function(path) {
try {
// Left as a dense regular expression for brevity.
return (/v[=\/]([^?&]*)|youtu\.be\/([^?]*)|^([\w-]*)$/i).exec(path).slice(1).join('').replace('?', '');
} catch (e) {
return '';
}
};
/**
* Determines if a URL is an RTMP link
*/
utils.isRtmp = function(file, type) {
return (file.indexOf('rtmp') === 0 || type === 'rtmp');
};
/**
* Iterates over an object and executes a callback function for each property (if it exists)
* This is a safe way to iterate over objects if another script has modified the object prototype
*/
utils.foreach = function(aData, fnEach) {
var key, val;
for (key in aData) {
if (utils.typeOf(aData.hasOwnProperty) === 'function') {
if (aData.hasOwnProperty(key)) {
val = aData[key];
fnEach(key, val);
}
} else {
// IE8 has a problem looping through XML nodes
val = aData[key];
fnEach(key, val);
}
}
};
/** Determines if the current page is HTTPS **/
utils.isHTTPS = function() {
return (window.location.href.indexOf('https') === 0);
};
/** Gets the repository location **/
utils.repo = function() {
var repo = 'http://p.jwpcdn.com/' + jwplayer.version.split(/\W/).splice(0, 2).join('/') + '/';
try {
if (utils.isHTTPS()) {
repo = repo.replace('http://', 'https://ssl.');
}
} catch (e) {}
return repo;
};
utils.versionCheck = function(target) {
var tParts = ('0'+target).split(/\W/);
var jParts = jwplayer.version.split(/\W/);
var tMajor = parseFloat(tParts[0]);
var jMajor = parseFloat(jParts[0]);
if (tMajor > jMajor) {
return false;
} else if (tMajor === jMajor) {
if (parseFloat('0'+tParts[1]) > parseFloat(jParts[1])) {
return false;
}
}
return true;
};
/** Loads an XML file into a DOM object * */
utils.ajax = function(xmldocpath, completecallback, errorcallback, donotparse) {
var xmlhttp;
var isError = false;
// Hash tags should be removed from the URL since they can't be loaded in IE
if (xmldocpath.indexOf('#') > 0) {
xmldocpath = xmldocpath.replace(/#.*$/, '');
}
if (_isCrossdomain(xmldocpath) && utils.exists(window.XDomainRequest)) {
// IE8 / 9
xmlhttp = new window.XDomainRequest();
xmlhttp.onload = _ajaxComplete(xmlhttp, xmldocpath, completecallback, errorcallback, donotparse);
xmlhttp.ontimeout = xmlhttp.onprogress = function() {};
xmlhttp.timeout = 5000;
} else if (utils.exists(window.XMLHttpRequest)) {
// Firefox, Chrome, Opera, Safari
xmlhttp = new window.XMLHttpRequest();
xmlhttp.onreadystatechange =
_readyStateChangeHandler(xmlhttp, xmldocpath, completecallback, errorcallback, donotparse);
} else {
if (errorcallback) {
errorcallback('', xmldocpath, xmlhttp);
}
return xmlhttp;
}
if (xmlhttp.overrideMimeType) {
xmlhttp.overrideMimeType('text/xml');
}
xmlhttp.onerror = _ajaxError(errorcallback, xmldocpath, xmlhttp);
try {
xmlhttp.open('GET', xmldocpath, true);
} catch (error) {
isError = true;
}
// make XDomainRequest asynchronous:
setTimeout(function() {
if (isError) {
if (errorcallback) {
errorcallback(xmldocpath, xmldocpath, xmlhttp);
}
return;
}
try {
xmlhttp.send();
} catch (error) {
if (errorcallback) {
errorcallback(xmldocpath, xmldocpath, xmlhttp);
}
}
}, 0);
return xmlhttp;
};
function _isCrossdomain(path) {
return (path && path.indexOf('://') >= 0) &&
(path.split('/')[2] !== window.location.href.split('/')[2]);
}
function _ajaxError(errorcallback, xmldocpath, xmlhttp) {
return function() {
errorcallback('Error loading file', xmldocpath, xmlhttp);
};
}
function _readyStateChangeHandler(xmlhttp, xmldocpath, completecallback, errorcallback, donotparse) {
return function() {
if (xmlhttp.readyState === 4) {
switch (xmlhttp.status) {
case 200:
_ajaxComplete(xmlhttp, xmldocpath, completecallback, errorcallback, donotparse)();
break;
case 404:
errorcallback('File not found', xmldocpath, xmlhttp);
}
}
};
}
function _ajaxComplete(xmlhttp, xmldocpath, completecallback, errorcallback, donotparse) {
return function() {
// Handle the case where an XML document was returned with an incorrect MIME type.
var xml, firstChild;
if (donotparse) {
completecallback(xmlhttp);
} else {
try {
// This will throw an error on Windows Mobile 7.5.
// We want to trigger the error so that we can move down to the next section
xml = xmlhttp.responseXML;
if (xml) {
firstChild = xml.firstChild;
if (xml.lastChild && xml.lastChild.nodeName === 'parsererror') {
if (errorcallback) {
errorcallback('Invalid XML', xmldocpath, xmlhttp);
}
return;
}
}
} catch (e) {}
if (xml && firstChild) {
return completecallback(xmlhttp);
}
var parsedXML = utils.parseXML(xmlhttp.responseText);
if (parsedXML && parsedXML.firstChild) {
xmlhttp = utils.extend({}, xmlhttp, {
responseXML: parsedXML
});
} else {
if (errorcallback) {
errorcallback(xmlhttp.responseText ? 'Invalid XML' : xmldocpath, xmldocpath, xmlhttp);
}
return;
}
completecallback(xmlhttp);
}
};
}
/** Takes an XML string and returns an XML object **/
utils.parseXML = function(input) {
var parsedXML;
try {
// Parse XML in FF/Chrome/Safari/Opera
if (window.DOMParser) {
parsedXML = (new window.DOMParser()).parseFromString(input, 'text/xml');
if (parsedXML.childNodes && parsedXML.childNodes.length &&
parsedXML.childNodes[0].firstChild.nodeName === 'parsererror') {
return;
}
} else {
// Internet Explorer
parsedXML = new window.ActiveXObject('Microsoft.XMLDOM');
parsedXML.async = 'false';
parsedXML.loadXML(input);
}
} catch (e) {
return;
}
return parsedXML;
};
/**
* Ensure a number is between two bounds
*/
utils.between = function(num, min, max) {
return Math.max(Math.min(num, max), min);
};
/**
* Convert a time-representing string to a number.
*
* @param {String} The input string. Supported are 00:03:00.1 / 03:00.1 / 180.1s / 3.2m / 3.2h
* @return {Number} The number of seconds.
*/
utils.seconds = function(str) {
if (_.isNumber(str)) {
return str;
}
str = str.replace(',', '.');
var arr = str.split(':');
var sec = 0;
if (str.slice(-1) === 's') {
sec = parseFloat(str);
} else if (str.slice(-1) === 'm') {
sec = parseFloat(str) * 60;
} else if (str.slice(-1) === 'h') {
sec = parseFloat(str) * 3600;
} else if (arr.length > 1) {
sec = parseFloat(arr[arr.length - 1]);
sec += parseFloat(arr[arr.length - 2]) * 60;
if (arr.length === 3) {
sec += parseFloat(arr[arr.length - 3]) * 3600;
}
} else {
sec = parseFloat(str);
}
return sec;
};
/**
* Basic serialization: string representations of booleans and numbers are
* returned typed
*
* @param {String}
* val String value to serialize.
* @return {Object} The original value in the correct primitive type.
*/
utils.serialize = function(val) {
if (val === null) {
return null;
} else if (val.toString().toLowerCase() === 'true') {
return true;
} else if (val.toString().toLowerCase() === 'false') {
return false;
} else if (isNaN(Number(val)) || val.length > 5 || val.length === 0) {
return val;
} else {
return Number(val);
}
};
utils.addClass = function(element, classes) {
// TODO:: use _.union on the two arrays
var originalClasses = _.isString(element.className) ? element.className.split(' ') : [];
var addClasses = _.isArray(classes) ? classes : classes.split(' ');
_.each(addClasses, function(c) {
if (! _.contains(originalClasses, c)) {
originalClasses.push(c);
}
});
element.className = utils.trim(originalClasses.join(' '));
};
utils.removeClass = function(element, c) {
var originalClasses = _.isString(element.className) ? element.className.split(' ') : [];
var removeClasses = _.isArray(c) ? c : c.split(' ');
element.className = utils.trim(_.difference(originalClasses, removeClasses).join(' '));
};
utils.emptyElement = function(element) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
};
utils.indexOf = _.indexOf;
utils.noop = function() {};
utils.canCast = function() {
var cast = jwplayer.cast;
return !!(cast && _.isFunction(cast.available) && cast.available());
};
})(jwplayer);
(function(jwplayer) {
var utils = jwplayer.utils,
MAX_CSS_RULES = 50000,
_styleSheets = {},
_styleSheet,
_rules = {},
_cssBlock = null,
_ruleIndexes = {},
_debug = false;
function _createStylesheet(debugText) {
var styleSheet = document.createElement('style');
if (debugText) {
styleSheet.appendChild(document.createTextNode(debugText));
}
styleSheet.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(styleSheet);
return styleSheet;
}
utils.cssKeyframes = function(keyframeName, keyframeSteps) {
var styleElement = _styleSheets.keyframes;
if (!styleElement) {
styleElement = _createStylesheet();
_styleSheets.keyframes = styleElement;
}
var sheet = styleElement.sheet;
var rulesText = '@keyframes ' + keyframeName + ' { ' + keyframeSteps + ' }';
_insertRule(sheet, rulesText, sheet.cssRules.length);
_insertRule(sheet, rulesText.replace(/(keyframes|transform)/g, '-webkit-$1'), sheet.cssRules.length);
};
var _css = utils.css = function(selector, styles, important) {
important = important || false;
if (!_rules[selector]) {
_rules[selector] = {};
}
if (!_updateStyles(_rules[selector], styles, important)) {
//no change in css
return;
}
if (_debug) {
// add a new style sheet with css text and exit
if (_styleSheets[selector]) {
_styleSheets[selector].parentNode.removeChild(_styleSheets[selector]);
}
_styleSheets[selector] = _createStylesheet(_getRuleText(selector));
return;
}
if (!_styleSheets[selector]) {
// set stylesheet for selector
var numberRules = _styleSheet && _styleSheet.sheet && _styleSheet.sheet.cssRules &&
_styleSheet.sheet.cssRules.length || 0;
if (!_styleSheet || numberRules > MAX_CSS_RULES) {
_styleSheet = _createStylesheet();
}
_styleSheets[selector] = _styleSheet;
}
if (_cssBlock !== null) {
_cssBlock.styleSheets[selector] = _rules[selector];
// finish this later
return;
}
_updateStylesheet(selector);
};
_css.style = function(elements, styles, immediate) {
if (elements === undefined || elements === null) {
//utils.log('css.style invalid elements: '+ elements +' '+ JSON.stringify(styles) +' '+ immediate);
return;
}
if (elements.length === undefined) {
elements = [elements];
}
var cssRules = {};
_updateStyleAttributes(cssRules, styles);
if (_cssBlock !== null && !immediate) {
elements.__cssRules = _extend(elements.__cssRules, cssRules);
if (jwplayer._.indexOf(_cssBlock.elements, elements) < 0) {
_cssBlock.elements.push(elements);
}
// finish this later
return;
}
_updateElementsStyle(elements, cssRules);
};
_css.block = function(id) {
// use id so that the first blocker gets to unblock
if (_cssBlock === null) {
// console.time('block_'+id);
_cssBlock = {
id: id,
styleSheets: {},
elements: []
};
}
};
_css.unblock = function(id) {
if (_cssBlock && (!id || _cssBlock.id === id)) {
// IE9 limits the number of style tags in the head, so we need to update the entire stylesheet each time
for (var selector in _cssBlock.styleSheets) {
_updateStylesheet(selector);
}
for (var i = 0; i < _cssBlock.elements.length; i++) {
var elements = _cssBlock.elements[i];
_updateElementsStyle(elements, elements.__cssRules);
}
_cssBlock = null;
// console.timeEnd('block_'+id);
}
};
function _extend(target, source) {
target = target || {};
for (var prop in source) {
target[prop] = source[prop];
}
return target;
}
function _updateStyles(cssRules, styles, important) {
var dirty = false,
style, val;
for (style in styles) {
val = _styleValue(style, styles[style], important);
if (val !== '') {
if (val !== cssRules[style]) {
cssRules[style] = val;
dirty = true;
}
} else if (cssRules[style] !== undefined) {
delete cssRules[style];
dirty = true;
}
}
return dirty;
}
function _updateStyleAttributes(cssRules, styles) {
for (var style in styles) {
cssRules[style] = _styleValue(style, styles[style]);
}
}
function _styleAttributeName(name) {
name = name.split('-');
for (var i = 1; i < name.length; i++) {
name[i] = name[i].charAt(0).toUpperCase() + name[i].slice(1);
}
return name.join('');
}
function _styleValue(style, value, important) {
if (!utils.exists(value)) {
return '';
}
var importantString = important ? ' !important' : '';
//string
if (typeof value === 'string' && isNaN(value)) {
if ((/png|gif|jpe?g/i).test(value) && value.indexOf('url') < 0) {
return 'url(' + value + ')';
}
return value + importantString;
}
// number
if (value === 0 ||
style === 'z-index' ||
style === 'opacity') {
return '' + value + importantString;
}
if ((/color/i).test(style)) {
return '#' + utils.pad(value.toString(16).replace(/^0x/i, ''), 6) + importantString;
}
return Math.ceil(value) + 'px' + importantString;
}
function _updateElementsStyle(elements, cssRules) {
for (var i = 0; i < elements.length; i++) {
var element = elements[i],
style, styleName;
if (element !== undefined && element !== null) {
for (style in cssRules) {
styleName = _styleAttributeName(style);
if (element.style[styleName] !== cssRules[style]) {
element.style[styleName] = cssRules[style];
}
}
}
}
}
function _updateStylesheet(selector) {
var sheet = _styleSheets[selector].sheet,
cssRules,
ruleIndex,
ruleText;
if (sheet) {
cssRules = sheet.cssRules;
ruleIndex = _ruleIndexes[selector];
ruleText = _getRuleText(selector);
if (ruleIndex !== undefined && ruleIndex < cssRules.length &&
cssRules[ruleIndex].selectorText === selector) {
if (ruleText === cssRules[ruleIndex].cssText) {
//no update needed
return;
}
sheet.deleteRule(ruleIndex);
} else {
ruleIndex = cssRules.length;
_ruleIndexes[selector] = ruleIndex;
}
_insertRule(sheet, ruleText, ruleIndex);
}
}
function _insertRule(sheet, text, index) {
try {
sheet.insertRule(text, index);
} catch (e) {
//console.log(e.message, text);
}
}
function _getRuleText(selector) {
var styles = _rules[selector];
selector += ' { ';
for (var style in styles) {
selector += style + ': ' + styles[style] + '; ';
}
return selector + '}';
}
// Removes all css elements which match a particular style
utils.clearCss = function(filter) {
for (var rule in _rules) {
if (rule.indexOf(filter) >= 0) {
delete _rules[rule];
}
}
for (var selector in _styleSheets) {
if (selector.indexOf(filter) >= 0) {
_updateStylesheet(selector);
}
}
};
utils.transform = function(element, value) {
var transform = 'transform',
style = {};
value = value || '';
style[transform] = value;
style['-webkit-' + transform] = value;
style['-ms-' + transform] = value;
style['-moz-' + transform] = value;
style['-o-' + transform] = value;
if (typeof element === 'string') {
_css(element, style);
} else {
_css.style(element, style);
}
};
utils.dragStyle = function(selector, style) {
_css(selector, {
'-webkit-user-select': style,
'-moz-user-select': style,
'-ms-user-select': style,
'-webkit-user-drag': style,
'user-select': style,
'user-drag': style
});
};
utils.transitionStyle = function(selector, style) {
// Safari 5 has problems with CSS3 transitions
if (navigator.userAgent.match(/5\.\d(\.\d)? safari/i)) {
return;
}
_css(selector, {
'-webkit-transition': style,
'-moz-transition': style,
'-o-transition': style,
transition: style
});
};
utils.rotate = function(domelement, deg) {
utils.transform(domelement, 'rotate(' + deg + 'deg)');
};
utils.rgbHex = function(color) {
var hex = String(color).replace('#', '');
if (hex.length === 3) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
return '#' + hex.substr(-6);
};
utils.hexToRgba = function(hexColor, opacity) {
var style = 'rgb';
var channels = [
parseInt(hexColor.substr(1, 2), 16),
parseInt(hexColor.substr(3, 2), 16),
parseInt(hexColor.substr(5, 2), 16)
];
if (opacity !== undefined && opacity !== 100) {
style += 'a';
channels.push(opacity / 100);
}
return style + '(' + channels.join(',') + ')';
};
})(jwplayer);
(function(utils) {
var video = 'video/',
audio = 'audio/',
mp4 = 'mp4',
webm = 'webm',
ogg = 'ogg',
aac = 'aac',
mp3 = 'mp3',
vorbis = 'vorbis',
_ = jwplayer._,
_foreach = utils.foreach,
mimeMap = {
mp4: video + mp4,
ogg: video + ogg,
oga: audio + ogg,
vorbis: audio + ogg,
webm: video + webm,
aac: audio + mp4,
mp3: audio + 'mpeg',
hls: 'application/vnd.apple.mpegurl'
},
html5Extensions = {
'mp4': mimeMap[mp4],
'f4v': mimeMap[mp4],
'm4v': mimeMap[mp4],
'mov': mimeMap[mp4],
'm4a': mimeMap[aac],
'f4a': mimeMap[aac],
'aac': mimeMap[aac],
'mp3': mimeMap[mp3],
'ogv': mimeMap[ogg],
'ogg': mimeMap[ogg],
'oga': mimeMap[vorbis],
'vorbis': mimeMap[vorbis],
'webm': mimeMap[webm],
'm3u8': mimeMap.hls,
'm3u': mimeMap.hls,
'hls': mimeMap.hls
},
videoX = 'video',
flashExtensions = {
'flv': videoX,
'f4v': videoX,
'mov': videoX,
'm4a': videoX,
'm4v': videoX,
'mp4': videoX,
'aac': videoX,
'f4a': videoX,
'mp3': 'sound',
'smil': 'rtmp',
'm3u8': 'hls',
'hls': 'hls'
};
var _extensionmap = utils.extensionmap = {};
_foreach(html5Extensions, function(ext, val) {
_extensionmap[ext] = {
html5: val
};
});
_foreach(flashExtensions, function(ext, val) {
if (!_extensionmap[ext]) {
_extensionmap[ext] = {};
}
_extensionmap[ext].flash = val;
});
_extensionmap.types = mimeMap;
_extensionmap.mimeType = function(mime) {
// return the first mime that matches
var returnType;
_.find(mimeMap, function(val, key) {
if (val === mime) {
returnType = key;
return true;
}
});
return returnType;
};
_extensionmap.extType = function(extension) {
return _extensionmap.mimeType(html5Extensions[extension]);
};
})(jwplayer.utils);
(function(utils) {
var _loaderstatus = utils.loaderstatus = {
NEW: 0,
LOADING: 1,
ERROR: 2,
COMPLETE: 3
};
utils.scriptloader = function(url) {
var _events = jwplayer.events,
_this = utils.extend(this, new _events.eventdispatcher()),
_status = _loaderstatus.NEW;
this.load = function() {
// Only execute on the first run
if (_status !== _loaderstatus.NEW) {
return;
}
// If we already have a scriptloader loading the same script, don't create a new one;
var sameLoader = utils.scriptloader.loaders[url];
if (sameLoader) {
_status = sameLoader.getStatus();
if (_status < 2) {
// dispatch to this instances listeners when the first loader gets updates
sameLoader.addEventListener(_events.ERROR, _sendError);
sameLoader.addEventListener(_events.COMPLETE, _sendComplete);
return;
}
// already errored or loaded... keep going?
}
var head = document.getElementsByTagName('head')[0] || document.documentElement;
var scriptTag = document.createElement('script');
var done = false;
scriptTag.onload = scriptTag.onreadystatechange = function(evt) {
if (!done &&
(!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) {
done = true;
_sendComplete(evt);
// Handle memory leak in IE
scriptTag.onload = scriptTag.onreadystatechange = null;
if (head && scriptTag.parentNode) {
head.removeChild(scriptTag);
}
}
};
scriptTag.onerror = _sendError;
scriptTag.src = url;
head.insertBefore(scriptTag, head.firstChild);
_status = _loaderstatus.LOADING;
utils.scriptloader.loaders[url] = this;
};
function _sendError(evt) {
_status = _loaderstatus.ERROR;
_this.sendEvent(_events.ERROR, evt);
}
function _sendComplete(evt) {
_status = _loaderstatus.COMPLETE;
_this.sendEvent(_events.COMPLETE, evt);
}
this.getStatus = function() {
return _status;
};
};
utils.scriptloader.loaders = {};
})(jwplayer.utils);
/**
* String utilities for the JW Player.
*
* @version 6.0
*/
(function(utils) {
/** Removes whitespace from the beginning and end of a string **/
utils.trim = function(inputString) {
return inputString.replace(/^\s+|\s+$/g, '');
};
/**
* Pads a string
* @param {String} string
* @param {Number} length
* @param {String} padder
*/
utils.pad = function(str, length, padder) {
if (!padder) {
padder = '0';
}
while (str.length < length) {
str = padder + str;
}
return str;
};
/**
* Get the value of a case-insensitive attribute in an XML node
* @param {XML} xml
* @param {String} attribute
* @return {String} Value
*/
utils.xmlAttribute = function(xml, attribute) {
for (var attrib = 0; attrib < xml.attributes.length; attrib++) {
if (xml.attributes[attrib].name && xml.attributes[attrib].name.toLowerCase() === attribute.toLowerCase()) {
return xml.attributes[attrib].value.toString();
}
}
return '';
};
/**
* This does not return the file extension, instead it returns a media type extension
*/
function getAzureFileFormat(path) {
if (path.indexOf('(format=m3u8-') > -1) {
return 'm3u8';
} else {
return false;
}
}
utils.extension = function(path) {
if (!path || path.substr(0, 4) === 'rtmp') {
return '';
}
var azureFormat = getAzureFileFormat(path);
if (azureFormat) {
return azureFormat;
}
path = path.substring(path.lastIndexOf('/') + 1, path.length).split('?')[0].split('#')[0];
if (path.lastIndexOf('.') > -1) {
return path.substr(path.lastIndexOf('.') + 1, path.length).toLowerCase();
}
};
/** Convert a string representation of a string to an integer **/
utils.stringToColor = function(value) {
value = value.replace(/(#|0x)?([0-9A-F]{3,6})$/gi, '$2');
if (value.length === 3) {
value = value.charAt(0) + value.charAt(0) + value.charAt(1) +
value.charAt(1) + value.charAt(2) + value.charAt(2);
}
return parseInt(value, 16);
};
})(jwplayer.utils);
(function (utils) {
var TOUCH_MOVE = 'touchmove',
TOUCH_START = 'touchstart',
TOUCH_END = 'touchend',
TOUCH_CANCEL = 'touchcancel';
utils.touch = function (elem) {
var _elem = elem,
_isListening = false,
_handlers = {},
_startEvent = null,
_gotMove = false,
_events = utils.touchEvents;
document.addEventListener(TOUCH_MOVE, touchHandler);
document.addEventListener(TOUCH_END, documentEndHandler);
document.addEventListener(TOUCH_CANCEL, touchHandler);
elem.addEventListener(TOUCH_START, touchHandler);
elem.addEventListener(TOUCH_END, touchHandler);
function documentEndHandler(evt) {
if (_isListening) {
if (_gotMove) {
triggerEvent(_events.DRAG_END, evt);
}
}
_gotMove = false;
_isListening = false;
_startEvent = null;
}
function touchHandler(evt) {
if (evt.type === TOUCH_START) {
_isListening = true;
_startEvent = createEvent(_events.DRAG_START, evt);
}
else if (evt.type === TOUCH_MOVE) {
if (_isListening) {
if (_gotMove) {
triggerEvent(_events.DRAG, evt);
}
else {
triggerEvent(_events.DRAG_START, evt, _startEvent);
_gotMove = true;
triggerEvent(_events.DRAG, evt);
}
}
}
else {
if (_isListening) {
if (_gotMove) {
triggerEvent(_events.DRAG_END, evt);
}
else {
// This allows the controlbar/dock/logo tap events not to be forwarded to the view
evt.cancelBubble = true;
triggerEvent(_events.TAP, evt);
}
}
_gotMove = false;
_isListening = false;
_startEvent = null;
}
}
function triggerEvent(type, srcEvent, finalEvt) {
if (_handlers[type]) {
preventDefault(srcEvent);
var evt = finalEvt ? finalEvt : createEvent(type, srcEvent);
if (evt) {
_handlers[type](evt);
}
}
}
function createEvent(type, srcEvent) {
var touch = null;
if (srcEvent.touches && srcEvent.touches.length) {
touch = srcEvent.touches[0];
}
else if (srcEvent.changedTouches && srcEvent.changedTouches.length) {
touch = srcEvent.changedTouches[0];
}
if (!touch) {
return null;
}
var rect = _elem.getBoundingClientRect();
var evt = {
type: type,
target: _elem,
x: ((touch.pageX - window.pageXOffset) - rect.left),
y: touch.pageY,
deltaX: 0,
deltaY: 0
};
if (type !== _events.TAP && _startEvent) {
evt.deltaX = evt.x - _startEvent.x;
evt.deltaY = evt.y - _startEvent.y;
}
return evt;
}
function preventDefault(evt) {
if (evt.preventManipulation) {
evt.preventManipulation();
}
if (evt.preventDefault) {
evt.preventDefault();
}
}
this.addEventListener = function (type, handler) {
_handlers[type] = handler;
};
this.removeEventListener = function (type) {
delete _handlers[type];
};
return this;
};
})(jwplayer.utils);(function(utils) {
utils.touchEvents = {
DRAG: 'jwplayerDrag',
DRAG_START: 'jwplayerDragStart',
DRAG_END: 'jwplayerDragEnd',
TAP: 'jwplayerTap'
};
})(jwplayer.utils);
/**
* Event namespace definition for the JW Player
*
* @author pablo
* @version 6.0
*/
(function(jwplayer) {
jwplayer.events = {
// General Events
COMPLETE: 'COMPLETE',
ERROR: 'ERROR',
// API Events
API_READY: 'jwplayerAPIReady',
JWPLAYER_READY: 'jwplayerReady',
JWPLAYER_FULLSCREEN: 'jwplayerFullscreen',
JWPLAYER_RESIZE: 'jwplayerResize',
JWPLAYER_ERROR: 'jwplayerError',
JWPLAYER_SETUP_ERROR: 'jwplayerSetupError',
// Media Events
JWPLAYER_MEDIA_BEFOREPLAY: 'jwplayerMediaBeforePlay',
JWPLAYER_MEDIA_BEFORECOMPLETE: 'jwplayerMediaBeforeComplete',
JWPLAYER_MEDIA_BUFFER: 'jwplayerMediaBuffer',
JWPLAYER_MEDIA_BUFFER_FULL: 'jwplayerMediaBufferFull',
JWPLAYER_MEDIA_ERROR: 'jwplayerMediaError',
JWPLAYER_MEDIA_LOADED: 'jwplayerMediaLoaded',
JWPLAYER_MEDIA_COMPLETE: 'jwplayerMediaComplete',
JWPLAYER_MEDIA_SEEK: 'jwplayerMediaSeek',
JWPLAYER_MEDIA_TIME: 'jwplayerMediaTime',
JWPLAYER_MEDIA_VOLUME: 'jwplayerMediaVolume',
JWPLAYER_MEDIA_META: 'jwplayerMediaMeta',
JWPLAYER_MEDIA_MUTE: 'jwplayerMediaMute',
JWPLAYER_AUDIO_TRACKS: 'jwplayerAudioTracks',
JWPLAYER_AUDIO_TRACK_CHANGED: 'jwplayerAudioTrackChanged',
JWPLAYER_MEDIA_LEVELS: 'jwplayerMediaLevels',
JWPLAYER_MEDIA_LEVEL_CHANGED: 'jwplayerMediaLevelChanged',
JWPLAYER_CAPTIONS_CHANGED: 'jwplayerCaptionsChanged',
JWPLAYER_CAPTIONS_LIST: 'jwplayerCaptionsList',
JWPLAYER_CAPTIONS_LOADED: 'jwplayerCaptionsLoaded',
// State events
JWPLAYER_PLAYER_STATE: 'jwplayerPlayerState',
state: {
BUFFERING: 'BUFFERING',
IDLE: 'IDLE',
PAUSED: 'PAUSED',
PLAYING: 'PLAYING'
},
// Playlist Events
JWPLAYER_PLAYLIST_LOADED: 'jwplayerPlaylistLoaded',
JWPLAYER_PLAYLIST_ITEM: 'jwplayerPlaylistItem',
JWPLAYER_PLAYLIST_COMPLETE: 'jwplayerPlaylistComplete',
// Display CLick
JWPLAYER_DISPLAY_CLICK: 'jwplayerViewClick',
JWPLAYER_PROVIDER_CLICK: 'jwplayerProviderClick',
JWPLAYER_VIEW_TAB_FOCUS: 'jwplayerViewTabFocus',
// Controls show/hide
JWPLAYER_CONTROLS: 'jwplayerViewControls',
JWPLAYER_USER_ACTION: 'jwplayerUserAction',
// Instream events
JWPLAYER_INSTREAM_CLICK: 'jwplayerInstreamClicked',
JWPLAYER_INSTREAM_DESTROYED: 'jwplayerInstreamDestroyed',
// Ad events
JWPLAYER_AD_TIME: 'jwplayerAdTime',
JWPLAYER_AD_ERROR: 'jwplayerAdError',
JWPLAYER_AD_CLICK: 'jwplayerAdClicked',
JWPLAYER_AD_COMPLETE: 'jwplayerAdComplete',
JWPLAYER_AD_IMPRESSION: 'jwplayerAdImpression',
JWPLAYER_AD_COMPANIONS: 'jwplayerAdCompanions',
JWPLAYER_AD_SKIPPED: 'jwplayerAdSkipped',
JWPLAYER_AD_PLAY: 'jwplayerAdPlay',
JWPLAYER_AD_PAUSE: 'jwplayerAdPause',
JWPLAYER_AD_META: 'jwplayerAdMeta',
// Casting
JWPLAYER_CAST_AVAILABLE: 'jwplayerCastAvailable',
JWPLAYER_CAST_SESSION: 'jwplayerCastSession',
JWPLAYER_CAST_AD_CHANGED: 'jwplayerCastAdChanged'
};
})(jwplayer);
(function(jwplayer) {
var events = jwplayer.events,
_utils = jwplayer.utils;
events.eventdispatcher = function(id, debug) {
var _id = id,
_debug = debug,
_listeners,
_globallisteners;
/** Clears all event listeners **/
this.resetEventListeners = function() {
_listeners = {};
_globallisteners = [];
};
this.resetEventListeners();
/** Add an event listener for a specific type of event. **/
this.addEventListener = function(type, listener, count) {
try {
if (!_utils.exists(_listeners[type])) {
_listeners[type] = [];
}
if (_utils.typeOf(listener) === 'string') {
/*jshint evil:true*/
listener = (new Function('return ' + listener))();
}
_listeners[type].push({
listener: listener,
count: count || null
});
} catch (err) {
_utils.log('error', err);
}
return false;
};
/** Remove an event listener for a specific type of event. **/
this.removeEventListener = function(type, listener) {
var listenerIndex;
if (!_listeners[type]) {
return;
}
try {
if (listener === undefined) {
_listeners[type] = [];
return;
}
for (listenerIndex = 0; listenerIndex < _listeners[type].length; listenerIndex++) {
if (_listeners[type][listenerIndex].listener.toString() === listener.toString()) {
_listeners[type].splice(listenerIndex, 1);
break;
}
}
} catch (err) {
_utils.log('error', err);
}
return false;
};
/** Add an event listener for all events. **/
this.addGlobalListener = function(listener, count) {
try {
if (_utils.typeOf(listener) === 'string') {
/*jshint evil:true*/
listener = (new Function('return ' + listener))();
}
_globallisteners.push({
listener: listener,
count: count || null
});
} catch (err) {
_utils.log('error', err);
}
return false;
};
/** Add an event listener for all events. **/
this.removeGlobalListener = function(listener) {
if (!listener) {
return;
}
try {
for (var index = _globallisteners.length; index--;) {
if (_globallisteners[index].listener.toString() === listener.toString()) {
_globallisteners.splice(index, 1);
}
}
} catch (err) {
_utils.log('error', err);
}
return false;
};
/** Send an event **/
this.sendEvent = function(type, data) {
if (!_utils.exists(data)) {
data = {};
}
_utils.extend(data, {
id: _id,
version: jwplayer.version,
type: type
});
if (_debug) {
_utils.log(type, data);
}
dispatchEvent(_listeners[type], data, type);
dispatchEvent(_globallisteners, data, type);
};
function dispatchEvent(listeners, data, type) {
if (!listeners) {
return;
}
for (var index = 0; index < listeners.length; index++) {
var listener = listeners[index];
if (listener) {
if (listener.count !== null && --listener.count === 0) {
delete listeners[index];
}
try {
listener.listener(data);
} catch (err) {
_utils.log('Error handling "' + type +
'" event listener [' + index + ']: ' + err.toString(), listener.listener, data);
}
}
}
}
};
})(window.jwplayer);
/**
* Plugin package definition
* @author zach
* @version 5.5
*/
(function(jwplayer) {
var _plugins = {},
_pluginLoaders = {};
jwplayer.plugins = function() {};
jwplayer.plugins.loadPlugins = function(id, config) {
_pluginLoaders[id] = new jwplayer.plugins.pluginloader(new jwplayer.plugins.model(_plugins), config);
return _pluginLoaders[id];
};
jwplayer.plugins.registerPlugin = function(id, target, arg1, arg2) {
var pluginId = jwplayer.utils.getPluginName(id);
if (!_plugins[pluginId]) {
_plugins[pluginId] = new jwplayer.plugins.plugin(id);
}
_plugins[pluginId].registerPlugin(id, target, arg1, arg2);
};
})(jwplayer);
(function(jwplayer) {
jwplayer.plugins.model = function(plugins) {
this.addPlugin = function(url) {
var pluginName = jwplayer.utils.getPluginName(url);
if (!plugins[pluginName]) {
plugins[pluginName] = new jwplayer.plugins.plugin(url);
}
return plugins[pluginName];
};
this.getPlugins = function() {
return plugins;
};
};
})(jwplayer);
(function(plugins) {
var utils = jwplayer.utils,
events = jwplayer.events,
UNDEFINED = 'undefined';
plugins.pluginmodes = {
FLASH: 0,
JAVASCRIPT: 1,
HYBRID: 2
};
plugins.plugin = function(url) {
var _status = utils.loaderstatus.NEW,
_flashPath,
_js,
_target,
_completeTimeout;
var _eventDispatcher = new events.eventdispatcher();
utils.extend(this, _eventDispatcher);
function getJSPath() {
switch (utils.getPluginPathType(url)) {
case utils.pluginPathType.ABSOLUTE:
return url;
case utils.pluginPathType.RELATIVE:
return utils.getAbsolutePath(url, window.location.href);
}
}
function completeHandler() {
_completeTimeout = setTimeout(function() {
_status = utils.loaderstatus.COMPLETE;
_eventDispatcher.sendEvent(events.COMPLETE);
}, 1000);
}
function errorHandler() {
_status = utils.loaderstatus.ERROR;
_eventDispatcher.sendEvent(events.ERROR, {url: url});
}
this.load = function() {
if (_status === utils.loaderstatus.NEW) {
if (url.lastIndexOf('.swf') > 0) {
_flashPath = url;
_status = utils.loaderstatus.COMPLETE;
_eventDispatcher.sendEvent(events.COMPLETE);
return;
} else if (utils.getPluginPathType(url) === utils.pluginPathType.CDN) {
_status = utils.loaderstatus.COMPLETE;
_eventDispatcher.sendEvent(events.COMPLETE);
return;
}
_status = utils.loaderstatus.LOADING;
var _loader = new utils.scriptloader(getJSPath());
// Complete doesn't matter - we're waiting for registerPlugin
_loader.addEventListener(events.COMPLETE, completeHandler);
_loader.addEventListener(events.ERROR, errorHandler);
_loader.load();
}
};
this.registerPlugin = function(id, target, arg1, arg2) {
if (_completeTimeout) {
clearTimeout(_completeTimeout);
_completeTimeout = undefined;
}
_target = target;
if (arg1 && arg2) {
_flashPath = arg2;
_js = arg1;
} else if (typeof arg1 === 'string') {
_flashPath = arg1;
} else if (typeof arg1 === 'function') {
_js = arg1;
} else if (!arg1 && !arg2) {
_flashPath = id;
}
_status = utils.loaderstatus.COMPLETE;
_eventDispatcher.sendEvent(events.COMPLETE);
};
this.getStatus = function() {
return _status;
};
this.getPluginName = function() {
return utils.getPluginName(url);
};
this.getFlashPath = function() {
if (_flashPath) {
switch (utils.getPluginPathType(_flashPath)) {
case utils.pluginPathType.ABSOLUTE:
return _flashPath;
case utils.pluginPathType.RELATIVE:
if (url.lastIndexOf('.swf') > 0) {
return utils.getAbsolutePath(_flashPath, window.location.href);
}
return utils.getAbsolutePath(_flashPath, getJSPath());
// case utils.pluginPathType.CDN:
// if (_flashPath.indexOf('-') > -1){
// return _flashPath+'h';
// }
// return _flashPath+'-h';
}
}
return null;
};
this.getJS = function() {
return _js;
};
this.getTarget = function() {
return _target;
};
this.getPluginmode = function() {
if (typeof _flashPath !== UNDEFINED && typeof _js !== UNDEFINED) {
return plugins.pluginmodes.HYBRID;
} else if (typeof _flashPath !== UNDEFINED) {
return plugins.pluginmodes.FLASH;
} else if (typeof _js !== UNDEFINED) {
return plugins.pluginmodes.JAVASCRIPT;
}
};
this.getNewInstance = function(api, config, div) {
return new _js(api, config, div);
};
this.getURL = function() {
return url;
};
};
})(jwplayer.plugins);
(function(jwplayer) {
var utils = jwplayer.utils,
events = jwplayer.events,
_ = jwplayer._,
_foreach = utils.foreach;
jwplayer.plugins.pluginloader = function(model, config) {
var _status = utils.loaderstatus.NEW,
_loading = false,
_iscomplete = false,
_config = config,
_pluginCount = _.size(_config),
_pluginLoaded,
_destroyed = false,
_eventDispatcher = new events.eventdispatcher();
utils.extend(this, _eventDispatcher);
/*
* Plugins can be loaded by multiple players on the page, but all of them use
* the same plugin model singleton. This creates a race condition because
* multiple players are creating and triggering loads, which could complete
* at any time. We could have some really complicated logic that deals with
* this by checking the status when it's created and / or having the loader
* redispatch its current status on load(). Rather than do this, we just check
* for completion after all of the plugins have been created. If all plugins
* have been loaded by the time checkComplete is called, then the loader is
* done and we fire the complete event. If there are new loads, they will
* arrive later, retriggering the completeness check and triggering a complete
* to fire, if necessary.
*/
function _complete() {
if (!_iscomplete) {
_iscomplete = true;
_status = utils.loaderstatus.COMPLETE;
_eventDispatcher.sendEvent(events.COMPLETE);
}
}
// This is not entirely efficient, but it's simple
function _checkComplete() {
// Since we do not remove event listeners on pluginObj when destroying
if (_destroyed) {
return;
}
if (!_config || _.keys(_config).length === 0) {
_complete();
}
if (!_iscomplete) {
var plugins = model.getPlugins();
_pluginLoaded = _.after(_pluginCount, _complete);
utils.foreach(_config, function(plugin) {
var pluginName = utils.getPluginName(plugin),
pluginObj = plugins[pluginName],
js = pluginObj.getJS(),
target = pluginObj.getTarget(),
status = pluginObj.getStatus();
if (status === utils.loaderstatus.LOADING || status === utils.loaderstatus.NEW) {
return;
} else if (js && !utils.versionCheck(target)) {
_eventDispatcher.sendEvent(events.ERROR, {
message: 'Incompatible player version'
});
}
_pluginLoaded();
});
}
}
function _pluginError(e) {
// Since we do not remove event listeners on pluginObj when destroying
if (_destroyed) {
return;
}
var message = 'File not found';
_eventDispatcher.sendEvent(events.ERROR, {
message: message
});
if (e.url) {
utils.log(message, e.url);
}
_checkComplete();
}
this.setupPlugins = function(api, config, resizer) {
var flashPlugins = {
length: 0,
plugins: {}
},
jsplugins = {
length: 0,
plugins: {}
},
plugins = model.getPlugins();
_foreach(config.plugins, function(plugin, pluginConfig) {
var pluginName = utils.getPluginName(plugin),
pluginObj = plugins[pluginName],
flashPath = pluginObj.getFlashPath(),
jsPlugin = pluginObj.getJS(),
pluginURL = pluginObj.getURL();
if (flashPath) {
flashPlugins.plugins[flashPath] = utils.extend({}, pluginConfig);
flashPlugins.plugins[flashPath].pluginmode = pluginObj.getPluginmode();
flashPlugins.length++;
}
try {
if (jsPlugin && config.plugins && config.plugins[pluginURL]) {
var div = document.createElement('div');
div.id = api.id + '_' + pluginName;
div.style.position = 'absolute';
div.style.top = 0;
div.style.zIndex = jsplugins.length + 10;
jsplugins.plugins[pluginName] = pluginObj.getNewInstance(api,
utils.extend({}, config.plugins[pluginURL]), div);
jsplugins.length++;
api.onReady(resizer(jsplugins.plugins[pluginName], div, true));
api.onResize(resizer(jsplugins.plugins[pluginName], div));
}
} catch (err) {
utils.log('ERROR: Failed to load ' + pluginName + '.');
}
});
api.plugins = jsplugins.plugins;
return flashPlugins;
};
this.load = function() {
// Must be a hash map
if (utils.exists(config) && utils.typeOf(config) !== 'object') {
_checkComplete();
return;
}
_status = utils.loaderstatus.LOADING;
_loading = true;
/** First pass to create the plugins and add listeners **/
_foreach(config, function(plugin) {
if (utils.exists(plugin)) {
var pluginObj = model.addPlugin(plugin);
pluginObj.addEventListener(events.COMPLETE, _checkComplete);
pluginObj.addEventListener(events.ERROR, _pluginError);
}
});
var plugins = model.getPlugins();
/** Second pass to actually load the plugins **/
_foreach(plugins, function(plugin, pluginObj) {
// Plugin object ensures that it's only loaded once
pluginObj.load();
});
_loading = false;
// Make sure we're not hanging around waiting for plugins that already finished loading
_checkComplete();
};
this.destroy = function() {
_destroyed = true;
if (_eventDispatcher) {
_eventDispatcher.resetEventListeners();
_eventDispatcher = null;
}
};
this.pluginFailed = _pluginError;
this.getStatus = function() {
return _status;
};
};
})(jwplayer);
/**
* Parsers namespace declaration
*
* @author pablo
* @version 6.0
*/
(function(jwplayer) {
jwplayer.parsers = {
localName: function(node) {
if (!node) {
return '';
} else if (node.localName) {
return node.localName;
} else if (node.baseName) {
return node.baseName;
} else {
return '';
}
},
textContent: function(node) {
if (!node) {
return '';
} else if (node.textContent) {
return jwplayer.utils.trim(node.textContent);
} else if (node.text) {
return jwplayer.utils.trim(node.text);
} else {
return '';
}
},
getChildNode: function(parent, index) {
return parent.childNodes[index];
},
numChildren: function(parent) {
if (parent.childNodes) {
return parent.childNodes.length;
} else {
return 0;
}
}
};
})(jwplayer);
/**
* Parse a feed item for JWPlayer content.
*
* @author zach
* @modified pablo
* @version 6.0
*/
(function(jwplayer) {
var _parsers = jwplayer.parsers;
var jwparser = _parsers.jwparser = function() {};
var PREFIX = 'jwplayer';
/**
* Parse a feed entry for JWPlayer content.
*
* @param {XML}
* obj The XML object to parse.
* @param {Object}
* itm The playlistentry to amend the object to.
* @return {Object} The playlistentry, amended with the JWPlayer info.
*/
jwparser.parseEntry = function(obj, itm) {
var sources = [],
tracks = [],
_xmlAttribute = jwplayer.utils.xmlAttribute,
def = 'default',
label = 'label',
file = 'file',
type = 'type';
for (var i = 0; i < obj.childNodes.length; i++) {
var node = obj.childNodes[i];
if (node.prefix === PREFIX) {
var _localName = _parsers.localName(node);
if (_localName === 'source') {
delete itm.sources;
sources.push({
file: _xmlAttribute(node, file),
'default': _xmlAttribute(node, def),
label: _xmlAttribute(node, label),
type: _xmlAttribute(node, type)
});
} else if (_localName === 'track') {
delete itm.tracks;
tracks.push({
file: _xmlAttribute(node, file),
'default': _xmlAttribute(node, def),
kind: _xmlAttribute(node, 'kind'),
label: _xmlAttribute(node, label)
});
} else {
itm[_localName] = jwplayer.utils.serialize(_parsers.textContent(node));
if (_localName === 'file' && itm.sources) {
// jwplayer namespace file should override existing source
// (probably set in MediaParser)
delete itm.sources;
}
}
}
if (!itm[file]) {
itm[file] = itm.link;
}
}
if (sources.length) {
itm.sources = [];
for (i = 0; i < sources.length; i++) {
if (sources[i].file.length > 0) {
sources[i][def] = (sources[i][def] === 'true') ? true : false;
if (!sources[i].label.length) {
delete sources[i].label;
}
itm.sources.push(sources[i]);
}
}
}
if (tracks.length) {
itm.tracks = [];
for (i = 0; i < tracks.length; i++) {
if (tracks[i].file.length > 0) {
tracks[i][def] = (tracks[i][def] === 'true') ? true : false;
tracks[i].kind = (!tracks[i].kind.length) ? 'captions' : tracks[i].kind;
if (!tracks[i].label.length) {
delete tracks[i].label;
}
itm.tracks.push(tracks[i]);
}
}
}
return itm;
};
})(jwplayer);
/**
* Parse a MRSS group into a playlistitem (used in RSS and ATOM).
*
* author zach
* modified pablo
* version 6.0
*/
(function(parsers) {
var utils = jwplayer.utils,
_xmlAttribute = utils.xmlAttribute,
_localName = parsers.localName,
_textContent = parsers.textContent,
_numChildren = parsers.numChildren;
var mediaparser = parsers.mediaparser = function() {};
/** Prefix for the MRSS namespace. **/
var PREFIX = 'media';
/**
* Parse a feeditem for Yahoo MediaRSS extensions.
* The 'content' and 'group' elements can nest other MediaRSS elements.
* @param {XML} obj The entire MRSS XML object.
* @param {Object} itm The playlistentry to amend the object to.
* @return {Object} The playlistentry, amended with the MRSS info.
**/
mediaparser.parseGroup = function(obj, itm) {
var node,
i,
tracks = 'tracks',
captions = [];
function getLabel(code) {
var LANGS = {
'zh': 'Chinese',
'nl': 'Dutch',
'en': 'English',
'fr': 'French',
'de': 'German',
'it': 'Italian',
'ja': 'Japanese',
'pt': 'Portuguese',
'ru': 'Russian',
'es': 'Spanish'
};
if (LANGS[code]) {
return LANGS[code];
}
return code;
}
for (i = 0; i < _numChildren(obj); i++) {
node = obj.childNodes[i];
if (node.prefix === PREFIX) {
if (!_localName(node)) {
continue;
}
switch (_localName(node).toLowerCase()) {
case 'content':
//itm['file'] = _xmlAttribute(node, 'url');
if (_xmlAttribute(node, 'duration')) {
itm.duration = utils.seconds(_xmlAttribute(node, 'duration'));
}
if (_numChildren(node) > 0) {
itm = mediaparser.parseGroup(node, itm);
}
if (_xmlAttribute(node, 'url')) {
if (!itm.sources) {
itm.sources = [];
}
itm.sources.push({
file: _xmlAttribute(node, 'url'),
type: _xmlAttribute(node, 'type'),
width: _xmlAttribute(node, 'width'),
label: _xmlAttribute(node, 'label')
});
}
break;
case 'title':
itm.title = _textContent(node);
break;
case 'description':
itm.description = _textContent(node);
break;
case 'guid':
itm.mediaid = _textContent(node);
break;
case 'thumbnail':
if (!itm.image) {
itm.image = _xmlAttribute(node, 'url');
}
break;
case 'player':
// var url = node.url;
break;
case 'group':
mediaparser.parseGroup(node, itm);
break;
case 'subtitle':
var entry = {};
entry.file = _xmlAttribute(node, 'url');
entry.kind = 'captions';
if (_xmlAttribute(node, 'lang').length > 0) {
entry.label = getLabel(_xmlAttribute(node, 'lang'));
}
captions.push(entry);
}
}
}
if (!itm.hasOwnProperty(tracks)) {
itm[tracks] = [];
}
for (i = 0; i < captions.length; i++) {
itm[tracks].push(captions[i]);
}
return itm;
};
})(jwplayer.parsers);
/**
* Parse an RSS feed and translate it to a playlist.
*
* @author zach
* @modified pablo
* @version 6.0
*/
(function(parsers) {
var utils = jwplayer.utils,
_textContent = parsers.textContent,
_getChildNode = parsers.getChildNode,
_numChildren = parsers.numChildren,
_localName = parsers.localName;
parsers.rssparser = {};
/**
* Parse an RSS playlist for feed items.
*
* @param {XML} dat
* @reuturn {Array} playlistarray
*/
parsers.rssparser.parse = function(dat) {
var arr = [];
for (var i = 0; i < _numChildren(dat); i++) {
var node = _getChildNode(dat, i),
localName = _localName(node).toLowerCase();
if (localName === 'channel') {
for (var j = 0; j < _numChildren(node); j++) {
var subNode = _getChildNode(node, j);
if (_localName(subNode).toLowerCase() === 'item') {
arr.push(_parseItem(subNode));
}
}
}
}
return arr;
};
/**
* Translate RSS item to playlist item.
*
* @param {XML} obj
* @return {PlaylistItem} PlaylistItem
*/
function _parseItem(obj) {
var itm = {};
for (var i = 0; i < obj.childNodes.length; i++) {
var node = obj.childNodes[i];
var localName = _localName(node);
if (!localName) {
continue;
}
switch (localName.toLowerCase()) {
case 'enclosure':
itm.file = utils.xmlAttribute(node, 'url');
break;
case 'title':
itm.title = _textContent(node);
break;
case 'guid':
itm.mediaid = _textContent(node);
break;
case 'pubdate':
itm.date = _textContent(node);
break;
case 'description':
itm.description = _textContent(node);
break;
case 'link':
itm.link = _textContent(node);
break;
case 'category':
if (itm.tags) {
itm.tags += _textContent(node);
} else {
itm.tags = _textContent(node);
}
break;
}
}
itm = parsers.mediaparser.parseGroup(obj, itm);
itm = parsers.jwparser.parseEntry(obj, itm);
return new jwplayer.playlist.item(itm);
}
})(jwplayer.parsers);
(function(jwplayer) {
var utils = jwplayer.utils;
var _ = jwplayer._;
jwplayer.playlist = function(playlist) {
var _playlist = [];
// Can be either an array of items or a single item.
playlist = (_.isArray(playlist) ? playlist : [playlist]);
_.each(playlist, function(item) {
_playlist.push(new jwplayer.playlist.item(item));
});
return _playlist;
};
/** Go through the playlist and choose a single playable type to play; remove sources of a different type **/
jwplayer.playlist.filterPlaylist = function(playlist, androidhls) {
var list = [];
_.each(playlist, function(item) {
item = utils.extend({}, item);
item.sources = _filterSources(item.sources, false, androidhls);
if (!item.sources.length) {
return;
}
// If the source doesn't have a label, number it
for (var j = 0; j < item.sources.length; j++) {
item.sources[j].label = item.sources[j].label || j.toString();
}
list.push(item);
});
return list;
};
function _parseSource(source) {
// file is the only hard requirement
if (!source || !source.file) { return; }
var file = utils.trim('' + source.file);
var type = source.type;
// If type not included, we infer it from extension
if (!type) {
var extension = utils.extension(file);
type = utils.extensionmap.extType(extension);
}
return utils.extend({}, source, { file : file, type : type }) ;
}
/** Filters the sources by taking the first playable type and eliminating sources of a different type **/
var _filterSources = jwplayer.playlist.filterSources = function(sources, filterFlash, androidhls) {
var selectedType,
newSources = [],
canPlay = (filterFlash ? jwplayer.embed.flashCanPlay : jwplayer.embed.html5CanPlay);
if (!sources) { return; }
_.each(sources, function(originalSource) {
var source = _parseSource(originalSource);
if (!source) { return; }
if (canPlay(source.file, source.type, androidhls)) {
// We want sources of all the same type since they may be of different quality levels
selectedType = selectedType || source.type;
if (source.type === selectedType) {
newSources.push(source);
}
}
});
return newSources;
};
})(jwplayer);
(function(playlist) {
var _item = playlist.item = function(config) {
var utils = jwplayer.utils,
_playlistitem = utils.extend({}, _item.defaults, config),
i, j, def;
_playlistitem.tracks = (config && utils.exists(config.tracks)) ? config.tracks : [];
if (_playlistitem.sources.length === 0) {
_playlistitem.sources = [new playlist.source(_playlistitem)];
}
/** Each source should be a named object **/
for (i = 0; i < _playlistitem.sources.length; i++) {
def = _playlistitem.sources[i]['default'];
if (def) {
_playlistitem.sources[i]['default'] = (def.toString() === 'true');
} else {
_playlistitem.sources[i]['default'] = false;
}
_playlistitem.sources[i] = new playlist.source(_playlistitem.sources[i]);
}
if (_playlistitem.captions && !utils.exists(config.tracks)) {
for (j = 0; j < _playlistitem.captions.length; j++) {
_playlistitem.tracks.push(_playlistitem.captions[j]);
}
delete _playlistitem.captions;
}
for (i = 0; i < _playlistitem.tracks.length; i++) {
_playlistitem.tracks[i] = new playlist.track(_playlistitem.tracks[i]);
}
return _playlistitem;
};
_item.defaults = {
description: undefined,
image: undefined,
mediaid: undefined,
title: undefined,
sources: [],
tracks: []
};
})(jwplayer.playlist);
(function(jwplayer) {
var utils = jwplayer.utils,
events = jwplayer.events,
parsers = jwplayer.parsers;
jwplayer.playlist.loader = function() {
var _eventDispatcher = new events.eventdispatcher();
utils.extend(this, _eventDispatcher);
this.load = function(playlistfile) {
utils.ajax(playlistfile, _playlistLoaded, _playlistLoadError);
};
function _playlistLoaded(loadedEvent) {
try {
var childNodes = loadedEvent.responseXML.childNodes;
var rss = '';
for (var i = 0; i < childNodes.length; i++) {
rss = childNodes[i];
if (rss.nodeType !== 8) { // 8: Node.COMMENT_NODE (IE8 doesn't have the Node.COMMENT_NODE constant)
break;
}
}
if (parsers.localName(rss) === 'xml') {
rss = rss.nextSibling;
}
if (parsers.localName(rss) !== 'rss') {
_playlistError('Not a valid RSS feed');
return;
}
var pl = new jwplayer.playlist(parsers.rssparser.parse(rss));
_eventDispatcher.sendEvent(events.JWPLAYER_PLAYLIST_LOADED, {
playlist: pl
});
} catch (e) {
_playlistError();
}
}
function _playlistLoadError(err) {
_playlistError(err.match(/invalid/i) ? 'Not a valid RSS feed' : '');
}
function _playlistError(msg) {
_eventDispatcher.sendEvent(events.JWPLAYER_ERROR, {
message: msg ? msg : 'Error loading file'
});
}
};
})(jwplayer);
(function(playlist) {
var utils = jwplayer.utils,
defaults = {
file: undefined,
label: undefined,
type: undefined,
'default': undefined
};
playlist.source = function(config) {
var _source = utils.extend({}, defaults);
utils.foreach(defaults, function(property) {
if (utils.exists(config[property])) {
_source[property] = config[property];
// Actively move from config to source
delete config[property];
}
});
if (_source.type && _source.type.indexOf('/') > 0) {
_source.type = utils.extensionmap.mimeType(_source.type);
}
if (_source.type === 'm3u8') {
_source.type = 'hls';
}
if (_source.type === 'smil') {
_source.type = 'rtmp';
}
return _source;
};
})(jwplayer.playlist);
(function(playlist) {
var utils = jwplayer.utils,
defaults = {
file: undefined,
label: undefined,
kind: 'captions',
'default': false
};
playlist.track = function(config) {
var _track = utils.extend({}, defaults);
if (!config) {
config = {};
}
utils.foreach(defaults, function(property) {
if (utils.exists(config[property])) {
_track[property] = config[property];
// Actively move from config to track
delete config[property];
}
});
return _track;
};
})(jwplayer.playlist);
(function(jwplayer) {
var utils = jwplayer.utils,
events = jwplayer.events,
_ = jwplayer._;
var embed = jwplayer.embed = function(playerApi) {
var _config = new embed.config(playerApi.config),
_width = _config.width,
_height = _config.height,
_errorText = 'Error loading player: ',
_oldContainer = document.getElementById(playerApi.id),
_pluginloader = jwplayer.plugins.loadPlugins(playerApi.id, _config.plugins),
_loader,
_playlistLoading = false,
_errorOccurred = false,
_playerEmbedder = null,
_setupErrorTimer = -1,
_this = this;
_config.id = playerApi.id;
if (_config.aspectratio) {
playerApi.config.aspectratio = _config.aspectratio;
} else {
delete playerApi.config.aspectratio;
}
_setupEvents(playerApi, _config.events);
var _container = document.createElement('div');
_container.id = _oldContainer.id;
_container.style.width = _width.toString().indexOf('%') > 0 ? _width : (_width + 'px');
_container.style.height = _height.toString().indexOf('%') > 0 ? _height : (_height + 'px');
_this.embed = function() {
if (_errorOccurred) {
return;
}
_pluginloader.addEventListener(events.COMPLETE, _doEmbed);
_pluginloader.addEventListener(events.ERROR, _pluginError);
_pluginloader.load();
};
_this.destroy = function() {
if (_playerEmbedder) {
_playerEmbedder.destroy();
_playerEmbedder = null;
}
if (_pluginloader) {
_pluginloader.destroy();
_pluginloader = null;
}
if (_loader) {
_loader.resetEventListeners();
_loader = null;
}
};
function _doEmbed() {
if (_errorOccurred) {
return;
}
var playlist = _config.playlist;
// Check for common playlist errors
if (_.isArray(playlist)) {
if (playlist.length === 0) {
_sourceError();
return;
}
// If single item playlist and it doesn't have any sources
if (playlist.length === 1) {
if (!playlist[0].sources || playlist[0].sources.length === 0 ||
!playlist[0].sources[0].file) {
_sourceError();
return;
}
}
}
if (_playlistLoading) {
return;
}
if (_.isString(playlist)) {
_loader = new jwplayer.playlist.loader();
_loader.addEventListener(events.JWPLAYER_PLAYLIST_LOADED, function(evt) {
_config.playlist = evt.playlist;
_playlistLoading = false;
_doEmbed();
});
_loader.addEventListener(events.JWPLAYER_ERROR, function(evt) {
_playlistLoading = false;
_sourceError(evt);
});
_playlistLoading = true;
_loader.load(_config.playlist);
return;
}
if (_pluginloader.getStatus() === utils.loaderstatus.COMPLETE) {
for (var i = 0; i < _config.modes.length; i++) {
var mode = _config.modes[i];
var type = mode.type;
if (type && embed[type]) {
var configClone = utils.extend({}, _config);
_playerEmbedder = new embed[type](_container, mode, configClone,
_pluginloader, playerApi);
if (_playerEmbedder.supportsConfig()) {
_playerEmbedder.addEventListener(events.ERROR, _embedError);
_playerEmbedder.embed();
_insertCSS();
return playerApi;
}
}
}
var message;
if (_config.fallback) {
message = 'No suitable players found and fallback enabled';
_dispatchSetupError(message, true);
utils.log(message);
new embed.download(_container, _config, _sourceError);
} else {
message = 'No suitable players found and fallback disabled';
_dispatchSetupError(message, false);
utils.log(message);
}
}
}
function _embedError(evt) {
_errorScreen(_errorText + evt.message);
}
function _pluginError(evt) {
playerApi.dispatchEvent(events.JWPLAYER_ERROR, {
message: 'Could not load plugin: ' + evt.message
});
}
function _sourceError(evt) {
if (evt && evt.message) {
_errorScreen('Error loading playlist: ' + evt.message);
} else {
_errorScreen(_errorText + 'No playable sources found');
}
}
function _dispatchSetupError(message, fallback) {
// Throttle this so that it runs once if called twice in the same callstack
clearTimeout(_setupErrorTimer);
_setupErrorTimer = setTimeout(function() {
playerApi.dispatchEvent(events.JWPLAYER_SETUP_ERROR, {
message: message,
fallback: fallback
});
}, 0);
}
function _errorScreen(message) {
if (_errorOccurred) {
return;
}
// Put new container in page
_oldContainer.parentNode.replaceChild(_container, _oldContainer);
if (!_config.fallback) {
_dispatchSetupError(message, false);
return;
}
_errorOccurred = true;
_displayError(_container, message, _config);
_dispatchSetupError(message, true);
}
_this.errorScreen = _errorScreen;
return _this;
};
function _setupEvents(api, events) {
utils.foreach(events, function(evt, val) {
var fn = api[evt];
if (typeof fn === 'function') {
fn.call(api, val);
}
});
}
function _insertCSS() {
utils.css('object.jwswf, .jwplayer:focus', {
outline: 'none'
});
utils.css('.jw-tab-focus:focus', {
outline: 'solid 2px #0B7EF4'
});
}
function _displayError(container, message, config) {
var style = container.style;
style.backgroundColor = '#000';
style.color = '#FFF';
style.width = utils.styleDimension(config.width);
style.height = utils.styleDimension(config.height);
style.display = 'table';
style.opacity = 1;
var text = document.createElement('p'),
textStyle = text.style;
textStyle.verticalAlign = 'middle';
textStyle.textAlign = 'center';
textStyle.display = 'table-cell';
textStyle.font = '15px/20px Arial, Helvetica, sans-serif';
text.innerHTML = message.replace(':', ':
');
container.innerHTML = '';
container.appendChild(text);
}
// Make this publicly accessible so the HTML5 player can error out on setup using the same code
jwplayer.embed.errorScreen = _displayError;
})(jwplayer);
(function(jwplayer) {
var utils = jwplayer.utils,
embed = jwplayer.embed,
playlistitem = jwplayer.playlist.item;
var config = embed.config = function(config) {
var _defaults = {
fallback: true, // enable download embedder
height: 270,
primary: 'html5',
width: 480,
base: config.base ? config.base : utils.getScriptPath('jwplayer.js'),
aspectratio: ''
},
_config = utils.extend({}, _defaults, jwplayer.defaults, config),
_modes = {
html5: {
type: 'html5',
src: _config.base + 'jwplayer.html5.js'
},
flash: {
type: 'flash',
src: _config.base + 'jwplayer.flash.swf'
}
};
// No longer allowing user-set modes block as of 6.0
_config.modes = (_config.primary === 'flash') ? [_modes.flash, _modes.html5] : [_modes.html5, _modes.flash];
if (_config.listbar) {
_config.playlistsize = _config.listbar.size;
_config.playlistposition = _config.listbar.position;
_config.playlistlayout = _config.listbar.layout;
}
if (_config.flashplayer) { _modes.flash.src = _config.flashplayer; }
if (_config.html5player) { _modes.html5.src = _config.html5player; }
_normalizePlaylist(_config);
evaluateAspectRatio(_config);
return _config;
};
function evaluateAspectRatio(config) {
var ar = config.aspectratio,
ratio = getRatio(ar);
if (config.width.toString().indexOf('%') === -1) {
delete config.aspectratio;
} else if (!ratio) {
delete config.aspectratio;
} else {
config.aspectratio = ratio;
}
}
function getRatio(ar) {
if (typeof ar !== 'string' || !utils.exists(ar)) {
return 0;
}
var index = ar.indexOf(':');
if (index === -1) {
return 0;
}
var w = parseFloat(ar.substr(0, index)),
h = parseFloat(ar.substr(index + 1));
if (w <= 0 || h <= 0) {
return 0;
}
return (h / w * 100) + '%';
}
/** Appends a new configuration onto an old one; used for mode configuration **/
config.addConfig = function(oldConfig, newConfig) {
_normalizePlaylist(newConfig);
return utils.extend(oldConfig, newConfig);
};
/** Construct a playlist from base-level config elements **/
function _normalizePlaylist(config) {
if (!config.playlist) {
var singleItem = {};
utils.foreach(playlistitem.defaults, function(itemProp) {
_moveProperty(config, singleItem, itemProp);
});
if (!singleItem.sources) {
if (config.levels) {
singleItem.sources = config.levels;
delete config.levels;
} else {
var singleSource = {};
_moveProperty(config, singleSource, 'file');
_moveProperty(config, singleSource, 'type');
singleItem.sources = singleSource.file ? [singleSource] : [];
}
}
config.playlist = [new playlistitem(singleItem)];
} else {
// Use JW Player playlist items to normalize sources of existing playlist items
for (var i = 0; i < config.playlist.length; i++) {
config.playlist[i] = new playlistitem(config.playlist[i]);
}
}
}
function _moveProperty(sourceObj, destObj, property) {
if (utils.exists(sourceObj[property])) {
destObj[property] = sourceObj[property];
delete sourceObj[property];
}
}
})(jwplayer);
(function(jwplayer) {
var embed = jwplayer.embed,
utils = jwplayer.utils,
JW_CSS_NONE = 'none',
JW_CSS_BLOCK = 'block',
JW_CSS_100PCT = '100%',
JW_CSS_RELATIVE = 'relative',
JW_CSS_ABSOLUTE = 'absolute';
// We cannot use jwplayer.utils.css due to an IE8 incompatability
function _badCss(selector, style) {
var elements = document.querySelectorAll(selector);
function app(prop, val) {
elements[i].style[prop] = val;
}
for (var i = 0; i < elements.length; i++) {
utils.foreach(style, app);
}
}
embed.download = function(_container, _options, _errorCallback) {
var params = utils.extend({}, _options),
_display,
_width = params.width ? params.width : 480,
_height = params.height ? params.height : 320,
_file,
_image,
_logo = _options.logo ? _options.logo : {
prefix: utils.repo(),
file: 'logo.png',
margin: 10
};
function _embed() {
var file, image, youtube, i, item, sources,
source, type,
playlist = params.playlist,
types = ['mp4', 'aac', 'mp3'];
if (!playlist || !playlist.length) {
return;
}
item = playlist[0];
sources = item.sources;
// If no downloadable files, and youtube, display youtube
// If nothing, show error message
for (i = 0; i < sources.length; i++) {
source = sources[i];
if (!source.file) {
continue;
}
type = source.type || utils.extensionmap.extType(utils.extension(source.file));
var typeIndex = utils.indexOf(types, type);
if (typeIndex >= 0) {
file = source.file;
image=item.image;
} else if (utils.isYouTube(source.file, type)) {
youtube = source.file;
}
}
if (file) {
_file = file;
_image = image;
_buildElements();
_styleElements();
} else if (youtube) {
_embedYouTube(youtube);
} else {
_errorCallback();
}
}
function _buildElements() {
if (_container) {
_display = _createElement('a', 'display', _container);
_createElement('div', 'icon', _display);
_createElement('div', 'logo', _display);
if (_file) {
_display.setAttribute('href', utils.getAbsolutePath(_file));
}
}
}
function _styleElements() {
var _prefix = '#' + _container.id + ' .jwdownload';
_container.style.width = '';
_container.style.height = '';
_badCss(_prefix + 'display', {
width: utils.styleDimension(Math.max(320, _width)),
height: utils.styleDimension(Math.max(180, _height)),
background: 'black center no-repeat ' + (_image ? 'url(' + _image + ')' : ''),
backgroundSize: 'contain',
position: JW_CSS_RELATIVE,
border: JW_CSS_NONE,
display: JW_CSS_BLOCK
});
_badCss(_prefix + 'display div', {
position: JW_CSS_ABSOLUTE,
width: JW_CSS_100PCT,
height: JW_CSS_100PCT
});
_badCss(_prefix + 'logo', {
top: _logo.margin + 'px',
right: _logo.margin + 'px',
background: 'top right no-repeat url(' + _logo.prefix + _logo.file + ')'
});
_badCss(_prefix + 'icon', {
/*jshint maxlen:9000*/
background: 'center no-repeat url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAgNJREFUeNrs28lqwkAYB/CZqNVDDj2r6FN41QeIy8Fe+gj6BL275Q08u9FbT8ZdwVfotSBYEPUkxFOoks4EKiJdaDuTjMn3wWBO0V/+sySR8SNSqVRKIR8qaXHkzlqS9jCfzzWcTCYp9hF5o+59sVjsiRzcegSckFzcjT+ruN80TeSlAjCAAXzdJSGPFXRpAAMYwACGZQkSdhG4WCzehMNhqV6vG6vVSrirKVEw66YoSqDb7cqlUilE8JjHd/y1MQefVzqdDmiaJpfLZWHgXMHn8F6vJ1cqlVAkEsGuAn83J4gAd2RZymQygX6/L1erVQt+9ZPWb+CDwcCC2zXGJaewl/DhcHhK3DVj+KfKZrMWvFarcYNLomAv4aPRSFZVlTlcSPA5fDweW/BoNIqFnKV53JvncjkLns/n/cLdS+92O7RYLLgsKfv9/t8XlDn4eDyiw+HA9Jyz2eyt0+kY2+3WFC5hluej0Ha7zQQq9PPwdDq1Et1sNsx/nFBgCqWJ8oAK1aUptNVqcYWewE4nahfU0YQnk4ntUEfGMIU2m01HoLaCKbTRaDgKtaVLk9tBYaBcE/6Artdr4RZ5TB6/dC+9iIe/WgAMYADDpAUJAxjAAAYwgGFZgoS/AtNNTF7Z2bL0BYPBV3Jw5xFwwWcYxgtBP5OkE8i9G7aWGOOCruvauwADALMLMEbKf4SdAAAAAElFTkSuQmCC)'
});
}
function _createElement(tag, className, parent) {
var _element = document.createElement(tag);
if (className) {
_element.className = 'jwdownload' + className;
}
if (parent) {
parent.appendChild(_element);
}
return _element;
}
/**
* Although this function creates a flash embed, the target is iOS,
* which interprets the embed code as a YouTube video,
* and plays it using the browser
*/
function _embedYouTube(path) {
var embed = _createElement('iframe', '', _container);
embed.src = 'http://www.youtube.com/embed/' + utils.youTubeID(path);
embed.width = _width;
embed.height = _height;
embed.style.border = 'none';
}
_embed();
};
})(jwplayer);
(function(jwplayer) {
/*jshint maxparams:5*/
var utils = jwplayer.utils,
events = jwplayer.events,
storedFlashvars = {};
var _flash = jwplayer.embed.flash = function(_container, _player, _options, _loader, _api) {
var _eventDispatcher = new jwplayer.events.eventdispatcher(),
_flashVersion = utils.flashVersion();
utils.extend(this, _eventDispatcher);
function appendAttribute(object, name, value) {
var param = document.createElement('param');
param.setAttribute('name', name);
param.setAttribute('value', value);
object.appendChild(param);
}
function _resizePlugin(plugin, div, onready) {
return function() {
try {
if (onready) {
document.getElementById(_api.id + '_wrapper').appendChild(div);
}
var display = document.getElementById(_api.id).getPluginConfig('display');
if (typeof plugin.resize === 'function') {
plugin.resize(display.width, display.height);
}
div.style.left = display.x;
div.style.top = display.h;
} catch (e) {}
};
}
function parsePlugins(pluginBlock) {
if (!pluginBlock) {
return {};
}
var flat = {},
pluginKeys = [];
utils.foreach(pluginBlock, function(plugin, pluginConfig) {
var pluginName = utils.getPluginName(plugin);
pluginKeys.push(plugin);
utils.foreach(pluginConfig, function(param, val) {
flat[pluginName + '.' + param] = val;
});
});
flat.plugins = pluginKeys.join(',');
return flat;
}
this.embed = function() {
// Make sure we're passing the correct ID into Flash for Linux API support
_options.id = _api.id;
// If Flash is installed, but the version is too low, display an error.
if (_flashVersion < 10) {
_eventDispatcher.sendEvent(events.ERROR, {
message: 'Flash version must be 10.0 or greater'
});
return false;
}
var _wrapper,
_aspect,
id = _container.id,
lb = _api.config.listbar;
var params = utils.extend({}, _options);
// Put the new container into the page
var replace = document.getElementById(_api.id);
replace.parentNode.replaceChild(_container, replace);
// Hack for when adding / removing happens too quickly
if (id + '_wrapper' === _container.parentNode.id) {
_wrapper = document.getElementById(id + '_wrapper');
} else {
_wrapper = document.createElement('div');
_aspect = document.createElement('div');
_aspect.style.display = 'none';
_aspect.id = id + '_aspect';
_wrapper.id = id + '_wrapper';
_wrapper.style.position = 'relative';
_wrapper.style.display = 'block';
_wrapper.style.width = utils.styleDimension(params.width);
_wrapper.style.height = utils.styleDimension(params.height);
_wrapper.style.margin = 'auto';
if (_api.config.aspectratio) {
var ar = parseFloat(_api.config.aspectratio);
_aspect.style.display = 'block';
_aspect.style.marginTop = _api.config.aspectratio;
_wrapper.style.height = 'auto';
_wrapper.style.display = 'inline-block';
if (lb) {
if (lb.position === 'bottom') {
_aspect.style.paddingBottom = lb.size + 'px';
} else if (lb.position === 'right') {
_aspect.style.marginBottom = (-1 * lb.size * (ar / 100)) + 'px';
}
}
}
_container.parentNode.replaceChild(_wrapper, _container);
_wrapper.appendChild(_container);
_wrapper.appendChild(_aspect);
}
var flashPlugins = _loader.setupPlugins(_api, params, _resizePlugin);
if (flashPlugins.length > 0) {
utils.extend(params, parsePlugins(flashPlugins.plugins));
} else {
delete params.plugins;
}
// Hack for the dock
if (typeof params['dock.position'] !== 'undefined') {
if (params['dock.position'].toString().toLowerCase() === 'false') {
params.dock = params['dock.position'];
delete params['dock.position'];
}
}
var bgcolor = '#000000',
flashPlayer, //flashvars,
wmode = params.wmode || (params.height && params.height <= 40 ? 'transparent' : 'opaque'),
toDelete = ['height', 'width', 'modes', 'events', 'primary', 'base', 'fallback', 'volume'];
for (var i = 0; i < toDelete.length; i++) {
delete params[toDelete[i]];
}
// If we've set any cookies in HTML5 mode, bring them into flash
var cookies = utils.getCookies();
utils.foreach(cookies, function(cookie, val) {
if (typeof(params[cookie]) === 'undefined') {
params[cookie] = val;
}
});
var base = window.location.href.split('/');
base.splice(base.length - 1, 1);
base = base.join('/');
params.base = base + '/';
storedFlashvars[id] = params;
if (utils.isMSIE()) {
_container.outerHTML = '';
flashPlayer = _wrapper.getElementsByTagName('object')[0];
flashPlayer.style.outline = 'none';
} else {
flashPlayer = document.createElement('object');
flashPlayer.setAttribute('type', 'application/x-shockwave-flash');
flashPlayer.setAttribute('data', _player.src);
flashPlayer.setAttribute('width', '100%');
flashPlayer.setAttribute('height', '100%');
flashPlayer.setAttribute('bgcolor', bgcolor);
flashPlayer.setAttribute('id', id);
flashPlayer.setAttribute('name', id);
flashPlayer.className = 'jwswf';
//obj.setAttribute('tabindex', 0);
appendAttribute(flashPlayer, 'allowfullscreen', 'true');
appendAttribute(flashPlayer, 'allowscriptaccess', 'always');
appendAttribute(flashPlayer, 'seamlesstabbing', 'true');
appendAttribute(flashPlayer, 'wmode', wmode);
_container.parentNode.replaceChild(flashPlayer, _container);
}
if (_api.config.aspectratio) {
flashPlayer.style.position = 'absolute';
flashPlayer.style.left = '0';
}
_api.container = flashPlayer;
_api.setPlayer(flashPlayer, 'flash');
};
/**
* Detects whether Flash supports this configuration
*/
this.supportsConfig = function() {
if (_flashVersion) {
if (_options) {
if (utils.typeOf(_options.playlist) === 'string') {
return true;
}
try {
var item = _options.playlist[0],
sources = item.sources;
if (typeof sources === 'undefined') {
return true;
} else {
for (var i = 0; i < sources.length; i++) {
if (sources[i].file && _flashCanPlay(sources[i].file, sources[i].type)) {
return true;
}
}
}
} catch (e) {
return false;
}
} else {
return true;
}
}
return false;
};
// Removing the object from the page cleans everything up
this.destroy = function() { };
};
_flash.getVars = function(id) {
return storedFlashvars[id];
};
/**
* Determines if a Flash can play a particular file, based on its extension
*/
var _flashCanPlay = jwplayer.embed.flashCanPlay = function(file, type) {
// TODO: Return false if isMobile
if (utils.isYouTube(file, type)) { return true; }
if (utils.isRtmp(file, type)) { return true; }
if (type === 'hls') { return true; }
var mappedType = utils.extensionmap[type ? type : utils.extension(file)];
// If no type or unrecognized type, don't allow to play
if (!mappedType) {
return false;
}
return !!(mappedType.flash);
};
})(jwplayer);
(function(jwplayer) {
/*jshint maxparams:5*/
var utils = jwplayer.utils,
extensionmap = utils.extensionmap,
events = jwplayer.events,
scriptLoader;
jwplayer.embed.html5 = function(_container, _player, _options, _loader, _api) {
var _this = this,
_eventdispatcher = new events.eventdispatcher();
utils.extend(_this, _eventdispatcher);
function _resizePlugin(plugin, div, onready) {
return function() {
try {
var displayarea = document.querySelector('#' + _container.id + ' .jwmain');
if (onready) {
displayarea.appendChild(div);
}
if (typeof plugin.resize === 'function') {
plugin.resize(displayarea.clientWidth, displayarea.clientHeight);
setTimeout(function() {
plugin.resize(displayarea.clientWidth, displayarea.clientHeight);
}, 400);
}
div.left = displayarea.style.left;
div.top = displayarea.style.top;
} catch (e) {}
};
}
_this.embed = function() {
if (!jwplayer.html5) {
this.loadEmbedder();
return;
}
_loader.setupPlugins(_api, _options, _resizePlugin);
utils.emptyElement(_container);
var playerOptions = jwplayer.utils.extend({}, _options);
// Volume option is tricky to remove, since it needs to be in the HTML5 player model.
delete playerOptions.volume;
var html5player = new jwplayer.html5.player(playerOptions);
_api.setPlayer(html5player, 'html5');
};
this.loadEmbedder = function() {
scriptLoader = scriptLoader || new utils.scriptloader(_player.src);
scriptLoader.addEventListener(events.ERROR, this.loadError);
scriptLoader.addEventListener(events.COMPLETE, this.embed);
scriptLoader.load(); // Don't worry, it will only load once
};
this.loadError = function(evt) {
this.sendEvent(evt.type, {
message: 'HTML5 player not found'
});
};
/**
* Detects whether the html5 player supports this configuration.
*
* @return {Boolean}
*/
_this.supportsConfig = function() {
if (!!jwplayer.vid.canPlayType) {
try {
if (utils.typeOf(_options.playlist) === 'string') {
return true;
} else {
var sources = _options.playlist[0].sources;
for (var i = 0; i < sources.length; i++) {
var file = sources[i].file,
type = sources[i].type;
if (jwplayer.embed.html5CanPlay(file, type, _options.androidhls)) {
return true;
}
}
}
} catch (e) {}
}
return false;
};
_this.destroy = function() {
if (scriptLoader) {
scriptLoader.resetEventListeners();
scriptLoader = null;
}
};
};
/**
* Determines if a video element can play a particular file, based on its extension
* @param {Object} file
* @param {Object} type
* @return {Boolean}
*/
function _html5CanPlay(file, type, androidhls) {
// HTML5 playback is not sufficiently supported on Blackberry devices; should fail over automatically.
if (navigator.userAgent.match(/BlackBerry/i) !== null) {
return false;
}
if (utils.isIE(9)) {
return false;
}
// Youtube JavaScript API Provider
if (utils.isYouTube(file, type)) {
// TODO: check that js api requirements are met first
// https://developers.google.com/youtube/js_api_reference
return true;
}
var extension = utils.extension(file);
type = type || extensionmap.extType(extension);
// HLS not sufficiently supported on Android devices; should fail over automatically.
if (type === 'hls') {
//when androidhls is set to true, allow HLS playback on Android 4.1 and up
if (androidhls) {
var isAndroidNative = utils.isAndroidNative;
if (isAndroidNative(2) || isAndroidNative(3) || isAndroidNative('4.0')) {
return false;
} else if (utils.isAndroid()) { //utils.isAndroidNative()) {
// skip canPlayType check
// canPlayType returns '' in native browser even though HLS will play
return true;
}
} else if (utils.isAndroid()) {
return false;
}
}
// Ensure RTMP files are not seen as videos
if (utils.isRtmp(file, type)) {
return false;
}
var mappedType = extensionmap[type] || extensionmap[extension];
// If no type or unrecognized type, don't allow to play
if (!mappedType) {
return false;
}
// Extension is recognized as a format Flash can play, but no HTML5 support is listed
if (mappedType.flash && !mappedType.html5) {
return false;
}
// Last, but not least, we ask the browser
// (But only if it's a video with an extension known to work in HTML5)
return _browserCanPlay(mappedType.html5);
}
/**
*
* @param {DOMMediaElement} video
* @param {String} mimetype
* @return {Boolean}
*/
function _browserCanPlay(mimetype) {
// OK to use HTML5 with no extension
if (!mimetype) {
return true;
}
try {
var result = jwplayer.vid.canPlayType(mimetype);
return !!result;
} catch (e) {}
return false;
}
jwplayer.embed.html5CanPlay = _html5CanPlay;
})(jwplayer);
(function(jwplayer, undefined) {
var _players = [],
utils = jwplayer.utils,
events = jwplayer.events,
_ = jwplayer._,
_uniqueIndex = 0,
states = events.state;
function addFocusBorder(container) {
utils.addClass(container, 'jw-tab-focus');
}
function removeFocusBorder(container) {
utils.removeClass(container, 'jw-tab-focus');
}
var _internalFuncsToGenerate = [
'getBuffer',
'getCaptionsList',
'getControls',
'getCurrentCaptions',
'getCurrentQuality',
'getCurrentAudioTrack',
'getDuration',
'getFullscreen',
'getHeight',
'getLockState',
'getMute',
'getPlaylistIndex',
'getSafeRegion',
'getPosition',
'getQualityLevels',
'getState',
'getVolume',
'getWidth',
'isBeforeComplete',
'isBeforePlay',
'releaseState'
];
var _chainableInternalFuncs = [
'playlistNext',
'stop',
// The following pass an argument to function
'forceState',
'playlistPrev',
'seek',
'setCurrentCaptions',
'setControls',
'setCurrentQuality',
'setVolume',
'setCurrentAudioTrack'
];
var _eventMapping = {
onBufferChange: events.JWPLAYER_MEDIA_BUFFER,
onBufferFull: events.JWPLAYER_MEDIA_BUFFER_FULL,
onError: events.JWPLAYER_ERROR,
onSetupError: events.JWPLAYER_SETUP_ERROR,
onFullscreen: events.JWPLAYER_FULLSCREEN,
onMeta: events.JWPLAYER_MEDIA_META,
onMute: events.JWPLAYER_MEDIA_MUTE,
onPlaylist: events.JWPLAYER_PLAYLIST_LOADED,
onPlaylistItem: events.JWPLAYER_PLAYLIST_ITEM,
onPlaylistComplete: events.JWPLAYER_PLAYLIST_COMPLETE,
onReady: events.API_READY,
onResize: events.JWPLAYER_RESIZE,
onComplete: events.JWPLAYER_MEDIA_COMPLETE,
onSeek: events.JWPLAYER_MEDIA_SEEK,
onTime: events.JWPLAYER_MEDIA_TIME,
onVolume: events.JWPLAYER_MEDIA_VOLUME,
onBeforePlay: events.JWPLAYER_MEDIA_BEFOREPLAY,
onBeforeComplete: events.JWPLAYER_MEDIA_BEFORECOMPLETE,
onDisplayClick: events.JWPLAYER_DISPLAY_CLICK,
onControls: events.JWPLAYER_CONTROLS,
onQualityLevels: events.JWPLAYER_MEDIA_LEVELS,
onQualityChange: events.JWPLAYER_MEDIA_LEVEL_CHANGED,
onCaptionsList: events.JWPLAYER_CAPTIONS_LIST,
onCaptionsChange: events.JWPLAYER_CAPTIONS_CHANGED,
onAdError: events.JWPLAYER_AD_ERROR,
onAdClick: events.JWPLAYER_AD_CLICK,
onAdImpression: events.JWPLAYER_AD_IMPRESSION,
onAdTime: events.JWPLAYER_AD_TIME,
onAdComplete: events.JWPLAYER_AD_COMPLETE,
onAdCompanions: events.JWPLAYER_AD_COMPANIONS,
onAdSkipped: events.JWPLAYER_AD_SKIPPED,
onAdPlay: events.JWPLAYER_AD_PLAY,
onAdPause: events.JWPLAYER_AD_PAUSE,
onAdMeta: events.JWPLAYER_AD_META,
onCast: events.JWPLAYER_CAST_SESSION,
onAudioTrackChange: events.JWPLAYER_AUDIO_TRACK_CHANGED,
onAudioTracks: events.JWPLAYER_AUDIO_TRACKS
};
var _stateMapping = {
onBuffer: states.BUFFERING,
onPause: states.PAUSED,
onPlay: states.PLAYING,
onIdle: states.IDLE
};
jwplayer.api = function(container) {
var _this = this,
_listeners = {},
_stateListeners = {},
_player,
_playerReady = false,
_queuedCalls = [],
_instream,
_itemMeta = {},
_callbacks = {};
_this.container = container;
_this.id = container.id;
_this.setup = function(options) {
if (jwplayer.embed) {
// Remove any players that may be associated to this DOM element
jwplayer.api.destroyPlayer(_this.id);
var newApi = (new jwplayer.api(_this.container));
jwplayer.api.addPlayer(newApi);
newApi.config = options;
newApi._embedder = new jwplayer.embed(newApi);
newApi._embedder.embed();
return newApi;
}
return _this;
};
_this.getContainer = function() {
return _this.container;
};
_this.addButton = function(icon, label, handler, id) {
try {
_callbacks[id] = handler;
var handlerString = 'jwplayer("' + _this.id + '").callback("' + id + '")';
//_player.jwDockAddButton(icon, label, handlerString, id);
_callInternal('jwDockAddButton', icon, label, handlerString, id);
} catch (e) {
utils.log('Could not add dock button' + e.message);
}
};
_this.removeButton = function(id) {
_callInternal('jwDockRemoveButton', id);
};
_this.callback = function(id) {
if (_callbacks[id]) {
_callbacks[id]();
}
};
_this.getMeta = function() {
return _this.getItemMeta();
};
_this.getPlaylist = function() {
var playlist = _callInternal('jwGetPlaylist');
if (_this.renderingMode === 'flash') {
utils.deepReplaceKeyName(playlist,
['__dot__', '__spc__', '__dsh__', '__default__'], ['.', ' ', '-', 'default']);
}
return playlist;
};
_this.getPlaylistItem = function(item) {
if (!utils.exists(item)) {
item = _this.getPlaylistIndex();
}
return _this.getPlaylist()[item];
};
_this.getRenderingMode = function() {
return _this.renderingMode;
};
// Player Public Methods
_this.setFullscreen = function(fullscreen) {
if (!utils.exists(fullscreen)) {
_callInternal('jwSetFullscreen', !_callInternal('jwGetFullscreen'));
} else {
_callInternal('jwSetFullscreen', fullscreen);
}
return _this;
};
_this.setMute = function(mute) {
if (!utils.exists(mute)) {
_callInternal('jwSetMute', !_callInternal('jwGetMute'));
} else {
_callInternal('jwSetMute', mute);
}
return _this;
};
_this.lock = function() {
return _this;
};
_this.unlock = function() {
return _this;
};
_this.load = function(toLoad) {
_callInternal('jwInstreamDestroy');
if (jwplayer(_this.id).plugins.googima) {
_callInternal('jwDestroyGoogima');
}
_callInternal('jwLoad', toLoad);
return _this;
};
_this.playlistItem = function(item) {
_callInternal('jwPlaylistItem', parseInt(item, 10));
return _this;
};
_this.resize = function(width, height) {
if (_this.renderingMode !== 'flash') {
_callInternal('jwResize', width, height);
} else {
var wrapper = document.getElementById(_this.id + '_wrapper'),
aspect = document.getElementById(_this.id + '_aspect');
if (aspect) {
aspect.style.display = 'none';
}
if (wrapper) {
wrapper.style.display = 'block';
wrapper.style.width = utils.styleDimension(width);
wrapper.style.height = utils.styleDimension(height);
}
}
return _this;
};
_this.play = function(state) {
if (state !== undefined) {
_callInternal('jwPlay', state);
return _this;
}
state = _this.getState();
var instreamState = _instream && _instream.getState();
if (instreamState) {
if (instreamState === states.IDLE || instreamState === states.PLAYING ||
instreamState === states.BUFFERING) {
_callInternal('jwInstreamPause');
} else {
_callInternal('jwInstreamPlay');
}
}
if (state === states.PLAYING || state === states.BUFFERING) {
_callInternal('jwPause');
} else {
_callInternal('jwPlay');
}
return _this;
};
_this.pause = function(state) {
if (state === undefined) {
state = _this.getState();
if (state === states.PLAYING || state === states.BUFFERING) {
_callInternal('jwPause');
} else {
_callInternal('jwPlay');
}
} else {
_callInternal('jwPause', state);
}
return _this;
};
_this.createInstream = function() {
return new jwplayer.api.instream(this, _player);
};
_this.setInstream = function(instream) {
_instream = instream;
return instream;
};
_this.loadInstream = function(item, options) {
_instream = _this.setInstream(_this.createInstream()).init(options);
_instream.loadItem(item);
return _instream;
};
_this.destroyPlayer = function() {
// so players can be removed before loading completes
_playerReady = true;
_callInternal('jwPlayerDestroy');
};
_this.playAd = function(ad) {
var plugins = jwplayer(_this.id).plugins;
if (plugins.vast) {
plugins.vast.jwPlayAd(ad);
} else {
_callInternal('jwPlayAd', ad);
}
};
_this.pauseAd = function() {
var plugins = jwplayer(_this.id).plugins;
if (plugins.vast) {
plugins.vast.jwPauseAd();
} else {
_callInternal('jwPauseAd');
}
};
// Take a mapping of function names to event names and setup listeners
function initializeMapping(mapping, listener) {
utils.foreach(mapping, function(name, value) {
_this[name] = function(callback) {
return listener(value, callback);
};
});
}
initializeMapping(_stateMapping, _stateListener);
initializeMapping(_eventMapping, _eventListener);
// given a name "getBuffer", it adds to jwplayer.api a function which internally triggers jwGetBuffer
function generateInternalFunction(chainable, name) {
var internalName = 'jw' + name.charAt(0).toUpperCase() + name.slice(1);
_this[name] = function() {
var value = _callInternal.apply(this, [internalName].concat(Array.prototype.slice.call(arguments, 0)));
return (chainable ? _this : value);
};
}
var nonChainingGenerator = function(index, name) {
generateInternalFunction(false, name);
};
var chainingGenerator = function(index, name) {
generateInternalFunction(true, name);
};
utils.foreach(_internalFuncsToGenerate, nonChainingGenerator);
utils.foreach(_chainableInternalFuncs, chainingGenerator);
_this.remove = function() {
// Cancel embedding even if it is in progress
if (this._embedder && this._embedder.destroy) {
this._embedder.destroy();
}
_queuedCalls = [];
// Is there more than one player using the same DIV on the page?
var sharedDOM = (_.size(_.where(_players, {id : _this.id})) > 1);
// If sharing the DOM element, don't reset CSS
if (! sharedDOM) {
utils.clearCss('#' + _this.id);
}
var toDestroy = document.getElementById(_this.id + (_this.renderingMode === 'flash' ? '_wrapper' : ''));
if (toDestroy) {
if (_this.renderingMode === 'html5') {
// calls jwPlayerDestroy()
_this.destroyPlayer();
} else if (utils.isMSIE(8)) {
// remove flash object safely, setting flash external interface methods to null for ie8
var swf = document.getElementById(_this.id);
if (swf && swf.parentNode) {
swf.style.display = 'none';
for (var i in swf) {
if (typeof swf[i] === 'function') {
swf[i] = null;
}
}
swf.parentNode.removeChild(swf);
}
}
// If the tag is reused by another player, do not destroy the div
if (! sharedDOM) {
var replacement = document.createElement('div');
replacement.id = _this.id;
toDestroy.parentNode.replaceChild(replacement, toDestroy);
}
}
// Remove from array of players
_players = _.filter(_players, function(p) {
return (p.uniqueId !== _this.uniqueId);
});
};
_this.registerPlugin = function(id, target, arg1, arg2) {
jwplayer.plugins.registerPlugin(id, target, arg1, arg2);
};
/** Use this function to set the internal low-level player.
* This is a javascript object which contains the low-level API calls. **/
_this.setPlayer = function(player, renderingMode) {
_player = player;
_this.renderingMode = renderingMode;
};
_this.detachMedia = function() {
if (_this.renderingMode === 'html5') {
return _callInternal('jwDetachMedia');
}
};
_this.attachMedia = function(seekable) {
if (_this.renderingMode === 'html5') {
return _callInternal('jwAttachMedia', seekable);
}
};
_this.getAudioTracks = function() {
return _callInternal('jwGetAudioTracks');
};
function _stateListener(state, callback) {
if (!_stateListeners[state]) {
_stateListeners[state] = [];
_eventListener(events.JWPLAYER_PLAYER_STATE, _stateCallback(state));
}
_stateListeners[state].push(callback);
return _this;
}
function _stateCallback(state) {
return function(args) {
var newstate = args.newstate,
oldstate = args.oldstate;
if (newstate === state) {
var callbacks = _stateListeners[newstate];
if (callbacks) {
for (var c = 0; c < callbacks.length; c++) {
var fn = callbacks[c];
if (typeof fn === 'function') {
fn.call(this, {
oldstate: oldstate,
newstate: newstate
});
}
}
}
}
};
}
function _addInternalListener(player, type) {
try {
player.jwAddEventListener(type,
'function(dat) { jwplayer("' + _this.id + '").dispatchEvent("' + type + '", dat); }');
} catch (e) {
if (_this.renderingMode === 'flash') {
var anchor = document.createElement('a');
anchor.href = _player.data;
if (anchor.protocol !== location.protocol) {
utils.log('Warning: Your site [' + location.protocol + '] and JWPlayer ['+anchor.protocol +
'] are hosted using different protocols');
}
}
utils.log('Could not add internal listener');
}
}
function _eventListener(type, callback) {
if (!_listeners[type]) {
_listeners[type] = [];
if (_player && _playerReady) {
_addInternalListener(_player, type);
}
}
_listeners[type].push(callback);
return _this;
}
_this.removeEventListener = function(type, callback) {
var listeners = _listeners[type];
if (listeners) {
for (var l = listeners.length; l--;) {
if (listeners[l] === callback) {
listeners.splice(l, 1);
}
}
}
};
_this.dispatchEvent = function(type) {
var listeners = _listeners[type];
if (listeners) {
listeners = listeners.slice(0); //copy array
var args = utils.translateEventResponse(type, arguments[1]);
for (var l = 0; l < listeners.length; l++) {
var fn = listeners[l];
if (typeof fn === 'function') {
try {
if (type === events.JWPLAYER_PLAYLIST_LOADED) {
utils.deepReplaceKeyName(args.playlist,
['__dot__', '__spc__', '__dsh__', '__default__'], ['.', ' ', '-', 'default']);
}
fn.call(this, args);
} catch (e) {
utils.log('There was an error calling back an event handler', e);
}
}
}
}
};
_this.dispatchInstreamEvent = function(type) {
if (_instream) {
_instream.dispatchEvent(type, arguments);
}
};
function _callInternal() {
if (_playerReady) {
if (_player) {
var args = Array.prototype.slice.call(arguments, 0),
funcName = args.shift();
if (typeof _player[funcName] === 'function') {
// Can't use apply here -- Flash's externalinterface doesn't like it.
//return func.apply(player, args);
switch (args.length) {
case 6:
return _player[funcName](args[0], args[1], args[2], args[3], args[4], args[5]);
case 5:
return _player[funcName](args[0], args[1], args[2], args[3], args[4]);
case 4:
return _player[funcName](args[0], args[1], args[2], args[3]);
case 3:
return _player[funcName](args[0], args[1], args[2]);
case 2:
return _player[funcName](args[0], args[1]);
case 1:
return _player[funcName](args[0]);
}
return _player[funcName]();
}
}
return null;
}
_queuedCalls.push(arguments);
}
_this.callInternal = _callInternal;
_this.playerReady = function(obj) {
_playerReady = true;
if (!_player) {
_this.setPlayer(document.getElementById(obj.id));
}
_this.container = document.getElementById(_this.id);
utils.foreach(_listeners, function(eventType) {
_addInternalListener(_player, eventType);
});
_eventListener(events.JWPLAYER_PLAYLIST_ITEM, function() {
_itemMeta = {};
});
_eventListener(events.JWPLAYER_MEDIA_META, function(data) {
utils.extend(_itemMeta, data.metadata);
});
_eventListener(events.JWPLAYER_VIEW_TAB_FOCUS, function(data) {
var container = _this.getContainer();
if (data.hasFocus === true) {
addFocusBorder(container);
} else {
removeFocusBorder(container);
}
});
_this.dispatchEvent(events.API_READY);
while (_queuedCalls.length > 0) {
_callInternal.apply(_this, _queuedCalls.shift());
}
};
_this.getItemMeta = function() {
return _itemMeta;
};
return _this;
};
//
// API Static methods
//
jwplayer.playerReady = function(obj) {
var api = jwplayer.api.playerById(obj.id);
if (!api) {
api = jwplayer.api.selectPlayer(obj.id);
}
api.playerReady(obj);
};
jwplayer.api.selectPlayer = function(identifier) {
var _container;
if (!utils.exists(identifier)) {
identifier = 0;
}
if (identifier.nodeType) {
// Handle DOM Element
_container = identifier;
} else if (typeof identifier === 'string') {
// Find container by ID
_container = document.getElementById(identifier);
}
if (_container) {
var foundPlayer = jwplayer.api.playerById(_container.id);
if (foundPlayer) {
return foundPlayer;
} else {
return (new jwplayer.api(_container));
}
} else if (typeof identifier === 'number') {
return _players[identifier];
}
return null;
};
jwplayer.api.playerById = function(id) {
for (var p = 0; p < _players.length; p++) {
if (_players[p].id === id) {
return _players[p];
}
}
return null;
};
jwplayer.api.addPlayer = function(player) {
for (var p = 0; p < _players.length; p++) {
if (_players[p] === player) {
return player; // Player is already in the list;
}
}
_uniqueIndex++;
player.uniqueId = _uniqueIndex;
_players.push(player);
return player;
};
// Destroys all players bound to a specific dom element by ID
jwplayer.api.destroyPlayer = function(id) {
// Get all players with matching id
var players = _.where(_players, {id : id});
// Call remove on every player in the array
_.each(players, _.partial(_.result, _, 'remove'));
};
})(window.jwplayer);
(function(jwplayer) {
var events = jwplayer.events,
utils = jwplayer.utils,
states = events.state;
jwplayer.api.instream = function(_api, _player) {
var _item,
_options,
_listeners = {},
_stateListeners = {},
_this = this;
function _addInternalListener(id, type) {
_player.jwInstreamAddEventListener(type,
'function(dat) { jwplayer("' + id + '").dispatchInstreamEvent("' + type + '", dat); }');
}
function _eventListener(type, callback) {
if (!_listeners[type]) {
_listeners[type] = [];
_addInternalListener(_api.id, type);
}
_listeners[type].push(callback);
return this;
}
function _stateListener(state, callback) {
if (!_stateListeners[state]) {
_stateListeners[state] = [];
_eventListener(events.JWPLAYER_PLAYER_STATE, _stateCallback(state));
}
_stateListeners[state].push(callback);
return this;
}
function _stateCallback(state) {
return function(args) {
var newstate = args.newstate,
oldstate = args.oldstate;
if (newstate === state) {
var callbacks = _stateListeners[newstate];
if (callbacks) {
for (var c = 0; c < callbacks.length; c++) {
var fn = callbacks[c];
if (typeof fn === 'function') {
fn.call(this, {
oldstate: oldstate,
newstate: newstate,
type: args.type
});
}
}
}
}
};
}
_this.type = 'instream';
_this.init = function() {
_api.callInternal('jwInitInstream');
return _this;
};
_this.loadItem = function(item, options) {
_item = item;
_options = options || {};
if (utils.typeOf(item) === 'array') {
_api.callInternal('jwLoadArrayInstream', _item, _options);
} else {
_api.callInternal('jwLoadItemInstream', _item, _options);
}
};
_this.removeEvents = function() {
_listeners = _stateListeners = {};
};
_this.removeEventListener = function(type, callback) {
var listeners = _listeners[type];
if (listeners) {
for (var l = listeners.length; l--;) {
if (listeners[l] === callback) {
listeners.splice(l, 1);
}
}
}
};
_this.dispatchEvent = function(type, calledArguments) {
var listeners = _listeners[type];
if (listeners) {
listeners = listeners.slice(0); //copy array
var args = utils.translateEventResponse(type, calledArguments[1]);
for (var l = 0; l < listeners.length; l++) {
var fn = listeners[l];
if (typeof fn === 'function') {
fn.call(this, args);
}
}
}
};
_this.onError = function(callback) {
return _eventListener(events.JWPLAYER_ERROR, callback);
};
_this.onMediaError = function(callback) {
return _eventListener(events.JWPLAYER_MEDIA_ERROR, callback);
};
_this.onFullscreen = function(callback) {
return _eventListener(events.JWPLAYER_FULLSCREEN, callback);
};
_this.onMeta = function(callback) {
return _eventListener(events.JWPLAYER_MEDIA_META, callback);
};
_this.onMute = function(callback) {
return _eventListener(events.JWPLAYER_MEDIA_MUTE, callback);
};
_this.onComplete = function(callback) {
return _eventListener(events.JWPLAYER_MEDIA_COMPLETE, callback);
};
// _this.onSeek = function(callback) {
// return _eventListener(events.JWPLAYER_MEDIA_SEEK, callback);
// };
_this.onPlaylistComplete = function(callback) {
return _eventListener(events.JWPLAYER_PLAYLIST_COMPLETE, callback);
};
_this.onPlaylistItem = function(callback) {
return _eventListener(events.JWPLAYER_PLAYLIST_ITEM, callback);
};
_this.onTime = function(callback) {
return _eventListener(events.JWPLAYER_MEDIA_TIME, callback);
};
// _this.onVolume = function(callback) {
// return _eventListener(events.JWPLAYER_MEDIA_VOLUME, callback);
// };
// State events
_this.onBuffer = function(callback) {
return _stateListener(states.BUFFERING, callback);
};
_this.onPause = function(callback) {
return _stateListener(states.PAUSED, callback);
};
_this.onPlay = function(callback) {
return _stateListener(states.PLAYING, callback);
};
_this.onIdle = function(callback) {
return _stateListener(states.IDLE, callback);
};
// Instream events
_this.onClick = function(callback) {
return _eventListener(events.JWPLAYER_INSTREAM_CLICK, callback);
};
_this.onInstreamDestroyed = function(callback) {
return _eventListener(events.JWPLAYER_INSTREAM_DESTROYED, callback);
};
_this.onAdSkipped = function(callback) {
return _eventListener(events.JWPLAYER_AD_SKIPPED, callback);
};
_this.play = function(state) {
_player.jwInstreamPlay(state);
};
_this.pause = function(state) {
_player.jwInstreamPause(state);
};
_this.hide = function() {
_api.callInternal('jwInstreamHide');
};
_this.destroy = function() {
_this.removeEvents();
_api.callInternal('jwInstreamDestroy');
};
_this.setText = function(text) {
_player.jwInstreamSetText(text ? text : '');
};
_this.getState = function() {
return _player.jwInstreamState();
};
_this.setClick = function(url) {
//only present in flashMode
if (_player.jwInstreamClick) {
_player.jwInstreamClick(url);
}
};
};
})(jwplayer);
/**
* JW Player Source Endcap
*
* This will appear at the end of the JW Player source
*
* @version 6.0
*/
}