Re-write of the Vimeo Player plug-in to use the new Player API [#728]

This commit is contained in:
Christopher De Cairos 2011-09-30 00:09:46 -04:00
Родитель caa6b79129
Коммит ff4c81b3b1
4 изменённых файлов: 613 добавлений и 783 удалений

Просмотреть файл

@ -21,7 +21,7 @@
padding-left: 20px;
}
</style>
<script src="../../popcorn.js"></script>
<script type="text/javascript" src="popcorn.vimeo.js"></script>
<script src="../../plugins/footnote/popcorn.footnote.js"></script>
@ -32,67 +32,61 @@
<script src="../../plugins/image/popcorn.image.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="../../plugins/twitter/popcorn.twitter.js"></script>
<script type="text/javascript">
// Called as onload function
// Set up interface controls
VimeoEmbedLoaded = function( player ) {
var loop = 0,
volume = 1;
// Hook up custom controls
// Single play/pause buttons
document.getElementById( "btnPlay" ).addEventListener( "click", function(e) {
player.play();
}, false);
document.getElementById( "btnPause" ).addEventListener( "click", function(e) {
player.pause();
}, false);
//Seek
document.getElementById( "btnSeek" ).addEventListener( "click", function() {
player.currentTime( 30 );
}, false);
// Loop
document.getElementById( "btnLoop" ).addEventListener( "click", function() {
loop = loop === "loop" ? "" : "loop";
player.video.setLoop( loop );
}, false);
// Volume
document.getElementById( "btnVolume" ).addEventListener( "click", function() {
volume = volume === 1 ? 0.5 : 1;
volume = volume === 100 ? 50 : 100;
player.volume( volume );
}, false);
// Mute
document.getElementById( "btnMute" ).addEventListener( "click", function() {
player.mute();
player.mute( !player.media.muted );
}, false);
// Hook into player events
// Timeupdate, as the video plays
player.listen( "timeupdate", function() {
document.getElementById( "player_time" ).innerHTML = player.currentTime();
});
// When the volume changes
player.listen( "volumechange", function() {
document.getElementById( "player_vol" ).innerHTML = player.volume();
});
// When the video duration changes
player.listen( "durationchange", function() {
document.getElementById( "player_duration" ).innerHTML = player.duration();
});
// When the meddia ready state changes
player.listen( "readystatechange", function() {
document.getElementById( "player_state" ).innerHTML = player.readyState();
});
// Output some initial UI values so we caan see what the player is doing
document.getElementById( "player_time" ).innerHTML = player.currentTime();
document.getElementById( "player_vol" ).innerHTML = player.volume();
@ -101,12 +95,7 @@
//On document ready
document.addEventListener( "DOMContentLoaded", function() {
var player = Popcorn( Popcorn.vimeo( "player_1", "http://player.vimeo.com/video/11127501", {
css: {
width: "500px",
height: "281px"
}
}) )
var player = Popcorn.vimeo( "player_1", "http://player.vimeo.com/video/6960892" )
.footnote({
start: 5, // seconds
end: 40, // seconds
@ -145,7 +134,7 @@
language: "en"
})
.webpage({
id: "webpages-a",
id: "webpages-a",
start: 0, // seconds
end: 15, // seconds
src: 'http://webmademovies.org/',
@ -165,34 +154,34 @@
href: 'http://www.drumbeat.org/',
src: 'https://www.drumbeat.org/media//images/drumbeat-logo-splash.png',
target: 'imagediv'
})
.listen( "load", function() {
});
player.listen( "load", function() {
//console.log( "asdfasdf" );
VimeoEmbedLoaded( player );
})
.listen( "loadstart", function() {
.listen( "loadstart", function() {
document.getElementById( "player_load" ).innerHTML = "Started";
})
.listen( "canplaythrough", function() {
document.getElementById( "player_load" ).innerHTML = "Finished";
})
.volume(0)
//.volume(0)
.play();
}, false);
</script>
</head>
<body>
<div>
<div id="player_1" ></div><br />
<div id="player_1" style="width: 400px; height: 400px;"></div><br />
<button class="simple" id="btnPlay">Play</button>
<button class="simple" id="btnPause">Pause</button>
<button class="seek" id="btnSeek">Seek to 30</button>
<button class="loop" id="btnLoop">Toggle Loop</button>
<button class="volume" id="btnVolume">Toggle Volume</button>
<button class="volume" id="btnMute">Mute</button>
<div>
Current Time (s): <span id="player_time"></span>
<br />Video Duration (s): <span id="player_duration"></span>
<br />Volume (0-1): <span id="player_vol"></span>
<br />Volume (0-100): <span id="player_vol"></span>
<br />Load Status: <span id="player_load">Not Started</span>
</div>
</div>
@ -243,9 +232,9 @@
<strong>Web Page Area</strong><br />
</div>
</div>
<br />
<br />
</body>
</html>

Просмотреть файл

@ -1,613 +1,246 @@
// Popcorn Vimeo Player Wrapper
( function( Popcorn, global ) {
/**
* Vimeo wrapper for Popcorn.
* This player adds enables Popcorn.js to handle Vimeo videos. It does so by masking an embedded Vimeo video Flash object
* as a video and implementing the HTML5 Media Element interface.
*
* You can specify the video in four ways:
* 1. Use the embed code path supplied by Vimeo as a div's src, and pass the div id into a new Popcorn.vimeo object
*
* <div id="player_1" width="500" height="281" src="http://player.vimeo.com/video/11127501" ></div>
* <script type="text/javascript">
* document.addEventListener("DOMContentLoaded", function() {
* var popcorn = Popcorn( Popcorn.vimeo( "player_1" ) );
* }, false);
* </script>
&
* 2. Pass the div id and the embed code path supplied by Vimeo into a new Popcorn.vimeo object
*
* <div id="player_1" width="500" height="281" ></div>
* <script type="text/javascript">
* document.addEventListener("DOMContentLoaded", function() {
* var popcorn = Popcorn( Popcorn.vimeo( "player_1", "http://player.vimeo.com/video/11127501" ) );
* }, false);
* </script>
*
* 3. Use a web url as a div's src, and pass the div id into a new Popcorn.vimeo object
*
* <div id="player_1" width="500" height="281" src="http://vimeo.com/11127501" ></div>
* <script type="text/javascript">
* document.addEventListener("DOMContentLoaded", function() {
* var popcorn = Popcorn( Popcorn.vimeo( "player_1" ) );
* }, false);
* </script>
*
* 4. Pass the div id and the web url into a new Popcorn.vimeo object
*
* <div id="player_1" width="500" height="281" ></div>
* <script type="text/javascript">
* document.addEventListener("DOMContentLoaded", function() {
* var popcorn = Popcorn( Popcorn.vimeo( "player_1", "http://vimeo.com/11127501" ) );
* }, false);
* </script>
*
* Due to Vimeo's API, certain events must be subscribed to at different times, and some not at all.
* These events are completely custom-implemented and may be subscribed to at any time:
* canplaythrough
* durationchange
* load
* loadedmetadata
* loadstart
* play
* readystatechange
* volumechange
*
* These events are related to player functionality and must be subscribed to during or after the load event:
* abort
* emptied
* ended
* pause
* playing
* progress
* seeked
* timeupdate
*
* These events are not supported:
* canplay
* error
* loadeddata
* ratechange
* seeking
* stalled
* suspend
* waiting
*
* Due to Vimeo's API, some attributes are be supported while others are not.
* Supported media attributes:
* autoplay ( via Popcorn )
* currentTime
* duration ( get only )
* ended ( get only )
* initialTime ( get only, always 0 )
* loop ( get only, set by calling setLoop() )
* muted ( get only )
* paused ( get only )
* readyState ( get only )
* volume
*
* load() function
* mute() function ( toggles on/off )
*
* Unsupported media attributes:
* buffered
* defaultPlaybackRate
* networkState
* playbackRate
* played
* preload
* seekable
* seeking
* src
* startOffsetTime
*/
(function() {
// Trackers
var timeupdateInterval = 33,
timeCheckInterval = 0.75,
abs = Math.abs,
registry = {};
// global callback for vimeo.. yuck.
vimeo_player_loaded = function( playerId ) {
vimeo_player_loaded[ playerId ] && vimeo_player_loaded[ playerId ]();
};
vimeo_player_loaded.seek = {};
vimeo_player_loaded.loadProgress = {};
vimeo_player_loaded.play = {};
vimeo_player_loaded.pause = {};
// base object for DOM-related behaviour like events
var EventManager = function ( owner ) {
var evts = {};
Popcorn.player( "vimeo", {
_setup: function( options ) {
function makeHandler( evtName ) {
if ( !evts[evtName] ) {
evts[evtName] = [];
var media = this,
vimeoObject,
vimeoContainer = document.createElement( "div" ),
currentTime = 0,
seekTime = 0,
seeking = false,
volumeChanged = false,
lastMuted = false,
lastVolume = 0;
// Create a wrapper function to all registered listeners
this["on"+evtName] = function( args ) {
Popcorn.forEach( evts[evtName], function( fn ) {
if ( fn ) {
fn.call( owner, args );
vimeoContainer.id = media.id + Popcorn.guid();
media.appendChild( vimeoContainer );
var vimeoInit = function() {
var flashvars,
params,
attributes = {},
src = media.src,
toggleMuteVolume = 0,
loadStarted = false;
vimeo_player_loaded[ vimeoContainer.id ] = function() {
vimeoObject = document.getElementById( vimeoContainer.id );
vimeo_player_loaded.seek[ vimeoContainer.id ] = function( time ) {
if( time !== currentTime ) {
currentTime = time;
media.dispatchEvent( "seeked" );
media.dispatchEvent( "timeupdate" );
}
};
vimeo_player_loaded.play[ vimeoContainer.id ] = function() {
if ( media.paused ) {
media.paused = false;
media.dispatchEvent( "play" );
media.dispatchEvent( "playing" );
timeUpdate();
}
};
vimeo_player_loaded.pause[ vimeoContainer.id ] = function() {
if ( !media.paused ) {
media.paused = true;
media.dispatchEvent( "pause" );
}
};
vimeo_player_loaded.loadProgress[ vimeoContainer.id ] = function( progress ) {
if ( !loadStarted ) {
loadStarted = true;
media.dispatchEvent( "loadstart" );
}
if ( progress.percent === 100 ) {
media.dispatchEvent( "canplaythrough" );
}
};
vimeoObject.api_addEventListener( "seek", "vimeo_player_loaded.seek." + vimeoContainer.id );
vimeoObject.api_addEventListener( "loadProgress", "vimeo_player_loaded.loadProgress." + vimeoContainer.id );
vimeoObject.api_addEventListener( "play", "vimeo_player_loaded.play." + vimeoContainer.id );
vimeoObject.api_addEventListener( "pause", "vimeo_player_loaded.pause." + vimeoContainer.id );
var timeUpdate = function() {
if ( !media.paused ) {
currentTime = vimeoObject.api_getCurrentTime();
media.dispatchEvent( "timeupdate" );
setTimeout( timeUpdate, 10 );
}
},
isMuted = function() {
return vimeoObject.api_getVolume() === 0;
};
var volumeUpdate = function() {
m = isMuted();
vol = vimeoObject.api_getVolume();
if ( lastMuted !== m ) {
lastMuted = m;
media.dispatchEvent( "volumechange" );
}
if ( lastVolume !== vol ) {
lastVolume = vol;
media.dispatchEvent( "volumechange" );
}
setTimeout( volumeUpdate, 250 );
};
var mute = function() {
};
media.play = function() {
media.paused = false;
media.dispatchEvent( "play" );
media.dispatchEvent( "playing" );
timeUpdate();
vimeoObject.api_play();
};
media.pause = function() {
if ( !media.paused ) {
media.paused = true;
media.dispatchEvent( "pause" );
vimeoObject.api_pause();
}
};
Popcorn.player.defineProperty( media, "currentTime", {
set: function( val ) {
if ( !val ) {
return currentTime;
}
currentTime = seekTime = +val;
seeking = true;
media.dispatchEvent( "seeked" );
media.dispatchEvent( "timeupdate" );
vimeoObject.api_seekTo( currentTime );
return currentTime;
},
get: function() {
return currentTime;
}
});
Popcorn.player.defineProperty( media, "muted", {
set: function( val ) {
if ( isMuted() !== val ) {
if ( val ) {
toggleMuteVolume = vimeoObject.api_getVolume();
vimeoObject.api_setVolume( 0 );
} else {
vimeoObject.api_setVolume( toggleMuteVolume );
}
}
},
get: function() {
return isMuted();
}
});
Popcorn.player.defineProperty( media, "volume", {
set: function( val ) {
if ( !val || typeof val !== "number" || ( val < 0 && val > 1 ) ) {
return vimeoObject.api_getVolume();
}
if ( vimeoObject.api_getVolume() !== val ) {
vimeoObject.api_setVolume( val );
lastVolume = vimeoObject.api_getVolume();
media.dispatchEvent( "volumechange" );
}
return vimeoObject.api_getVolume();
},
get: function() {
return vimeoObject.api_getVolume();
}
});
media.readyState = 4;
media.dispatchEvent( "load" );
media.duration = vimeoObject.api_getDuration();
media.dispatchEvent( "durationchange" );
volumeUpdate();
media.dispatchEvent( "loadeddata" );
}
function extractId( videoUrl ) {
if ( !videoUrl ) {
return;
}
var rPlayerUri = /^http:\/\/player\.vimeo\.com\/video\/[\d]+/i,
rWebUrl = /vimeo\.com\/[\d]+/;
var matches = videoUrl.match( rPlayerUri ) ? videoUrl.match( rPlayerUri )[ 0 ].substr( 30 ) : "";
return matches ? matches : videoUrl.match( rWebUrl ) ? videoUrl.match( rWebUrl )[ 0 ].substr( 10 ) : "";
}
if ( !( src = extractId( src ) ) ) {
throw "Invalid Video Id";
}
flashvars = {
clip_id: src,
show_portrait: 1,
show_byline: 1,
show_title: 1,
js_api: 1,
js_swf_id: vimeoContainer.id
};
params = {
allowscriptaccess: "always",
allowfullscreen: "true",
wmode: "transparent"
};
}
}
return {
addEventListener: function( evtName, fn, doFire ) {
evtName = evtName.toLowerCase();
swfobject.embedSWF( "http://vimeo.com/moogaloop.swf", vimeoContainer.id,
media.offsetWidth + "", media.offsetHeight + "", "9.0.0", "expressInstall.swf",
flashvars, params, attributes );
makeHandler.call( this, evtName );
evts[evtName].push( fn );
vimeoContainer.addEventListener( "load", function() {
console.log("asdfasdf");
});
if ( doFire ) {
dispatchEvent( evtName );
}
};
return fn;
},
// Add many listeners for a single event
// Takes an event name and array of functions
addEventListeners: function( evtName, events ) {
evtName = evtName.toLowerCase();
makeHandler.call( this, evtName );
evts[evtName] = evts[evtName].concat( events );
},
removeEventListener: function( evtName, fn ) {
var evtArray = this.getEventListeners( evtName ),
i,
l;
// Find and remove from events array
for ( i = 0, l = evtArray.length; i < l; i++) {
if ( evtArray[i] === fn ) {
var removed = evtArray[i];
evtArray[i] = 0;
return removed;
}
}
},
getEventListeners: function( evtName ) {
if( evtName ) {
return evts[ evtName.toLowerCase() ] || [];
} else {
return evts;
}
},
dispatchEvent: function( evt, args ) {
// If event object was passed in, toString will yield event type as string (timeupdate)
// If a string, toString() will return the string itself (timeupdate)
evt = "on"+evt.toString().toLowerCase();
this[evt] && this[evt]( args );
}
};
};
Popcorn.vimeo = function( mediaId, list, options ) {
return new Popcorn.vimeo.init( mediaId, list, options );
};
Popcorn.vimeo.onLoad = function( playerId ) {
var player = registry[ playerId ];
player.swfObj = document.getElementById( playerId );
// For calculating position relative to video (like subtitles)
player.offsetWidth = player.swfObj.offsetWidth;
player.offsetHeight = player.swfObj.offsetHeight;
player.offsetParent = player.swfObj.offsetParent;
player.offsetLeft = player.swfObj.offsetLeft;
player.offsetTop = player.swfObj.offsetTop;
player.dispatchEvent( "load" );
};
Popcorn.getScript( "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js" );
// A constructor, but we need to wrap it to allow for "static" functions
Popcorn.vimeo.init = (function() {
var rPlayerUri = /^http:\/\/player\.vimeo\.com\/video\/[\d]+/i,
rWebUrl = /vimeo\.com\/[\d]+/,
hasAPILoaded = false;
// Extract the numeric video id from container uri: 'http://player.vimeo.com/video/11127501' or 'http://player.vimeo.com/video/4282282'
// Expect id to be a valid 32/64-bit unsigned integer
// Returns string, empty string if could not match
function extractIdFromUri( uri ) {
if ( !uri ) {
return;
}
var matches = uri.match( rPlayerUri );
return matches ? matches[0].substr(30) : "";
}
// Extract the numeric video id from url: 'http://vimeo.com/11127501' or simply 'vimeo.com/4282282'
// Ignores protocol and subdomain, but one would expecct it to be http://www.vimeo.com/#######
// Expect id to be a valid 32/64-bit unsigned integer
// Returns string, empty string if could not match
function extractIdFromUrl( url ) {
if ( !url ) {
return;
}
var matches = url.match( rWebUrl );
return matches ? matches[0].substr(10) : "";
}
function makeSwf( self, vidId, containerId ) {
if ( !window.swfobject ) {
setTimeout( function() {
makeSwf( self, vidId, containerId );
}, 1);
return;
}
var params,
flashvars,
attributes = {};
flashvars = {
clip_id: vidId,
show_portrait: 1,
show_byline: 1,
show_title: 1,
// required in order to use the Javascript API
js_api: 1,
// moogaloop will call this JS function when it's done loading (optional)
js_onLoad: 'Popcorn.vimeo.onLoad',
// this will be passed into all event methods so you can keep track of multiple moogaloops (optional)
js_swf_id: containerId
};
params = {
allowscriptaccess: 'always',
allowfullscreen: 'true',
// This is so we can overlay html ontop o fFlash
wmode: 'transparent'
};
swfobject.embedSWF( "http://vimeo.com/moogaloop.swf", containerId, self.offsetWidth, self.offsetHeight, "9.0.0", "expressInstall.swf", flashvars, params, attributes );
}
// If container id is not supplied, assumed to be same as player id
var ctor = function ( containerId, videoUrl, options ) {
if ( !containerId ) {
throw "Must supply an id!";
} else if ( /file/.test( location.protocol ) ) {
throw "Must run from a web server!";
}
var vidId,
that = this,
tmp;
this._container = document.createElement( "div" );
this._container.id = containerId + "object";
this._target = document.getElementById( containerId );
this._target.appendChild( this._container );
options = options || {};
options.css && Popcorn.extend( this._target.style, options.css );
this.addEventFn = null;
this.evtHolder = null;
this.paused = true;
this.duration = Number.MAX_VALUE;
this.ended = 0;
this.currentTime = 0;
this.volume = 1;
this.loop = 0;
this.initialTime = 0;
this.played = 0;
this.readyState = 0;
this.parentNode = this._target.parentNode;
this.previousCurrentTime = this.currentTime;
this.previousVolume = this.volume;
this.evtHolder = new EventManager( this );
// For calculating position relative to video (like subtitles)
this.width = this._target.style.width || "504px";
this.height = this._target.style.height || "340px";
if ( !/[\d]%/.test( this.width ) ) {
this.offsetWidth = parseInt( this.width, 10 );
this._target.style.width = this.width + "px";
Popcorn.getScript( "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", vimeoInit );
} else {
// convert from pct to abs pixels
tmp = this._target.style.width;
this._target.style.width = this.width;
this.offsetWidth = this._target.offsetWidth;
this._target.style.width = tmp;
}
if ( !/[\d]%/.test( this.height ) ) {
this.offsetHeight = parseInt( this.height, 10 );
this._target.style.height = this.height + "px";
} else {
// convert from pct to abs pixels
tmp = this._target.style.height;
this._target.style.height = this.height;
this.offsetHeight = this._target.offsetHeight;
this._target.style.height = tmp;
}
this.offsetLeft = 0;
this.offsetTop = 0;
// Try and get a video id from a vimeo site url
// Try either from ctor param or from iframe itself
vidId = extractIdFromUrl( videoUrl ) || extractIdFromUri( videoUrl );
if ( !vidId ) {
throw "No video id";
}
registry[ this._container.id ] = this;
makeSwf( this, vidId, this._container.id );
// Set up listeners to internally track state as needed
this.addEventListener( "load", function() {
var hasLoaded = false;
that.duration = that.swfObj.api_getDuration();
that.evtHolder.dispatchEvent( "durationchange" );
that.evtHolder.dispatchEvent( "loadedmetadata" );
// Chain events and calls together so that this.currentTime reflects the current time of the video
// Done by Getting the Current Time while the video plays
that.addEventListener( "timeupdate", function() {
that.currentTime = that.swfObj.api_getCurrentTime();
});
// Add pause listener to keep track of playing state
that.addEventListener( "pause", function() {
that.paused = true;
});
// Add play listener to keep track of playing state
that.addEventListener( "playing", function() {
that.paused = false;
that.ended = 0;
});
// Add ended listener to keep track of playing state
that.addEventListener( "ended", function() {
if ( that.loop !== "loop" ) {
that.paused = true;
that.ended = 1;
}
});
// Add progress listener to keep track of ready state
that.addEventListener( "progress", function( data ) {
if ( !hasLoaded ) {
hasLoaded = 1;
that.readyState = 3;
that.evtHolder.dispatchEvent( "readystatechange" );
}
// Check if fully loaded
if ( data.percent === 100 ) {
that.readyState = 4;
that.evtHolder.dispatchEvent( "readystatechange" );
that.evtHolder.dispatchEvent( "canplaythrough" );
}
});
});
};
return ctor;
})();
Popcorn.vimeo.init.prototype = Popcorn.vimeo.prototype;
// Sequence object prototype
Popcorn.extend( Popcorn.vimeo.prototype, {
// Do everything as functions instead of get/set
setLoop: function( val ) {
if ( !val ) {
return;
}
this.loop = val;
var isLoop = val === "loop" ? 1 : 0;
// HTML convention says to loop if value is 'loop'
this.swfObj.api_setLoop( isLoop );
},
// Set the volume as a value between 0 and 1
setVolume: function( val ) {
if ( !val && val !== 0 ) {
return;
}
// Normalize in case outside range of expected values
if ( val < 0 ) {
val = -val;
}
if ( val > 1 ) {
val %= 1;
}
// HTML video expects to be 0.0 -> 1.0, Vimeo expects 0-100
this.volume = this.previousVolume = val;
this.swfObj.api_setVolume( val*100 );
this.evtHolder.dispatchEvent( "volumechange" );
},
// Seeks the video
setCurrentTime: function ( time ) {
if ( !time && time !== 0 ) {
return;
}
this.currentTime = this.previousCurrentTime = time;
this.ended = time >= this.duration;
this.swfObj.api_seekTo( time );
// Fire events for seeking and time change
this.evtHolder.dispatchEvent( "seeked" );
this.evtHolder.dispatchEvent( "timeupdate" );
},
// Play the video
play: function() {
// In case someone is cheeky enough to try this before loaded
if ( !this.swfObj ) {
this.addEventListener( "load", this.play );
return;
}
if ( !this.played ) {
this.played = 1;
this.startTimeUpdater();
this.evtHolder.dispatchEvent( "loadstart" );
}
this.evtHolder.dispatchEvent( "play" );
this.swfObj.api_play();
},
// Pause the video
pause: function() {
// In case someone is cheeky enough to try this before loaded
if ( !this.swfObj ) {
this.addEventListener( "load", this.pause );
return;
}
this.swfObj.api_pause();
},
// Toggle video muting
// Unmuting will leave it at the old value
mute: function() {
// In case someone is cheeky enough to try this before loaded
if ( !this.swfObj ) {
this.addEventListener( "load", this.mute );
return;
}
if ( !this.muted() ) {
this.oldVol = this.volume;
if ( this.paused ) {
this.setVolume( 0 );
} else {
this.volume = 0;
}
} else {
if ( this.paused ) {
this.setVolume( this.oldVol );
} else {
this.volume = this.oldVol;
}
}
},
muted: function() {
return this.volume === 0;
},
// Force loading by playing the player. Pause afterwards
load: function() {
// In case someone is cheeky enough to try this before loaded
if ( !this.swfObj ) {
this.addEventListener( "load", this.load );
return;
}
this.play();
this.pause();
},
unload: function() {
// In case someone is cheeky enough to try this before loaded
if ( !this.swfObj ) {
this.addEventListener( "load", this.unload );
return;
}
this.pause();
this.swfObj.api_unload();
this.evtHolder.dispatchEvent( "abort" );
this.evtHolder.dispatchEvent( "emptied" );
},
// Hook an event listener for the player event into internal event system
// Stick to HTML conventions of add event listener and keep lowercase, without prependinng "on"
addEventListener: function( evt, fn ) {
var playerEvt,
that = this;
// In case event object is passed in
evt = evt.type || evt.toLowerCase();
// If it's an HTML media event supported by player, map
if ( evt === "seeked" ) {
playerEvt = "onSeek";
} else if ( evt === "timeupdate" ) {
playerEvt = "onProgress";
} else if ( evt === "progress" ) {
playerEvt = "onLoading";
} else if ( evt === "ended" ) {
playerEvt = "onFinish";
} else if ( evt === "playing" ) {
playerEvt = "onPlay";
} else if ( evt === "pause" ) {
// Direct mapping, CamelCase the event name as vimeo API expects
playerEvt = "on"+evt[0].toUpperCase() + evt.substr(1);
}
// Vimeo only stores 1 callback per event
// Have vimeo call internal collection of callbacks
this.evtHolder.addEventListener( evt, fn, false );
// Link manual event structure with Vimeo's if not already
if( playerEvt && this.evtHolder.getEventListeners( evt ).length === 1 ) {
// Setup global functions on Popcorn.vimeo to sync player events to an internal collection
// Some events expect 2 args, some only one (the player id)
if ( playerEvt === "onSeek" || playerEvt === "onProgress" || playerEvt === "onLoading" ) {
Popcorn.vimeo[playerEvt] = function( arg1, arg2 ) {
var player = registry[arg2];
player.evtHolder.dispatchEvent( evt, arg1 );
};
} else {
Popcorn.vimeo[playerEvt] = function( arg1 ) {
var player = registry[arg1];
player.evtHolder.dispatchEvent( evt );
};
}
this.swfObj.api_addEventListener( playerEvt, "Popcorn.vimeo."+playerEvt );
}
},
removeEventListener: function( evtName, fn ) {
return this.evtHolder.removeEventListener( evtName, fn );
},
dispatchEvent: function( evtName ) {
return this.evtHolder.dispatchEvent( evtName );
},
getBoundingClientRect: function() {
return this._target.getBoundingClientRect();
},
startTimeUpdater: function() {
var self = this,
seeked = 0;
if ( abs( this.currentTime - this.previousCurrentTime ) > timeCheckInterval ) {
// Has programatically set the currentTime
this.setCurrentTime( this.currentTime );
seeked = 1;
} else {
this.previousCurrentTime = this.currentTime;
}
if ( this.volume !== this.previousVolume ) {
this.setVolume( this.volume );
}
if ( !self.paused || seeked ) {
this.dispatchEvent( 'timeupdate' );
}
if( !self.ended ) {
setTimeout( function() {
self.startTimeUpdater.call(self);
}, timeupdateInterval);
vimeoInit();
}
}
});
})( Popcorn, window );
})();

Просмотреть файл

@ -1,28 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>Popcorn API</title>
<title>Vimeo Player Unit Test Suite</title>
<link rel="stylesheet" href="../../test/qunit/qunit.css" type="text/css" media="screen">
<script src="../../test/qunit/qunit.js"></script>
<!--
do not move - this must be called immediately prior to
<!--
do not move - this must be called immediately prior to
popcorn-api-draft.js
-->
<script src="../../popcorn.js"></script>
<script src="popcorn.vimeo.unit.js"></script>
<script src="popcorn.vimeo.js"></script>
</head>
<body>
<h1 id="qunit-header">Popcorn Vimeo Player Plugin</h1>
<h1 id="qunit-header">Popcorn Vimeo Player Unit Tests</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture"> </div>
<div id="player_1"></div>
<div id="player_1" style="width: 400px; height: 400px;"></div>
<div id="player_2" style="width: 400px; height: 400px;"></div>
</body>
</html>

Просмотреть файл

@ -1,159 +1,366 @@
test("Popcorn Vimeo Plugin", function () {
function makeHandler( evtName ) {
return( function() {
var count = 0;
return function() {
count++;
if ( count === 1 ) {
ok( true, "Event '"+evtName+"' is supported" );
plus();
}
}
})();
}
test("Update Timer", function () {
QUnit.reset();
var p2 = Popcorn.vimeo( "#player_1", "http://player.vimeo.com/video/6960892" ),
expects = 12,
count = 0,
execCount = 0,
// These make sure events are only fired once
// any second call will produce a failed test
forwardStart = false,
forwardEnd = false,
backwardStart = false,
backwardEnd = false,
wrapperRunning = { one: false, two: false, };
function plus() {
if ( ++count === expects ) {
// clean up added events after tests
Popcorn.removePlugin( "forwards" );
Popcorn.removePlugin( "backwards" );
Popcorn.removePlugin( "wrapper" );
p2.removePlugin( "exec" );
p2.pause();
start();
}
}
var popped = Popcorn( Popcorn.vimeo( "player_1", "http://vimeo.com/11127501" ) ),
expects = 22,
playCount = 0,
pauseCount = 0,
count = 0,
events = {
"durationchange": makeHandler( "durationchange" ),
"play": makeHandler( "play" ),
"loadstart": function() {
(makeHandler( "loadstart" ))();
this.play();
},
"readystatechange": makeHandler( "readystatechange" ),
"volumechange": (function() {
var timesCalled = 0;
return function() {
timesCalled++;
if (timesCalled === 1) {
ok( true, "Volume changed event works" );
plus();
equals( popped.volume(), 0, "Volume correctly set" );
plus();
ok( popped.video.muted(), "Muted set when player volume 0" );
plus();
popped.volume( 0.333 );
} else if ( timesCalled === 2 ) {
ok( !popped.video.muted(), "Unmuted when volume not 0" );
plus();
popped.mute();
} else if ( timesCalled === 3 ) {
ok( popped.video.muted(), "Mute mutes when volume is non-zero" );
plus();
popped.mute();
} else if ( timesCalled === 4 ) {
equals( popped.volume(), 0.333, "Mute unmutes to last volume" );
plus();
popped.exec( 4, function() {
popped.video.unload();
});
}
};
})(),
"emptied": makeHandler( "emptied" ),
"ended": 0,
"pause": (function() {
var timesCalled = 0;
return function() {
timesCalled++;
if ( timesCalled === 1 ) {
ok( true, "Pause event works" );
plus();
ok( popped.video.paused, "Pause attribute set" );
plus();
popped.play();
}
};
})(),
"playing": (function() {
var timesCalled = 0;
return function() {
timesCalled++;
if ( timesCalled === 1 ) {
ok( true, "Play event works" );
plus();
ok( true, "Video autoplay attribute works" );
plus();
ok( !popped.video.paused, "Player paused attribute not set" );
plus();
popped.exec( 5, function() {
popped.currentTime( 0 );
popped.pause();
});
} else if ( timesCalled === 2 ) {
ok( true, "Popcorn play function works" );
plus();
popped.volume( 0 );
}
};
})(),
"progress": makeHandler( "progress" ),
"seeked": makeHandler( "seeked" ),
"timeupdate": makeHandler( "timeupdate" )
};
expect( expects );
stop( 20000 );
ok( "vimeo" in Popcorn, "Vimeo is a method of Popcorn" );
plus();
equals( popped.video.initialTime, 0, "Player initial time is 0" );
plus();
Popcorn.plugin( "timingTest", {
// These tests come close to 10 seconds on chrome, increasing to 15
stop();
Popcorn.plugin( "forwards", function () {
return {
start: function ( event, options ) {
if ( !options.startFired ) {
options.startFired = true;
forwardStart = !forwardStart;
ok( forwardStart, "forward's start fired" );
plus();
}
},
end: function ( event, options ) {
if ( !options.endFired ) {
options.endFired = true;
forwardEnd = !forwardEnd;
p2.currentTime(1).play();
ok( forwardEnd, "forward's end fired" );
plus();
}
}
};
});
p2.forwards({
start: 3,
end: 4
});
Popcorn.plugin( "backwards", function () {
return {
start: function ( event, options ) {
if ( !options.startFired ) {
options.startFired = true;
backwardStart = !backwardStart;
ok( true, "backward's start fired" );
plus();
}
},
end: function ( event, options ) {
if ( !options.endFired ) {
options.endFired = true;
backwardEnd = !backwardEnd;
ok( backwardEnd, "backward's end fired" );
plus();
p2.currentTime( 0 ).play();
}
}
};
});
p2.backwards({
start: 1,
end: 2
});
Popcorn.plugin( "wrapper", {
start: function ( event, options ) {
ok( true, "Popcorn plugin started" );
plus();
wrapperRunning[ options.wrapper ] = true;
},
end: function ( event, options ) {
ok( true, "Popcorn plugin stopped" );
wrapperRunning[ options.wrapper ] = false;
}
});
// second instance of wrapper is wrapping the first
p2.wrapper({
start: 6,
end: 7,
wrapper: "one"
})
.wrapper({
start: 5,
end: 8,
wrapper: "two"
})
// checking wrapper 2's start
.exec( 5, function() {
if ( execCount === 0 ) {
execCount++;
ok( wrapperRunning.two, "wrapper two is running at second 5" );
plus();
ok( !wrapperRunning.one, "wrapper one is stopped at second 5" );
plus();
}
})
// checking wrapper 1's start
.exec( 6, function() {
if ( execCount === 1 ) {
execCount++;
ok( wrapperRunning.two, "wrapper two is running at second 6" );
plus();
ok( wrapperRunning.one, "wrapper one is running at second 6" );
plus();
}
})
// checking wrapper 1's end
.exec( 7, function() {
if ( execCount === 2 ) {
execCount++;
ok( wrapperRunning.two, "wrapper two is running at second 7" );
plus();
ok( !wrapperRunning.one, "wrapper one is stopped at second 7" );
plus();
}
})
// checking wrapper 2's end
.exec( 8, function() {
if ( execCount === 3 ) {
execCount++;
ok( !wrapperRunning.two, "wrapper two is stopped at second 9" );
plus();
ok( !wrapperRunning.one, "wrapper one is stopped at second 9" );
plus();
}
});
popped.timingTest({
start: 3, // seconds
end: 4, // seconds
p2.exec( 3, function() {
p2.play();
});
popped.listen( "load", function() {
ok ( this.video.swfObj.id === popped.video.swfObj.id, "Correctly kept track of 'this'" );
p2.currentTime(3);
});
test("Plugin Factory", function () {
QUnit.reset();
var popped = Popcorn.vimeo( "#player_1", "http://player.vimeo.com/video/6960892" ),
methods = "load play pause currentTime mute volume roundTime exec removePlugin",
expects = 34, // 15*2+2+2. executor/complicator each do 15
count = 0;
function plus() {
if ( ++count == expects ) {
Popcorn.removePlugin("executor");
Popcorn.removePlugin("complicator");
popped.pause();
start();
}
}
expect( expects );
stop( 15000 );
Popcorn.plugin("executor", function () {
return {
start: function () {
var self = this;
// These ensure that a popcorn instance is the value of `this` inside a plugin definition
methods.split(/\s+/g).forEach(function (k,v) {
ok( k in self, "executor instance has method: " + k );
plus();
});
ok( "media" in this, "executor instance has `media` property" );
plus();
ok( Object.prototype.toString.call(popped.media) === "[object Object]", "video property is a HTML DIV element" );
plus();
ok( "data" in this, "executor instance has `data` property" );
plus();
ok( Object.prototype.toString.call(popped.data) === "[object Object]", "data property is an object" );
plus();
ok( "trackEvents" in this.data, "executor instance has `trackEvents` property" );
plus();
ok( Object.prototype.toString.call(popped.data.trackEvents) === "[object Object]", "executor trackEvents property is an object" )
plus();
},
end: function () {
}
};
});
ok( "executor" in popped, "executor plugin is now available to instance" );
plus();
equals( Popcorn.registry.length, 1, "One item in the registry");
plus();
popped.executor({
start: 1,
end: 2
});
Popcorn.plugin("complicator", {
start: function ( event ) {
var self = this;
// These ensure that a popcorn instance is the value of `this` inside a plugin definition
methods.split(/\s+/g).forEach(function (k,v) {
ok( k in self, "complicator instance has method: " + k );
plus();
});
ok( "media" in this, "complicator instance has `media` property" );
plus();
ok( Object.prototype.toString.call(popped.media) === "[object Object]", "video property is a HTMLVideoElement" );
plus();
ok( "data" in this, "complicator instance has `data` property" );
plus();
ok( Object.prototype.toString.call(popped.data) === "[object Object]", "complicator data property is an object" );
plus();
ok( "trackEvents" in this.data, " complicatorinstance has `trackEvents` property" );
plus();
ok( Object.prototype.toString.call(popped.data.trackEvents) === "[object Object]", "complicator trackEvents property is an object" )
plus();
},
end: function () {
//start();
},
timeupdate: function () {
}
});
ok( "complicator" in popped, "complicator plugin is now available to instance" );
plus();
equals( Popcorn.registry.length, 2, "Two items in the registry");
plus();
popped.complicator({
start: 4,
end: 5
});
popped.currentTime(0).play();
});
test( "Popcorn vimeo Plugin Url and Duration Tests", function() {
function plus(){
if ( ++count == expects ) {
popcorn.pause();
start();
}
}
QUnit.reset();
var count = 0,
expects = 3,
popcorn = Popcorn.vimeo( "#player_1", "http://player.vimeo.com/video/6960892" );
expect( expects );
stop( 10000 );
equals( popcorn.media.id, "player_1", "Video id set" );
plus();
equals( popcorn.duration(), 0, "Duration starts as 0");
plus();
popcorn.listen( "durationchange", function() {
notEqual( popcorn.duration(), 0, "Duration has been changed from 0" );
plus();
Popcorn.forEach( events, function( fn, evtName ) {
fn && popped.listen( evtName, fn );
popcorn.pause();
});
popcorn.play();
});
test( "Popcorn vimeo Plugin Url Regex Test", function() {
QUnit.reset();
var urlTests = [
{ name: 'standard',
url: 'http://player.vimeo.com/video/6960892',
expected: 'http://player.vimeo.com/video/6960892',
},
{ name: 'short url',
url: 'http://vimeo.com/6960892',
expected: 'http://vimeo.com/6960892',
}
];
var count = 0,
expects = urlTests.length;
expect( expects );
stop( 10000 );
Popcorn.forEach( urlTests, function( values, key ) {
var urlTest = urlTests[ key ],
popcorn = Popcorn.vimeo( '#player_2', urlTest.url );
popcorn.listen( "loadeddata", function() {
equals( popcorn.media.src, urlTest.expected, 'Video id is correct for ' + urlTest.name + ': ' + urlTest.url );
popcorn.pause();
count++;
if ( count === expects ) {
start();
popcorn.pause();
}
});
// Queue load
// Load event will play when beginning to load
popped.load();
});
});