123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- (function( Popcorn ) {
-
- // combines calls of two function calls into one
- var combineFn = function( first, second ) {
-
- first = first || Popcorn.nop;
- second = second || Popcorn.nop;
-
- return function() {
-
- first.apply( this, arguments );
- second.apply( this, arguments );
- };
- };
-
- // ID string matching
- var rIdExp = /^(#([\w\-\_\.]+))$/;
-
- var audioExtensions = "ogg|oga|aac|mp3|wav",
- videoExtensions = "ogg|ogv|mp4|webm",
- mediaExtensions = audioExtensions + "|" + videoExtensions;
-
- var audioExtensionRegexp = new RegExp( "^.*\\.(" + audioExtensions + ")($|\\?)" ),
- mediaExtensionRegexp = new RegExp( "^.*\\.(" + mediaExtensions + ")($|\\?)" );
-
- Popcorn.player = function( name, player ) {
-
- // return early if a player already exists under this name
- if ( Popcorn[ name ] ) {
-
- return;
- }
-
- player = player || {};
-
- var playerFn = function( target, src, options ) {
-
- options = options || {};
-
- // List of events
- var date = new Date() / 1000,
- baselineTime = date,
- currentTime = 0,
- readyState = 0,
- volume = 1,
- muted = false,
- events = {},
-
- // The container div of the resource
- container = typeof target === "string" ? Popcorn.dom.find( target ) : target,
- basePlayer = {},
- timeout,
- popcorn;
-
- if ( !Object.prototype.__defineGetter__ ) {
-
- basePlayer = container || document.createElement( "div" );
- }
-
- // copies a div into the media object
- for( var val in container ) {
-
- // don't copy properties if using container as baseplayer
- if ( val in basePlayer ) {
-
- continue;
- }
-
- if ( typeof container[ val ] === "object" ) {
-
- basePlayer[ val ] = container[ val ];
- } else if ( typeof container[ val ] === "function" ) {
-
- basePlayer[ val ] = (function( value ) {
-
- // this is a stupid ugly kludgy hack in honour of Safari
- // in Safari a NodeList is a function, not an object
- if ( "length" in container[ value ] && !container[ value ].call ) {
-
- return container[ value ];
- } else {
-
- return function() {
-
- return container[ value ].apply( container, arguments );
- };
- }
- }( val ));
- } else {
-
- Popcorn.player.defineProperty( basePlayer, val, {
- get: (function( value ) {
-
- return function() {
-
- return container[ value ];
- };
- }( val )),
- set: Popcorn.nop,
- configurable: true
- });
- }
- }
-
- var timeupdate = function() {
-
- date = new Date() / 1000;
-
- if ( !basePlayer.paused ) {
-
- basePlayer.currentTime = basePlayer.currentTime + ( date - baselineTime );
- basePlayer.dispatchEvent( "timeupdate" );
- timeout = setTimeout( timeupdate, 10 );
- }
-
- baselineTime = date;
- };
-
- basePlayer.play = function() {
-
- this.paused = false;
-
- if ( basePlayer.readyState >= 4 ) {
-
- baselineTime = new Date() / 1000;
- basePlayer.dispatchEvent( "play" );
- timeupdate();
- }
- };
-
- basePlayer.pause = function() {
-
- this.paused = true;
- basePlayer.dispatchEvent( "pause" );
- };
-
- Popcorn.player.defineProperty( basePlayer, "currentTime", {
- get: function() {
-
- return currentTime;
- },
- set: function( val ) {
-
- // make sure val is a number
- currentTime = +val;
- basePlayer.dispatchEvent( "timeupdate" );
-
- return currentTime;
- },
- configurable: true
- });
-
- Popcorn.player.defineProperty( basePlayer, "volume", {
- get: function() {
-
- return volume;
- },
- set: function( val ) {
-
- // make sure val is a number
- volume = +val;
- basePlayer.dispatchEvent( "volumechange" );
- return volume;
- },
- configurable: true
- });
-
- Popcorn.player.defineProperty( basePlayer, "muted", {
- get: function() {
-
- return muted;
- },
- set: function( val ) {
-
- // make sure val is a number
- muted = +val;
- basePlayer.dispatchEvent( "volumechange" );
- return muted;
- },
- configurable: true
- });
-
- Popcorn.player.defineProperty( basePlayer, "readyState", {
- get: function() {
-
- return readyState;
- },
- set: function( val ) {
-
- readyState = val;
- return readyState;
- },
- configurable: true
- });
-
- // Adds an event listener to the object
- basePlayer.addEventListener = function( evtName, fn ) {
-
- if ( !events[ evtName ] ) {
-
- events[ evtName ] = [];
- }
-
- events[ evtName ].push( fn );
- return fn;
- };
-
- // Removes an event listener from the object
- basePlayer.removeEventListener = function( evtName, fn ) {
-
- var i,
- listeners = events[ evtName ];
-
- if ( !listeners ){
-
- return;
- }
-
- // walk backwards so we can safely splice
- for ( i = events[ evtName ].length - 1; i >= 0; i-- ) {
-
- if( fn === listeners[ i ] ) {
-
- listeners.splice(i, 1);
- }
- }
-
- return fn;
- };
-
- // Can take event object or simple string
- basePlayer.dispatchEvent = function( oEvent ) {
-
- var evt,
- self = this,
- eventInterface,
- eventName = oEvent.type;
-
- // A string was passed, create event object
- if ( !eventName ) {
-
- eventName = oEvent;
- eventInterface = Popcorn.events.getInterface( eventName );
-
- if ( eventInterface ) {
-
- evt = document.createEvent( eventInterface );
- evt.initEvent( eventName, true, true, window, 1 );
- }
- }
-
- if ( events[ eventName ] ) {
-
- for ( var i = events[ eventName ].length - 1; i >= 0; i-- ) {
-
- events[ eventName ][ i ].call( self, evt, self );
- }
- }
- };
-
- // Attempt to get src from playerFn parameter
- basePlayer.src = src || "";
- basePlayer.duration = 0;
- basePlayer.paused = true;
- basePlayer.ended = 0;
-
- options && options.events && Popcorn.forEach( options.events, function( val, key ) {
-
- basePlayer.addEventListener( key, val, false );
- });
-
- // true and undefined returns on canPlayType means we should attempt to use it,
- // false means we cannot play this type
- if ( player._canPlayType( container.nodeName, src ) !== false ) {
-
- if ( player._setup ) {
-
- player._setup.call( basePlayer, options );
- } else {
-
- // there is no setup, which means there is nothing to load
- basePlayer.readyState = 4;
- basePlayer.dispatchEvent( "loadedmetadata" );
- basePlayer.dispatchEvent( "loadeddata" );
- basePlayer.dispatchEvent( "canplaythrough" );
- }
- } else {
-
- // Asynchronous so that users can catch this event
- setTimeout( function() {
- basePlayer.dispatchEvent( "error" );
- }, 0 );
- }
-
- popcorn = new Popcorn.p.init( basePlayer, options );
-
- if ( player._teardown ) {
-
- popcorn.destroy = combineFn( popcorn.destroy, function() {
-
- player._teardown.call( basePlayer, options );
- });
- }
-
- return popcorn;
- };
-
- playerFn.canPlayType = player._canPlayType = player._canPlayType || Popcorn.nop;
-
- Popcorn[ name ] = Popcorn.player.registry[ name ] = playerFn;
- };
-
- Popcorn.player.registry = {};
-
- Popcorn.player.defineProperty = Object.defineProperty || function( object, description, options ) {
-
- object.__defineGetter__( description, options.get || Popcorn.nop );
- object.__defineSetter__( description, options.set || Popcorn.nop );
- };
-
- // player queue is to help players queue things like play and pause
- // HTML5 video's play and pause are asynch, but do fire in sequence
- // play() should really mean "requestPlay()" or "queuePlay()" and
- // stash a callback that will play the media resource when it's ready to be played
- Popcorn.player.playerQueue = function() {
-
- var _queue = [],
- _running = false;
-
- return {
- next: function() {
-
- _running = false;
- _queue.shift();
- _queue[ 0 ] && _queue[ 0 ]();
- },
- add: function( callback ) {
-
- _queue.push(function() {
-
- _running = true;
- callback && callback();
- });
-
- // if there is only one item on the queue, start it
- !_running && _queue[ 0 ]();
- }
- };
- };
-
- // smart will attempt to find you a match, if it does not find a match,
- // it will attempt to create a video element with the source,
- // if that failed, it will throw.
- Popcorn.smart = function( target, src, options ) {
- var playerType,
- elementTypes = [ "AUDIO", "VIDEO" ],
- sourceNode,
- firstSrc,
- node = Popcorn.dom.find( target ),
- i, srcResult,
- canPlayTypeTester = document.createElement( "video" ),
- canPlayTypes = {
- "ogg": "video/ogg",
- "ogv": "video/ogg",
- "oga": "audio/ogg",
- "webm": "video/webm",
- "mp4": "video/mp4",
- "mp3": "audio/mp3"
- };
-
- var canPlayType = function( type ) {
-
- return canPlayTypeTester.canPlayType( canPlayTypes[ type ] );
- };
-
- var canPlaySrc = function( src ) {
-
- srcResult = mediaExtensionRegexp.exec( src );
-
- if ( !srcResult || !srcResult[ 1 ] ) {
- return false;
- }
-
- return canPlayType( srcResult[ 1 ] );
- };
-
- if ( !node ) {
-
- Popcorn.error( "Specified target " + target + " was not found." );
- return;
- }
-
- // For when no src is defined.
- // Usually this is a video element with a src already on it.
- if ( elementTypes.indexOf( node.nodeName ) > -1 && !src ) {
-
- if ( typeof src === "object" ) {
-
- options = src;
- src = undefined;
- }
-
- return Popcorn( node, options );
- }
-
- // if our src is not an array, create an array of one.
- if ( typeof( src ) === "string" ) {
-
- src = [ src ];
- }
-
- // go through each src, and find the first playable.
- // this only covers player sources popcorn knows of,
- // and not things like a youtube src that is private.
- // it will still consider a private youtube video to be playable.
- for ( i = 0, srcLength = src.length; i < srcLength; i++ ) {
-
- // src is a playable HTML5 video, we don't need to check custom players.
- if ( canPlaySrc( src[ i ] ) ) {
-
- src = src[ i ];
- break;
- }
-
- // for now we loop through and use the first valid player we find.
- for ( var key in Popcorn.player.registry ) {
-
- if ( Popcorn.player.registry.hasOwnProperty( key ) ) {
-
- if ( Popcorn.player.registry[ key ].canPlayType( node.nodeName, src[ i ] ) ) {
-
- // Popcorn.smart( player, src, /* options */ )
- return Popcorn[ key ]( node, src[ i ], options );
- }
- }
- }
- }
-
- // Popcorn.smart( div, src, /* options */ )
- // attempting to create a video in a container
- if ( elementTypes.indexOf( node.nodeName ) === -1 ) {
-
- firstSrc = typeof( src ) === "string" ? src : src.length ? src[ 0 ] : src;
-
- target = document.createElement( !!audioExtensionRegexp.exec( firstSrc ) ? elementTypes[ 0 ] : elementTypes[ 1 ] );
-
- // Controls are defaulted to being present
- target.controls = true;
-
- node.appendChild( target );
- node = target;
- }
-
- options && options.events && options.events.error && node.addEventListener( "error", options.events.error, false );
- node.src = src;
-
- return Popcorn( node, options );
-
- };
- })( Popcorn );
|