8 |
8 |
9 var methods = ( "forEach extend effects error guid sizeOf isArray nop position disable enable destroy " + |
9 var methods = ( "forEach extend effects error guid sizeOf isArray nop position disable enable destroy " + |
10 "addTrackEvent removeTrackEvent getTrackEvents getTrackEvent getLastTrackEventId " + |
10 "addTrackEvent removeTrackEvent getTrackEvents getTrackEvent getLastTrackEventId " + |
11 "timeUpdate plugin removePlugin compose effect parser xhr getJSONP getScript" ).split(/\s+/); |
11 "timeUpdate plugin removePlugin compose effect parser xhr getJSONP getScript" ).split(/\s+/); |
12 |
12 |
13 while( methods.length ) { |
13 while ( methods.length ) { |
14 global.Popcorn[ methods.shift() ] = function() {}; |
14 global.Popcorn[ methods.shift() ] = function() {}; |
15 } |
15 } |
16 return; |
16 return; |
17 } |
17 } |
18 |
18 |
56 function( callback, element ) { |
56 function( callback, element ) { |
57 global.setTimeout( callback, 16 ); |
57 global.setTimeout( callback, 16 ); |
58 }; |
58 }; |
59 }()), |
59 }()), |
60 |
60 |
|
61 refresh = function( obj ) { |
|
62 var currentTime = obj.media.currentTime, |
|
63 animation = obj.options.frameAnimation, |
|
64 disabled = obj.data.disabled, |
|
65 tracks = obj.data.trackEvents, |
|
66 animating = tracks.animating, |
|
67 start = tracks.startIndex, |
|
68 registryByName = Popcorn.registryByName, |
|
69 animIndex = 0, |
|
70 byStart, natives, type; |
|
71 |
|
72 start = Math.min( start + 1, tracks.byStart.length - 2 ); |
|
73 |
|
74 while ( start > 0 && tracks.byStart[ start ] ) { |
|
75 |
|
76 byStart = tracks.byStart[ start ]; |
|
77 natives = byStart._natives; |
|
78 type = natives && natives.type; |
|
79 |
|
80 if ( !natives || |
|
81 ( !!registryByName[ type ] || !!obj[ type ] ) ) { |
|
82 |
|
83 if ( ( byStart.start <= currentTime && byStart.end > currentTime ) && |
|
84 disabled.indexOf( type ) === -1 ) { |
|
85 |
|
86 if ( !byStart._running ) { |
|
87 byStart._running = true; |
|
88 natives.start.call( obj, null, byStart ); |
|
89 |
|
90 // if the 'frameAnimation' option is used, |
|
91 // push the current byStart object into the `animating` cue |
|
92 if ( animation && |
|
93 ( byStart && byStart._running && byStart.natives.frame ) ) { |
|
94 |
|
95 natives.frame.call( obj, null, byStart, currentTime ); |
|
96 } |
|
97 } |
|
98 } else if ( byStart._running === true ) { |
|
99 |
|
100 byStart._running = false; |
|
101 natives.end.call( obj, null, byStart ); |
|
102 |
|
103 if ( animation && byStart._natives.frame ) { |
|
104 animIndex = animating.indexOf( byStart ); |
|
105 if ( animIndex >= 0 ) { |
|
106 animating.splice( animIndex, 1 ); |
|
107 } |
|
108 } |
|
109 } |
|
110 } |
|
111 |
|
112 start--; |
|
113 } |
|
114 }, |
|
115 |
61 // Declare constructor |
116 // Declare constructor |
62 // Returns an instance object. |
117 // Returns an instance object. |
63 Popcorn = function( entity, options ) { |
118 Popcorn = function( entity, options ) { |
64 // Return new Popcorn object |
119 // Return new Popcorn object |
65 return new Popcorn.p.init( entity, options || null ); |
120 return new Popcorn.p.init( entity, options || null ); |
186 }; |
244 }; |
187 |
245 |
188 // Wrap true ready check |
246 // Wrap true ready check |
189 var isReady = function( that ) { |
247 var isReady = function( that ) { |
190 |
248 |
191 var duration, videoDurationPlus, animate; |
249 var duration, videoDurationPlus; |
192 |
250 |
193 if ( that.media.readyState >= 2 ) { |
251 if ( that.media.readyState >= 2 ) { |
194 // Adding padding to the front and end of the arrays |
252 // Adding padding to the front and end of the arrays |
195 // this is so we do not fall off either end |
253 // this is so we do not fall off either end |
196 |
254 |
206 if ( that.options.frameAnimation ) { |
264 if ( that.options.frameAnimation ) { |
207 // if Popcorn is created with frameAnimation option set to true, |
265 // if Popcorn is created with frameAnimation option set to true, |
208 // requestAnimFrame is used instead of "timeupdate" media event. |
266 // requestAnimFrame is used instead of "timeupdate" media event. |
209 // This is for greater frame time accuracy, theoretically up to |
267 // This is for greater frame time accuracy, theoretically up to |
210 // 60 frames per second as opposed to ~4 ( ~every 15-250ms) |
268 // 60 frames per second as opposed to ~4 ( ~every 15-250ms) |
211 animate = function () { |
269 that.data.timeUpdate = function () { |
212 |
270 |
213 Popcorn.timeUpdate( that, {} ); |
271 Popcorn.timeUpdate( that, {} ); |
214 |
272 |
215 that.trigger( "timeupdate" ); |
273 that.trigger( "timeupdate" ); |
216 |
274 |
217 requestAnimFrame( animate ); |
275 !that.isDestroyed && requestAnimFrame( that.data.timeUpdate ); |
218 }; |
276 }; |
219 |
277 |
220 requestAnimFrame( animate ); |
278 !that.isDestroyed && requestAnimFrame( that.data.timeUpdate ); |
221 |
279 |
222 } else { |
280 } else { |
223 |
281 |
224 that.data.timeUpdateFunction = function( event ) { |
282 that.data.timeUpdate = function( event ) { |
225 Popcorn.timeUpdate( that, event ); |
283 Popcorn.timeUpdate( that, event ); |
226 }; |
284 }; |
227 |
285 |
228 if ( !that.isDestroyed ) { |
286 if ( !that.isDestroyed ) { |
229 that.media.addEventListener( "timeupdate", that.data.timeUpdateFunction, false ); |
287 that.media.addEventListener( "timeupdate", that.data.timeUpdate, false ); |
230 } |
288 } |
231 } |
289 } |
232 } else { |
290 } else { |
233 global.setTimeout(function() { |
291 global.setTimeout(function() { |
234 isReady( that ); |
292 isReady( that ); |
355 |
413 |
356 if ( disabled.indexOf( plugin ) === -1 ) { |
414 if ( disabled.indexOf( plugin ) === -1 ) { |
357 disabled.push( plugin ); |
415 disabled.push( plugin ); |
358 } |
416 } |
359 |
417 |
|
418 refresh( instance ); |
|
419 |
360 return instance; |
420 return instance; |
361 }, |
421 }, |
362 enable: function( instance, plugin ) { |
422 enable: function( instance, plugin ) { |
363 |
423 |
364 var disabled = instance.data.disabled, |
424 var disabled = instance.data.disabled, |
365 index = disabled.indexOf( plugin ); |
425 index = disabled.indexOf( plugin ); |
366 |
426 |
367 if ( index > -1 ) { |
427 if ( index > -1 ) { |
368 disabled.splice( index, 1 ); |
428 disabled.splice( index, 1 ); |
369 } |
429 } |
|
430 |
|
431 refresh( instance ); |
370 |
432 |
371 return instance; |
433 return instance; |
372 }, |
434 }, |
373 destroy: function( instance ) { |
435 destroy: function( instance ) { |
374 var events = instance.data.events, |
436 var events = instance.data.events, |
778 track.end = Popcorn.util.toSeconds( track.end, obj.options.framerate ); |
840 track.end = Popcorn.util.toSeconds( track.end, obj.options.framerate ); |
779 |
841 |
780 // Store this definition in an array sorted by times |
842 // Store this definition in an array sorted by times |
781 var byStart = obj.data.trackEvents.byStart, |
843 var byStart = obj.data.trackEvents.byStart, |
782 byEnd = obj.data.trackEvents.byEnd, |
844 byEnd = obj.data.trackEvents.byEnd, |
783 idx; |
845 startIndex, endIndex, |
784 |
846 currentTime; |
785 for ( idx = byStart.length - 1; idx >= 0; idx-- ) { |
847 |
786 |
848 for ( startIndex = byStart.length - 1; startIndex >= 0; startIndex-- ) { |
787 if ( track.start >= byStart[ idx ].start ) { |
849 |
788 byStart.splice( idx + 1, 0, track ); |
850 if ( track.start >= byStart[ startIndex ].start ) { |
|
851 byStart.splice( startIndex + 1, 0, track ); |
789 break; |
852 break; |
790 } |
853 } |
791 } |
854 } |
792 |
855 |
793 for ( idx = byEnd.length - 1; idx >= 0; idx-- ) { |
856 for ( endIndex = byEnd.length - 1; endIndex >= 0; endIndex-- ) { |
794 |
857 |
795 if ( track.end > byEnd[ idx ].end ) { |
858 if ( track.end > byEnd[ endIndex ].end ) { |
796 byEnd.splice( idx + 1, 0, track ); |
859 byEnd.splice( endIndex + 1, 0, track ); |
797 break; |
860 break; |
798 } |
861 } |
799 } |
862 } |
800 |
863 |
801 this.timeUpdate( obj, null ); |
864 // Display track event immediately if it's enabled and current |
|
865 if ( track._natives && |
|
866 ( !!Popcorn.registryByName[ track._natives.type ] || !!obj[ track._natives.type ] ) ) { |
|
867 |
|
868 currentTime = obj.media.currentTime; |
|
869 if ( track.end > currentTime && |
|
870 track.start <= currentTime && |
|
871 obj.data.disabled.indexOf( track._natives.type ) === -1 ) { |
|
872 |
|
873 track._running = true; |
|
874 track._natives.start.call( obj, null, track ); |
|
875 |
|
876 if ( obj.options.frameAnimation && |
|
877 track._natives.frame ) { |
|
878 |
|
879 obj.data.trackEvents.animating.push( track ); |
|
880 track._natives.frame.call( obj, null, track, currentTime ); |
|
881 } |
|
882 } |
|
883 } |
|
884 |
|
885 // update startIndex and endIndex |
|
886 if ( startIndex <= obj.data.trackEvents.startIndex && |
|
887 track.start <= obj.data.trackEvents.previousUpdateTime ) { |
|
888 |
|
889 obj.data.trackEvents.startIndex++; |
|
890 } |
|
891 |
|
892 if ( endIndex <= obj.data.trackEvents.endIndex && |
|
893 track.end < obj.data.trackEvents.previousUpdateTime ) { |
|
894 |
|
895 obj.data.trackEvents.endIndex++; |
|
896 } |
|
897 |
|
898 this.timeUpdate( obj, null, true ); |
802 |
899 |
803 // Store references to user added trackevents in ref table |
900 // Store references to user added trackevents in ref table |
804 if ( track._id ) { |
901 if ( track._id ) { |
805 Popcorn.addTrackEvent.ref( obj, track ); |
902 Popcorn.addTrackEvent.ref( obj, track ); |
806 } |
903 } |
1206 options._natives.type = name; |
1303 options._natives.type = name; |
1207 options._running = false; |
1304 options._running = false; |
1208 |
1305 |
1209 natives.start = natives.start || natives[ "in" ]; |
1306 natives.start = natives.start || natives[ "in" ]; |
1210 natives.end = natives.end || natives[ "out" ]; |
1307 natives.end = natives.end || natives[ "out" ]; |
|
1308 |
|
1309 // extend teardown to always call end if running |
|
1310 natives._teardown = combineFn(function() { |
|
1311 |
|
1312 var args = slice.call( arguments ); |
|
1313 |
|
1314 // end function signature is not the same as teardown, |
|
1315 // put null on the front of arguments for the event parameter |
|
1316 args.unshift( null ); |
|
1317 |
|
1318 // only call end if event is running |
|
1319 args[ 1 ]._running && natives.end.apply( this, args ); |
|
1320 }, natives._teardown ); |
1211 |
1321 |
1212 // Check for previously set default options |
1322 // Check for previously set default options |
1213 defaults = this.options.defaults && this.options.defaults[ options._natives && options._natives.type ]; |
1323 defaults = this.options.defaults && this.options.defaults[ options._natives && options._natives.type ]; |
1214 |
1324 |
1215 // default to an empty string if no effect exists |
1325 // default to an empty string if no effect exists |
1362 // remove plugin reference from registry |
1472 // remove plugin reference from registry |
1363 for ( registryIdx = 0; registryIdx < registryLen; registryIdx++ ) { |
1473 for ( registryIdx = 0; registryIdx < registryLen; registryIdx++ ) { |
1364 if ( Popcorn.registry[ registryIdx ].name === name ) { |
1474 if ( Popcorn.registry[ registryIdx ].name === name ) { |
1365 Popcorn.registry.splice( registryIdx, 1 ); |
1475 Popcorn.registry.splice( registryIdx, 1 ); |
1366 delete Popcorn.registryByName[ name ]; |
1476 delete Popcorn.registryByName[ name ]; |
|
1477 delete Popcorn.manifest[ name ]; |
1367 |
1478 |
1368 // delete the plugin |
1479 // delete the plugin |
1369 delete obj[ name ]; |
1480 delete obj[ name ]; |
1370 |
1481 |
1371 // plugin found and removed, stop checking, we are done |
1482 // plugin found and removed, stop checking, we are done |
1552 basePlayer[ val ] = container[ val ]; |
1663 basePlayer[ val ] = container[ val ]; |
1553 } else if ( typeof container[ val ] === "function" ) { |
1664 } else if ( typeof container[ val ] === "function" ) { |
1554 |
1665 |
1555 basePlayer[ val ] = (function( value ) { |
1666 basePlayer[ val ] = (function( value ) { |
1556 |
1667 |
1557 return function() { |
1668 // this is a stupid ugly kludgy hack in honour of Safari |
1558 |
1669 // in Safari a NodeList is a function, not an object |
1559 return container[ value ].apply( container, arguments ); |
1670 if ( "length" in container[ value ] && !container[ value ].call ) { |
1560 }; |
1671 |
|
1672 return container[ value ]; |
|
1673 } else { |
|
1674 |
|
1675 return function() { |
|
1676 |
|
1677 return container[ value ].apply( container, arguments ); |
|
1678 }; |
|
1679 } |
1561 }( val )); |
1680 }( val )); |
1562 } else { |
1681 } else { |
1563 |
1682 |
1564 Popcorn.player.defineProperty( basePlayer, val, { |
1683 Popcorn.player.defineProperty( basePlayer, val, { |
1565 get: (function( value ) { |
1684 get: (function( value ) { |
1812 data = { |
1932 data = { |
1813 xml: settings.ajax.responseXML, |
1933 xml: settings.ajax.responseXML, |
1814 text: settings.ajax.responseText, |
1934 text: settings.ajax.responseText, |
1815 json: json |
1935 json: json |
1816 }; |
1936 }; |
|
1937 |
|
1938 // Normalize: data.xml is non-null in IE9 regardless of if response is valid xml |
|
1939 if ( !data.xml || !data.xml.documentElement ) { |
|
1940 data.xml = null; |
|
1941 |
|
1942 try { |
|
1943 parser = new DOMParser(); |
|
1944 xml = parser.parseFromString( settings.ajax.responseText, "text/xml" ); |
|
1945 |
|
1946 if ( !xml.getElementsByTagName( "parsererror" ).length ) { |
|
1947 data.xml = xml; |
|
1948 } |
|
1949 } catch ( e ) { |
|
1950 // data.xml remains null |
|
1951 } |
|
1952 } |
1817 |
1953 |
1818 // If a dataType was specified, return that type of data |
1954 // If a dataType was specified, return that type of data |
1819 if ( settings.dataType ) { |
1955 if ( settings.dataType ) { |
1820 data = data[ settings.dataType ]; |
1956 data = data[ settings.dataType ]; |
1821 } |
1957 } |