Merge branch 'develop' of git://github.com/cadecairos/popcorn-js into 1.2

* 'develop' of git://github.com/cadecairos/popcorn-js:
  [] Rewrites bulk of Popcorn.removeTrackEvent(), improves performance, fixes byEnd event issue.
  [] Don't assume a sequential index reference for track events.
  [] Failing tests. http://gyazo.com/66c76333dd7173e3fab1001d3ea0c8fc.png?1328905037
  [] fixed whitespace, comma and file moved back to proper location
  [] moved parser into modules, updated tests, etc.
  [] removed popcorn.player.html. It does not make sense.
  [] removed player from archaic test
  [] moved player into modules, tests, updated all touching files
  Extended timeout for subtitle unit tests []
  Removed popcorn.timeline.css []
This commit is contained in:
Rick Waldron waldron.rick@gmail.com 2012-02-26 22:07:59 -05:00
Родитель 4318846767 d79edc924b
Коммит 5c686806ab
40 изменённых файлов: 3527 добавлений и 734 удалений

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

@ -5,6 +5,7 @@
<meta charset="UTF-8" />
<script src="http://code.jquery.com/jquery.js"></script>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/webpage/popcorn.webpage.js"></script>
<script src="../../plugins/googlemap/popcorn.googlemap.js"></script>

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

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

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

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

@ -0,0 +1,103 @@
(function( Popcorn ) {
var
AP = Array.prototype,
OP = Object.prototype,
forEach = AP.forEach,
slice = AP.slice,
hasOwn = OP.hasOwnProperty,
toString = OP.toString;
// stores parsers keyed on filetype
Popcorn.parsers = {};
// An interface for extending Popcorn
// with parser functionality
Popcorn.parser = function( name, type, definition ) {
if ( Popcorn.protect.natives.indexOf( name.toLowerCase() ) >= 0 ) {
Popcorn.error( "'" + name + "' is a protected function name" );
return;
}
// fixes parameters for overloaded function call
if ( typeof type === "function" && !definition ) {
definition = type;
type = "";
}
if ( typeof definition !== "function" || typeof type !== "string" ) {
return;
}
// Provides some sugar, but ultimately extends
// the definition into Popcorn.p
var natives = Popcorn.events.all,
parseFn,
parser = {};
parseFn = function( filename, callback ) {
if ( !filename ) {
return this;
}
var that = this;
Popcorn.xhr({
url: filename,
dataType: type,
success: function( data ) {
var tracksObject = definition( data ),
tracksData,
tracksDataLen,
tracksDef,
idx = 0;
tracksData = tracksObject.data || [];
tracksDataLen = tracksData.length;
tracksDef = null;
// If no tracks to process, return immediately
if ( !tracksDataLen ) {
return;
}
// Create tracks out of parsed object
for ( ; idx < tracksDataLen; idx++ ) {
tracksDef = tracksData[ idx ];
for ( var key in tracksDef ) {
if ( hasOwn.call( tracksDef, key ) && !!that[ key ] ) {
that[ key ]( tracksDef[ key ] );
}
}
}
if ( callback ) {
callback();
}
}
});
return this;
};
// Assign new named definition
parser[ name ] = parseFn;
// Extend Popcorn.p with new named definition
Popcorn.extend( Popcorn.p, parser );
// keys the function name by filetype extension
//Popcorn.parsers[ name ] = true;
return parser;
};
})( Popcorn );

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

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<title>Popcorn Module: Timeline-Sources</title>
<link rel="stylesheet" href="../../test/qunit/qunit.css" type="text/css" media="screen">
<script src="../../test/qunit/qunit.js"></script>
<script src="../../popcorn.js"></script>
<script src="popcorn.parser.js"></script>
<script src="popcorn.parser.unit.js"></script>
</head>
<body>
<h1 id="qunit-header">Popcorn Module: player</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>
<video id="video"
style="display:;width:300px"
controls
preload="auto">
<source id="mp4"
src="../../test/trailer.mp4"
type='video/mp4; codecs="avc1, mp4a"'>
<source id="ogv"
src="../../test/trailer.ogv"
type='video/ogg; codecs="theora, vorbis"'>
<source id="webm"
src="../../test/trailer.webm"
type='video/webm; codecs="vp8, vorbis"'>
<p>Your user agent does not support the HTML5 Video element.</p>
</video>
<audio id="audio" data-timeline-sources="data/parserData.json" controls>
<source src="../../test/italia.mp4" type='audio/mp4; codecs="mp4a.40.2"'>
<source src="../../test/italia.ogg" type='audio/ogg; codecs="vorbis"'>
</audio>
</body>
</html>

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

@ -0,0 +1,162 @@
module( "Popcorn Parser" );
test( "Parsing Functions", function() {
var expects = 3,
count = 0,
popperly = Popcorn( "#video" );
function plus() {
if ( ++count === expects ) {
start();
}
}
expect( expects );
stop( 10000 );
ok( typeof Popcorn.parser === "function", "Popcorn.parser is a function" );
plus();
Popcorn.parser( "parseJSON" , "json", function( data ){
return data;
});
ok( typeof popperly.parseJSON === "function", "Popcorn.parser created a parseJSON function" );
plus();
ok( typeof popperly.parseJSON().parseJSON( "data/test.js" ).parseJSON === "function" , "parseJSON function is chainable" );
plus();
});
test( "Parsing Integrity", function() {
var expects = 6,
count = 0,
timeOut = 0,
poppercore = Popcorn( "#video" );
function plus() {
if ( ++count === expects ) {
start();
// clean up added events after tests
Popcorn.removePlugin( "parserTest" );
}
}
expect( expects );
stop( 10000 );
Popcorn.parser( "parseJSON2", function( data ){
ok( typeof data.json === "object", "data.json exists" );
plus();
return data.json;
});
Popcorn.parser( "parseJSON3" , "json", function( data ){
ok( typeof data === "object", "data exists" );
plus();
return data;
});
Popcorn.plugin( "parserTest", {
start: function() {
ok( true, "parserTest started" );
plus();
},
end: function() {
ok( true, "parserTest ended" );
plus();
}
});
poppercore.parseJSON2( "data/parserData.json", function() {
poppercore.parseJSON3( "data/parserData.json", function() {
poppercore.currentTime( 5 ).play();
});
});
});
test( "Parsing Handler - References unavailable plugin", function() {
var expects = 1,
count = 0,
timeOut = 0,
interval,
poppercore = Popcorn( "#video" );
function plus() {
if ( ++count === expects ) {
start();
// clean up added events after tests
clearInterval( interval );
poppercore.removePlugin( "parserTest" );
}
}
expect( expects );
stop();
Popcorn.parser( "parseJson", function( data ){
return data.json;
});
poppercore.parseJson( "data/parseMissing.json" );
// interval used to wait for data to be parsed
interval = setInterval( function() {
poppercore.currentTime( 5 ).play().currentTime( 6 );
ok( true, "Ignored call to missing plugin " );
plus();
}, 2000 );
});
test( "Parser Support - audio", function() {
var expects = 3,
count = 0,
timeOut = 0,
interval,
audiocorn = Popcorn( "#audio" );
function plus() {
if ( ++count === expects ) {
start();
Popcorn.removePlugin( "testAudioParser" );
}
}
expect( expects );
stop( 5000 );
Popcorn.plugin( "testAudioParser", {
start: function() {
ok( true, "testAudioParser started: " + Math.round( this.currentTime() ) );
plus();
},
end: function() {
ok( true, "testAudioParser ended: " + Math.round( this.currentTime() ) );
plus();
}
});
Popcorn.parser( "parseAudio", function( data ){
ok( typeof data.json === "object", "data.json exists");
plus();
return data.json;
});
audiocorn.parseAudio( "data/parserAudio.json", function() {
audiocorn.currentTime( 4 ).play();
});
});

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

@ -0,0 +1,235 @@
(function( Popcorn ) {
Popcorn.player = function( name, player ) {
// ID string matching
var rIdExp = /^(#([\w\-\_\.]+))$/;
player = player || {};
var playerFn = function( target, src, options ) {
options = options || {};
// List of events
var date = new Date() / 1000,
baselineTime = date,
currentTime = 0,
volume = 1,
muted = false,
events = {},
// The container div of the resource
container = document.getElementById( rIdExp.exec( target ) && rIdExp.exec( target )[ 2 ] ) ||
document.getElementById( target ) ||
target,
basePlayer = {},
timeout,
popcorn;
// copies a div into the media object
for( var val in container ) {
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
});
// Adds an event listener to the object
basePlayer.addEventListener = function( evtName, fn ) {
if ( !events[ evtName ] ) {
events[ evtName ] = [];
}
events[ evtName ].push( fn );
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 );
}
}
Popcorn.forEach( events[ eventName ], function( val ) {
val.call( self, evt, self );
});
};
// Attempt to get src from playerFn parameter
basePlayer.src = src || "";
basePlayer.readyState = 0;
basePlayer.duration = 0;
basePlayer.paused = true;
basePlayer.ended = 0;
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( "load" );
basePlayer.dispatchEvent( "loadeddata" );
}
// when a custom player is loaded, load basePlayer state into custom player
basePlayer.addEventListener( "load", function() {
// if a player is not ready before currentTime is called, this will set it after it is ready
basePlayer.currentTime = currentTime;
// same as above with volume and muted
basePlayer.volume = volume;
basePlayer.muted = muted;
});
basePlayer.addEventListener( "loadeddata", function() {
// if play was called before player ready, start playing video
!basePlayer.paused && basePlayer.play();
});
popcorn = new Popcorn.p.init( basePlayer, options );
return popcorn;
};
Popcorn[ name ] = Popcorn[ name ] || playerFn;
};
Popcorn.player.defineProperty = Object.defineProperty || function( object, description, options ) {
object.__defineGetter__( description, options.get || Popcorn.nop );
object.__defineSetter__( description, options.set || Popcorn.nop );
};
})( Popcorn );

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

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>Popcorn Module: Timeline-Sources</title>
<link rel="stylesheet" href="../../test/qunit/qunit.css" type="text/css" media="screen">
<script src="../../test/qunit/qunit.js"></script>
<script src="../../popcorn.js"></script>
<script src="popcorn.player.js"></script>
<script src="popcorn.player.unit.js"></script>
</head>
<body>
<h1 id="qunit-header">Popcorn Module: player</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='video'></div>
</body>
</html>

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

@ -0,0 +1,189 @@
module( "Popcorn Player" );
test( "Base player methods", function() {
var expects = 2;
expect( expects );
stop( 10000 );
ok( Popcorn.player, "Popcorn.player function exists" );
Popcorn.player( "newplayer" );
ok( Popcorn.newplayer, "Popcorn.player registers new players" );
start();
});
test( "Base player functionality", function() {
Popcorn.player( "baseplayer" );
//QUnit.reset();
var p2 = Popcorn.baseplayer( "#video" ),
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" );
start();
}
}
// These tests come close to 10 seconds on chrome, increasing to 15
stop( 15000 );
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;
p2.currentTime( 0 ).play();
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( 5 ).play();
}
}
};
});
p2.backwards({
start: 1,
end: 2
});
Popcorn.plugin( "wrapper", {
start: function( event, options ) {
wrapperRunning[ options.wrapper ] = true;
},
end: function( event, options ) {
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();
}
});
p2.currentTime( 3 ).play();
});

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

@ -6,6 +6,7 @@
<script src="../../test/qunit/qunit.js"></script>
<script src="../../popcorn.js"></script>
<script src="../parser/popcorn.parser.js"></script>
<script src="popcorn.timeline-sources.js"></script>
<script src="popcorn.timeline-sources.unit.js"></script>
<script src="../../parsers/parserJSON/popcorn.parserJSON.js"></script>

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

@ -0,0 +1,49 @@
{
"title":"Crockford Lives!",
"remote":"http://dl.dropbox.com/u/3531958/crockford.ogv",
"data": [
{
"webpage": {
"start":"0.0897589878863602",
"end":"2.001204869833337",
"target":"iframe-container",
"src":"http://json.org"
}
},
{
"footnote": {
"start":"0.23530116023787565",
"end":"2.0193976413772767",
"target":"footnote-container",
"text":"I invented JSON"
}
},
{
"googlemap": {
"start":"0.09096385771969716",
"end":"8.617349362660605",
"target":"map-container",
"type":"ROADMAP",
"lat":37.7749295,
"lng":-122.4194155,
"location":"San Francisco, CA"
}
},
{
"webpage": {
"start":"2.073975956009095",
"end":"10.278915922325776",
"target":"iframe-container",
"src":"http://jslint.org"
}
},
{
"footnote": {
"start":2.145542172351516,
"end":10.145542172351513,
"target":"footnote-container",
"text":"I wrote JSLint"
}
}
]
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -4,6 +4,7 @@
<title>Popcorn 1.0 JSON parser Plug-in Demo</title>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../modules/timeline-sources/popcorn.timeline-sources.js"></script>
<script src="../../plugins/webpage/popcorn.webpage.js"></script>
<script src="../../plugins/footnote/popcorn.footnote.js"></script>

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

@ -11,6 +11,7 @@
<script src="../../test/jquery.js"></script>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../modules/timeline-sources/popcorn.timeline-sources.js"></script>
<script src="../../plugins/webpage/popcorn.webpage.js"></script>
<script src="../../plugins/footnote/popcorn.footnote.js"></script>

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

@ -4,6 +4,7 @@
<title>Popcorn 1.0 SBV parser Plug-in Demo</title>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="popcorn.parserSBV.js"></script>

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

@ -10,6 +10,7 @@
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="popcorn.parserSBV.js"></script>

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

@ -4,6 +4,7 @@
<title>Popcorn 1.0 SRT parser Plug-in Demo</title>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="popcorn.parserSRT.js"></script>

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

@ -10,6 +10,7 @@ popcorn-api-draft.js
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="popcorn.parserSRT.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>

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

@ -4,6 +4,7 @@
<title>Popcorn 1.0 SSA parser Plug-in Demo</title>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="popcorn.parserSSA.js"></script>

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

@ -10,6 +10,7 @@
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="popcorn.parserSSA.js"></script>

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

@ -4,6 +4,7 @@
<title>Popcorn 1.0 TTML parser Plug-in Demo</title>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="popcorn.parserTTML.js"></script>

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

@ -10,6 +10,7 @@
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="popcorn.parserTTML.js"></script>

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

@ -4,6 +4,7 @@
<title>Popcorn 1.0 TTXT parser Plug-in Demo</title>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="popcorn.parserTTXT.js"></script>

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

@ -10,6 +10,7 @@
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="popcorn.parserTTXT.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>

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

@ -4,6 +4,7 @@
<title>Popcorn 1.0 WebSRT/VTT parser Plug-in Demo</title>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>
<script src="popcorn.parserVTT.js"></script>

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

@ -10,6 +10,7 @@ popcorn-api-draft.js
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="popcorn.parserVTT.js"></script>
<script src="../../plugins/subtitle/popcorn.subtitle.js"></script>

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

@ -4,6 +4,7 @@
<title>Popcorn 1.0 parser Plug-in Demo</title>
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="../../modules/timeline-sources/popcorn.timeline-sources.js"></script>
<script src="../../plugins/flickr/popcorn.flickr.js"></script>
<script src="popcorn.parserXML.js"></script>

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

@ -10,6 +10,7 @@
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/parser/popcorn.parser.js"></script>
<script src="popcorn.parserXML.js"></script>
<script src="popcorn.parserXML.unit.js"></script>

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

@ -9,6 +9,7 @@
</style>
<script src="../../popcorn.js"></script>
<script src="../../modules/player/popcorn.player.js"></script>
<script type="text/javascript" src="popcorn.soundcloud.js"></script>
<!-- Plugins for demo purposes -->

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

@ -10,6 +10,7 @@
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/player/popcorn.player.js"></script>
<script src="popcorn.soundcloud.unit.js"></script>
<script src="popcorn.soundcloud.js"></script>

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

@ -22,6 +22,7 @@
</style>
<script src="../../popcorn.js"></script>
<script src="../../modules/player/popcorn.player.js"></script>
<script type="text/javascript" src="popcorn.vimeo.js"></script>
<script src="../../plugins/footnote/popcorn.footnote.js"></script>
<script src="../../plugins/flickr/popcorn.flickr.js"></script>

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

@ -11,6 +11,7 @@
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/player/popcorn.player.js"></script>
<script src="popcorn.vimeo.unit.js"></script>
<script src="popcorn.vimeo.js"></script>

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

@ -3,6 +3,7 @@
<head>
<title>Popcorn Youtube Player Example</title>
<script src="../../popcorn.js"></script>
<script src="../../modules/player/popcorn.player.js"></script>
<script type="text/javascript" src="popcorn.youtube.js"></script>
<script src="../../plugins/footnote/popcorn.footnote.js"></script>
<script src="../../plugins/flickr/popcorn.flickr.js"></script>

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

@ -8,6 +8,7 @@
do not move - this must be called immediately prior to popcorn.js.
-->
<script src="../../popcorn.js"></script>
<script src="../../modules/player/popcorn.player.js"></script>
<script src="popcorn.youtube.js"></script>
<script src="popcorn.youtube.unit.js"></script>
<script src="../../test/inject.js"></script>

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

@ -17,7 +17,7 @@ test( "Popcorn Subtitle Plugin", function() {
}
}
stop( 12000 );
stop( 15000 );
ok( "subtitle" in popped, "subtitle is a method of the popped instance" );
plus();

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

@ -1,11 +0,0 @@
#big {
font-size:24px;
line-height: 130%;
}
#mid {
font-size: 16px;
}

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

@ -9,7 +9,7 @@
var methods = ( "removeInstance addInstance getInstanceById removeInstanceById " +
"forEach extend effects error guid sizeOf isArray nop position disable enable destroy" +
"addTrackEvent removeTrackEvent getTrackEvents getTrackEvent getLastTrackEventId " +
"timeUpdate plugin removePlugin compose effect parser xhr getJSONP getScript player" ).split(/\s+/);
"timeUpdate plugin removePlugin compose effect xhr getJSONP getScript" ).split(/\s+/);
while ( methods.length ) {
global.Popcorn[ methods.shift() ] = function() {};
@ -929,55 +929,83 @@
return obj;
};
Popcorn.removeTrackEvent = function( obj, trackId ) {
Popcorn.removeTrackEvent = function( obj, removeId ) {
var historyLen = obj.data.history.length,
var start, end, animate,
historyLen = obj.data.history.length,
length = obj.data.trackEvents.byStart.length,
index = 0,
indexWasAt = 0,
byStart = [],
byEnd = [],
animating = [],
history = [];
Popcorn.forEach( obj.data.trackEvents.byStart, function( o, i, context ) {
// Preserve the original start/end trackEvents
if ( !o._id ) {
byStart.push( obj.data.trackEvents.byStart[i] );
byEnd.push( obj.data.trackEvents.byEnd[i] );
while ( --length > -1 ) {
start = obj.data.trackEvents.byStart[ index ];
end = obj.data.trackEvents.byEnd[ index ];
// Padding events will not have _id properties.
// These should be safely pushed onto the front and back of the
// track event array
if ( !start._id ) {
byStart.push( start );
byEnd.push( end );
}
// Filter for user track events (vs system track events)
if ( o._id ) {
if ( start._id ) {
// Filter for the trackevent to remove
if ( o._id !== trackId ) {
byStart.push( obj.data.trackEvents.byStart[i] );
byEnd.push( obj.data.trackEvents.byEnd[i] );
// If not a matching start event for removal
if ( start._id !== removeId ) {
byStart.push( start );
}
// Capture the position of the track being removed.
if ( o._id === trackId ) {
indexWasAt = i;
o._natives._teardown && o._natives._teardown.call( obj, o );
}
}
});
if ( obj.data.trackEvents.animating.length ) {
Popcorn.forEach( obj.data.trackEvents.animating, function( o, i, context ) {
// Preserve the original start/end trackEvents
if ( !o._id ) {
animating.push( obj.data.trackEvents.animating[i] );
// If not a matching end event for removal
if ( end._id !== removeId ) {
byEnd.push( end );
}
// Filter for user track events (vs system track events)
if ( o._id ) {
// Filter for the trackevent to remove
if ( o._id !== trackId ) {
animating.push( obj.data.trackEvents.animating[i] );
// If the _id is matched, capture the current index
if ( start._id === removeId ) {
indexWasAt = index;
// If a _teardown function was defined,
// enforce for track event removals
if ( start._natives._teardown ) {
start._natives._teardown.call( obj, start );
}
}
});
}
// Increment the track index
index++;
}
// Reset length to be used by the condition below to determine
// if animating track events should also be filtered for removal.
// Reset index below to be used by the reverse while as an
// incrementing counter
length = obj.data.trackEvents.animating.length;
index = 0;
if ( length ) {
while ( --length > -1 ) {
animate = obj.data.trackEvents.animating[ index ];
// Padding events will not have _id properties.
// These should be safely pushed onto the front and back of the
// track event array
if ( !animate._id ) {
animating.push( animate );
}
// If not a matching animate event for removal
if ( animate._id && animate._id !== removeId ) {
animating.push( animate );
}
// Increment the track index
index++;
}
}
// Update
@ -994,7 +1022,7 @@
obj.data.trackEvents.animating = animating;
for ( var i = 0; i < historyLen; i++ ) {
if ( obj.data.history[ i ] !== trackId ) {
if ( obj.data.history[ i ] !== removeId ) {
history.push( obj.data.history[ i ] );
}
}
@ -1003,12 +1031,12 @@
obj.data.history = history;
// Update track event references
Popcorn.removeTrackEvent.ref( obj, trackId );
Popcorn.removeTrackEvent.ref( obj, removeId );
};
// Internal Only - Removes track event references from instance object's trackRefs hash table
Popcorn.removeTrackEvent.ref = function( obj, trackId ) {
delete obj.data.trackRefs[ trackId ];
Popcorn.removeTrackEvent.ref = function( obj, removeId ) {
delete obj.data.trackRefs[ removeId ];
return obj;
};
@ -1594,335 +1622,6 @@
Popcorn.plugin.effect = Popcorn.effect = Popcorn.compose;
// stores parsers keyed on filetype
Popcorn.parsers = {};
// An interface for extending Popcorn
// with parser functionality
Popcorn.parser = function( name, type, definition ) {
if ( Popcorn.protect.natives.indexOf( name.toLowerCase() ) >= 0 ) {
Popcorn.error( "'" + name + "' is a protected function name" );
return;
}
// fixes parameters for overloaded function call
if ( typeof type === "function" && !definition ) {
definition = type;
type = "";
}
if ( typeof definition !== "function" || typeof type !== "string" ) {
return;
}
// Provides some sugar, but ultimately extends
// the definition into Popcorn.p
var natives = Popcorn.events.all,
parseFn,
parser = {};
parseFn = function( filename, callback ) {
if ( !filename ) {
return this;
}
var that = this;
Popcorn.xhr({
url: filename,
dataType: type,
success: function( data ) {
var tracksObject = definition( data ),
tracksData,
tracksDataLen,
tracksDef,
idx = 0;
tracksData = tracksObject.data || [];
tracksDataLen = tracksData.length;
tracksDef = null;
// If no tracks to process, return immediately
if ( !tracksDataLen ) {
return;
}
// Create tracks out of parsed object
for ( ; idx < tracksDataLen; idx++ ) {
tracksDef = tracksData[ idx ];
for ( var key in tracksDef ) {
if ( hasOwn.call( tracksDef, key ) && !!that[ key ] ) {
that[ key ]( tracksDef[ key ] );
}
}
}
if ( callback ) {
callback();
}
}
});
return this;
};
// Assign new named definition
parser[ name ] = parseFn;
// Extend Popcorn.p with new named definition
Popcorn.extend( Popcorn.p, parser );
// keys the function name by filetype extension
//Popcorn.parsers[ name ] = true;
return parser;
};
Popcorn.player = function( name, player ) {
player = player || {};
var playerFn = function( target, src, options ) {
options = options || {};
// List of events
var date = new Date() / 1000,
baselineTime = date,
currentTime = 0,
volume = 1,
muted = false,
events = {},
// The container div of the resource
container = document.getElementById( rIdExp.exec( target ) && rIdExp.exec( target )[ 2 ] ) ||
document.getElementById( target ) ||
target,
basePlayer = {},
timeout,
popcorn;
// copies a div into the media object
for( var val in container ) {
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.forEach( [ "offsetWidth", "offsetHeight" ], function( prop ) {
Popcorn.player.defineProperty( basePlayer, prop, {
get: function() {
return +container[ prop ];
}
});
});
// Adds an event listener to the object
basePlayer.addEventListener = function( evtName, fn ) {
if ( !events[ evtName ] ) {
events[ evtName ] = [];
}
events[ evtName ].push( fn );
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 );
}
}
Popcorn.forEach( events[ eventName ], function( val ) {
val.call( self, evt, self );
});
};
// Attempt to get src from playerFn parameter
basePlayer.src = src || "";
basePlayer.readyState = 0;
basePlayer.duration = 0;
basePlayer.paused = true;
basePlayer.ended = 0;
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( "load" );
basePlayer.dispatchEvent( "loadeddata" );
}
// when a custom player is loaded, load basePlayer state into custom player
basePlayer.addEventListener( "load", function() {
// if a player is not ready before currentTime is called, this will set it after it is ready
basePlayer.currentTime = currentTime;
// same as above with volume and muted
basePlayer.volume = volume;
basePlayer.muted = muted;
});
basePlayer.addEventListener( "loadeddata", function() {
// if play was called before player ready, start playing video
!basePlayer.paused && basePlayer.play();
});
popcorn = new Popcorn.p.init( basePlayer, options );
return popcorn;
};
Popcorn[ name ] = Popcorn[ name ] || playerFn;
};
Popcorn.player.defineProperty = Object.defineProperty || function( object, description, options ) {
object.__defineGetter__( description, options.get || Popcorn.nop );
object.__defineSetter__( description, options.set || Popcorn.nop );
};
// Cache references to reused RegExps
var rparams = /\?/,
// XHR Setup object

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

@ -1,7 +1,7 @@
var methodsString = "removeInstance addInstance getInstanceById removeInstanceById " +
"forEach extend effects error guid sizeOf isArray nop position disable enable destroy" +
"addTrackEvent removeTrackEvent getTrackEvents getTrackEvent getLastTrackEventId " +
"timeUpdate plugin removePlugin compose effect parser xhr getJSONP getScript player";
"timeUpdate plugin removePlugin compose effect xhr getJSONP getScript";
module("Core");
test("Dummy", function () {

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

@ -183,6 +183,132 @@ test( "Popcorn.getTrackEvent", function() {
});
test( "Popcorn.removeTrackEvent", function() {
var pop = Popcorn( "#video" ),
count = 0,
aId, bId, cId, dId, byStart, byEnd;
expect( 5 );
Popcorn.plugin( "a", {
_setup: function( options ) {},
start: function( event, options ) {},
end: function( event, options ) {},
_teardown: function( options ) {}
});
Popcorn.plugin( "b", {
_setup: function( options ) {},
start: function( event, options ) {},
end: function( event, options ) {},
_teardown: function( options ) {}
});
Popcorn.plugin( "c", {
_setup: function( options ) {},
start: function( event, options ) {},
end: function( event, options ) {},
_teardown: function( options ) {}
});
Popcorn.plugin( "d", {
_setup: function( options ) {},
start: function( event, options ) {},
end: function( event, options ) {},
_teardown: function( options ) {}
});
pop.a({
start: 1,
end: 5
});
// Store track event id for "plugin a"
aId = pop.getLastTrackEventId();
pop.b({
start: 3,
end: 4
});
// Store track event id for "plugin b"
bId = pop.getLastTrackEventId();
pop.c({
start: 0,
end: 3
});
// Store track event id for "plugin c"
cId = pop.getLastTrackEventId();
pop.d({
start: 1,
end: 2
});
// Store track event id for "plugin d"
dId = pop.getLastTrackEventId();
// Capture the pre-removal track event count
count = pop.data.trackEvents.byStart.length;
// Remove the first track event for "plugin a"
pop.removeTrackEvent( aId );
// Shorthand references
byStart = pop.data.trackEvents.byStart;
byEnd = pop.data.trackEvents.byEnd;
equal( byStart.length, count - 1, "One less track event" );
// Iterate all byStart track events to prove that _only_ track events
// created by "plugin b" have survived
Popcorn.forEach( byStart, function( start ) {
if ( start._id ) {
// This condition should NEVER evaluate to true
if ( start._id === aId ) {
ok( false, "No byStart track events with " + aId + " should exist" );
}
// This condition should ALWAYS evaluate to true
if ( start._id === bId ) {
ok( true, "Only byStart track events with " + bId + " should exist" );
}
}
});
// Iterate all byEnd track events to prove that _only_ track events
// created by "plugin b" have survived
Popcorn.forEach( byEnd, function( end ) {
if ( end._id ) {
// This condition should NEVER evaluate to true
if ( end._id === aId ) {
ok( false, "No byEnd track events with " + aId + " should exist" );
}
// This condition should ALWAYS evaluate to true
if ( end._id === bId ) {
ok( true, "Only byEnd track events with " + bId + " should exist" );
}
}
});
// after the removal, byStart's first element is c
// console.log( byStart );
// after the removal, byEnd's first element should be d (if c, then broken)
// console.log( byEnd );
// Test to ensure order was preserved
equal( byStart[1]._id, cId, "byStart[1]._id matches cId" );
equal( byEnd[1]._id, dId, "byEnd[1]._id matches dId" );
Popcorn.forEach([ "a", "b", "c", "d" ], function( name ) {
Popcorn.removePlugin( name );
});
});
test( "Popcorn.forEach", function() {
expect( 3 );
@ -3803,7 +3929,6 @@ test( "XML Response", function() {
});
});
test( "dataType: XML Response", function() {
var expects = 2,
@ -3835,317 +3960,6 @@ test( "dataType: XML Response", function() {
});
});
module( "Popcorn Player" );
test( "Base player methods", function() {
var expects = 2;
expect( expects );
stop( 10000 );
ok( Popcorn.player, "Popcorn.player function exists" );
Popcorn.player( "newplayer" );
ok( Popcorn.newplayer, "Popcorn.player registers new players" );
start();
});
test( "Base player functionality", function() {
Popcorn.player( "baseplayer" );
//QUnit.reset();
var p2 = Popcorn.baseplayer( "#video" ),
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" );
start();
}
}
// These tests come close to 10 seconds on chrome, increasing to 15
stop( 15000 );
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;
p2.currentTime( 0 ).play();
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( 5 ).play();
}
}
};
});
p2.backwards({
start: 1,
end: 2
});
Popcorn.plugin( "wrapper", {
start: function( event, options ) {
wrapperRunning[ options.wrapper ] = true;
},
end: function( event, options ) {
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();
}
});
p2.currentTime( 3 ).play();
});
module( "Popcorn Parser" );
test( "Parsing Functions", function() {
var expects = 3,
count = 0,
popperly = Popcorn( "#video" );
function plus() {
if ( ++count === expects ) {
start();
}
}
expect( expects );
stop( 10000 );
ok( typeof Popcorn.parser === "function", "Popcorn.parser is a function" );
plus();
Popcorn.parser( "parseJSON" , "json", function( data ){
return data;
});
ok( typeof popperly.parseJSON === "function", "Popcorn.parser created a parseJSON function" );
plus();
ok( typeof popperly.parseJSON().parseJSON( "data/test.js" ).parseJSON === "function" , "parseJSON function is chainable" );
plus();
});
test( "Parsing Integrity", function() {
var expects = 6,
count = 0,
timeOut = 0,
poppercore = Popcorn( "#video" );
function plus() {
if ( ++count === expects ) {
start();
// clean up added events after tests
Popcorn.removePlugin( "parserTest" );
}
}
expect( expects );
stop( 10000 );
Popcorn.parser( "parseJSON2", function( data ){
ok( typeof data.json === "object", "data.json exists" );
plus();
return data.json;
});
Popcorn.parser( "parseJSON3" , "json", function( data ){
ok( typeof data === "object", "data exists" );
plus();
return data;
});
Popcorn.plugin( "parserTest", {
start: function() {
ok( true, "parserTest started" );
plus();
},
end: function() {
ok( true, "parserTest ended" );
plus();
}
});
poppercore.parseJSON2( "data/parserData.json", function() {
poppercore.parseJSON3( "data/parserData.json", function() {
poppercore.currentTime( 5 ).play();
});
});
});
test( "Parsing Handler - References unavailable plugin", function() {
var expects = 1,
count = 0,
timeOut = 0,
interval,
poppercore = Popcorn( "#video" );
function plus() {
if ( ++count === expects ) {
start();
// clean up added events after tests
clearInterval( interval );
poppercore.removePlugin( "parserTest" );
}
}
expect( expects );
stop();
Popcorn.parser( "parseJson", function( data ){
return data.json;
});
poppercore.parseJson( "data/parseMissing.json" );
// interval used to wait for data to be parsed
interval = setInterval( function() {
poppercore.currentTime( 5 ).play().currentTime( 6 );
ok( true, "Ignored call to missing plugin " );
plus();
}, 2000 );
});
module( "Audio" );
test( "Basic Audio Support (timeupdate)", function() {
@ -4290,49 +4104,6 @@ test( "Basic Audio Support (frameAnimation)", function() {
});
});
test( "Parser Support", function() {
var expects = 3,
count = 0,
timeOut = 0,
interval,
audiocorn = Popcorn( "#audio" );
function plus() {
if ( ++count === expects ) {
start();
Popcorn.removePlugin( "testAudioParser" );
}
}
expect( expects );
stop( 5000 );
Popcorn.plugin( "testAudioParser", {
start: function() {
ok( true, "testAudioParser started: " + Math.round( this.currentTime() ) );
plus();
},
end: function() {
ok( true, "testAudioParser ended: " + Math.round( this.currentTime() ) );
plus();
}
});
Popcorn.parser( "parseAudio", function( data ){
ok( typeof data.json === "object", "data.json exists");
plus();
return data.json;
});
audiocorn.parseAudio( "data/parserAudio.json", function() {
audiocorn.currentTime( 4 ).play();
});
});
module( "Popcorn Test Runner End" );
test( "Last Check", function() {
// Trigger follow-up tests to run in iframes