Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Updated player API to be avialable immediately.

Moved auto setup code to setup.js.
  • Loading branch information...
commit a839c89f0bfd8d4a088c6a2701ea51c3386f292c 1 parent 56355e5
@heff heff authored
Showing with 201 additions and 137 deletions.
  1. +3 −0  src/component.js
  2. +1 −51 src/core.js
  3. +147 −86 src/player.js
  4. +50 −0 src/setup.js
View
3  src/component.js
@@ -184,6 +184,9 @@ _V_.Component = _V_.Class.extend({
// Reset Ready Queue
this.readyQueue = [];
+
+ // Allow for using event listeners also, in case you want to do something everytime a source is ready.
+ this.triggerEvent("ready");
}
},
View
52 src/core.js
@@ -113,54 +113,4 @@ VideoJS.options = {
// Set CDN Version of swf
if (CDN_VERSION != "GENERATED_CDN_VSN") {
_V_.options.flash.swf = "http://vjs.zencdn.net/"+CDN_VERSION+"/video-js.swf"
-}
-
-// Automatically set up any tags that have a data-setup attribute
-_V_.autoSetup = function(){
- var options, vid, player,
- vids = document.getElementsByTagName("video");
-
- // Check if any media elements exist
- if (vids && vids.length > 0) {
-
- for (var i=0,j=vids.length; i<j; i++) {
- vid = vids[i];
-
- // Check if element exists, has getAttribute func.
- // IE seems to consider typeof el.getAttribute == "object" instead of "function" like expected, at least when loading the player immediately.
- if (vid && vid.getAttribute) {
-
- // Make sure this player hasn't already been set up.
- if (vid.player === undefined) {
- options = vid.getAttribute("data-setup");
-
- // Check if data-setup attr exists.
- // We only auto-setup if they've added the data-setup attr.
- if (options !== null) {
-
- // Parse options JSON
- // If empty string, make it a parsable json object.
- options = JSON.parse(options || "{}");
-
- // Create new video.js instance.
- player = _V_(vid, options);
- }
- }
-
- // If getAttribute isn't defined, we need to wait for the DOM.
- } else {
- _V_.autoSetupTimeout(1);
- break;
- }
- }
-
- // No videos were found, so keep looping unless page is finisehd loading.
- } else if (!_V_.windowLoaded) {
- _V_.autoSetupTimeout(1);
- }
-};
-
-// Pause to let the DOM keep processing
-_V_.autoSetupTimeout = function(wait){
- setTimeout(_V_.autoSetup, wait);
-};
+}
View
233 src/player.js
@@ -352,53 +352,79 @@ _V_.Player = _V_.Component.extend({
/* Player API
================================================================================ */
- apiCall: function(method, arg){
- if (this.isReady) {
+ // Method for calling methods on the current playback technology
+ techCall: function(method, arg){
+ try {
return this.tech[method](arg);
- } else {
- _V_.log("The playback technology API is not ready yet. Use player.ready(myFunction)."+" ["+method+"]", arguments.callee.caller.arguments.callee.caller.arguments.callee.caller)
- return false;
- // throw new Error("The playback technology API is not ready yet. Use player.ready(myFunction)."+" ["+method+"]");
+ } catch(e) {
+ _V_.log(e);
+ return;
}
+ // if (this.isReady) {
+ //
+ // } else {
+ // _V_.log("The playback technology API is not ready yet. Use player.ready(myFunction)."+" ["+method+"]", arguments.callee.caller.arguments.callee.caller.arguments.callee.caller)
+ // return false;
+ // // throw new Error("The playback technology API is not ready yet. Use player.ready(myFunction)."+" ["+method+"]");
+ // }
},
+ // http://dev.w3.org/html5/spec/video.html#dom-media-play
play: function(){
- this.apiCall("play"); return this;
+ this.techCall("play");
+ return this;
},
+
+ // http://dev.w3.org/html5/spec/video.html#dom-media-pause
pause: function(){
- this.apiCall("pause"); return this;
+ this.techCall("pause");
+ return this;
},
+
+ // http://dev.w3.org/html5/spec/video.html#dom-media-paused
+ // The initial state of paused should be true (in Safari it's actually false)
paused: function(){
- return this.apiCall("paused");
+ return (this.techCall("paused") === false) ? false : true;
},
+ // http://dev.w3.org/html5/spec/video.html#dom-media-currenttime
currentTime: function(seconds){
if (seconds !== undefined) {
// Cache the last set value for smoother scrubbing.
this.values.lastSetCurrentTime = seconds;
- this.apiCall("setCurrentTime", seconds);
+ this.techCall("setCurrentTime", seconds);
+
+ // Improve the accuracy of manual timeupdates
+ if (this.manualTimeUpdates) { this.triggerEvent("timeupdate"); }
- if (this.manualTimeUpdates) {
- this.triggerEvent("timeupdate");
- }
return this;
}
// Cache last currentTime and return
- return this.values.currentTime = this.apiCall("currentTime");
+ // Default to 0 seconds
+ return this.values.currentTime = (this.techCall("currentTime") || 0);
},
+
+ // http://dev.w3.org/html5/spec/video.html#dom-media-duration
+ // Duration should return NaN if not available. ParseFloat will turn false-ish values to NaN.
duration: function(){
- return this.apiCall("duration");
+ return parseFloat(this.techCall("duration"));
},
+
+ // Calculates how much time is left. Not in spec, but useful.
remainingTime: function(){
return this.duration() - this.currentTime();
},
+ // http://dev.w3.org/html5/spec/video.html#dom-media-buffered
+ // Buffered returns a timerange object. Kind of like an array of portions of the video that have been downloaded.
+ // So far no browsers return more than one range (portion)
buffered: function(){
- var buffered = this.apiCall("buffered"),
- start = 0, end = this.values.bufferEnd = this.values.bufferEnd || 0,
+ var buffered = this.techCall("buffered"),
+ start = 0,
+ end = this.values.bufferEnd = this.values.bufferEnd || 0, // Default end to 0 and store in values
timeRange;
if (buffered && buffered.length > 0 && buffered.end(0) !== end) {
@@ -410,34 +436,46 @@ _V_.Player = _V_.Component.extend({
return _V_.createTimeRange(start, end);
},
- // Calculates amount of buffer is full
+ // Calculates amount of buffer is full. Not in spec but useful.
bufferedPercent: function(){
return (this.duration()) ? this.buffered().end(0) / this.duration() : 0;
},
+ // http://dev.w3.org/html5/spec/video.html#dom-media-volume
volume: function(percentAsDecimal){
+ var vol;
+
if (percentAsDecimal !== undefined) {
- var vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1
+ vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1
this.values.volume = vol;
- this.apiCall("setVolume", vol);
+ this.techCall("setVolume", vol);
_V_.setLocalStorage("volume", vol);
return this;
}
- // if (this.values.volume) { return this.values.volume; }
- return this.apiCall("volume");
+
+ // Default to 1 when returning current volume.
+ vol = parseFloat(this.techCall("volume"));
+ return (isNaN(vol)) ? 1 : vol;
},
+
+ // http://dev.w3.org/html5/spec/video.html#attr-media-muted
muted: function(muted){
if (muted !== undefined) {
- this.apiCall("setMuted", muted);
+ this.techCall("setMuted", muted);
return this;
}
- return this.apiCall("muted");
+ return this.techCall("muted") || false; // Default to false
},
+ // http://dev.w3.org/html5/spec/dimension-attributes.html#attr-dim-height
+ // Video tag width/height only work in pixels. No percents.
+ // We could potentially allow percents but won't for now until we can do testing around it.
width: function(width, skipListeners){
if (width !== undefined) {
this.el.width = width;
this.el.style.width = width+"px";
+
+ // skipListeners allows us to avoid triggering the resize event when setting both width and height
if (!skipListeners) { this.triggerEvent("resize"); }
return this;
}
@@ -452,12 +490,14 @@ _V_.Player = _V_.Component.extend({
}
return parseInt(this.el.getAttribute("height"));
},
+ // Set both width and height at the same time.
size: function(width, height){
// Skip resize listeners on width for optimization
return this.width(width, true).height(height);
},
- supportsFullScreen: function(){ return this.apiCall("supportsFullScreen"); },
+ // Check if current tech can support native fullscreen (e.g. with built in controls lik iOS, so not our flash swf)
+ supportsFullScreen: function(){ return this.techCall("supportsFullScreen") || false; },
// Turn on fullscreen (or window) mode
requestFullScreen: function(){
@@ -492,7 +532,7 @@ _V_.Player = _V_.Component.extend({
}));
} else if (this.tech.supportsFullScreen()) {
- this.apiCall("enterFullScreen");
+ this.techCall("enterFullScreen");
} else {
this.enterFullWindow();
@@ -528,7 +568,7 @@ _V_.Player = _V_.Component.extend({
}
} else if (this.tech.supportsFullScreen()) {
- this.apiCall("exitFullScreen");
+ this.techCall("exitFullScreen");
} else {
this.exitFullWindow();
@@ -540,6 +580,7 @@ _V_.Player = _V_.Component.extend({
return this;
},
+ // When fullscreen isn't supported we can stretch the video container to as wide as the browser will let us.
enterFullWindow: function(){
this.isFullWindow = true;
@@ -558,7 +599,6 @@ _V_.Player = _V_.Component.extend({
this.triggerEvent("enterFullWindow");
},
-
fullWindowOnEscKey: function(event){
if (event.keyCode == 27) {
if (this.isFullScreen == true) {
@@ -585,6 +625,36 @@ _V_.Player = _V_.Component.extend({
this.triggerEvent("exitFullWindow");
},
+ selectSource: function(sources){
+
+ _V_.log(sources)
+
+ // Loop through each playback technology in the options order
+ for (var i=0,j=this.options.techOrder;i<j.length;i++) {
+ var techName = j[i],
+ tech = _V_[techName];
+ // tech = _V_.tech[techName];
+
+ // Check if the browser supports this technology
+ if (tech.isSupported()) {
+
+ // Loop through each source object
+ for (var a=0,b=sources;a<b.length;a++) {
+ var source = b[a];
+
+ // Check if source can be played with this technology
+ if (tech.canPlaySource.call(this, source)) {
+
+ return { source: source, tech: techName };
+
+ }
+ }
+ }
+ }
+
+ return false;
+ },
+
// src is a pretty powerful function
// If you pass it an array of source objects, it will find the best source to play and use that object.src
// If the new source requires a new playback technology, it will switch to that.
@@ -594,48 +664,36 @@ _V_.Player = _V_.Component.extend({
// Case: Array of source objects to choose from and pick the best to play
if (source instanceof Array) {
- var sources = source;
+ var sourceTech = this.selectSource(source),
+ source,
+ techName;
- techLoop: // Named loop for breaking both loops
- // Loop through each playback technology in the options order
- for (var i=0,j=this.options.techOrder;i<j.length;i++) {
- var techName = j[i],
- tech = _V_[techName];
- // tech = _V_.tech[techName];
+ if (sourceTech) {
+ source = sourceTech.source;
+ techName = sourceTech.tech;
- // Check if the browser supports this technology
- if (tech.isSupported()) {
+ // If this technology is already loaded, set source
+ if (techName == this.techName) {
+ this.src(source); // Passing the source object
- // Loop through each source object
- for (var a=0,b=sources;a<b.length;a++) {
- var source = b[a];
-
- // Check if source can be played with this technology
- if (tech.canPlaySource.call(this, source)) {
-
- // If this technology is already loaded, set source
- if (techName == this.techName) {
- this.src(source); // Passing the source object
-
- // Otherwise load this technology with chosen source
- } else {
- this.loadTech(techName, source);
- }
-
- break techLoop; // Break both loops
- }
- }
+ // Otherwise load this technology with chosen source
+ } else {
+ this.loadTech(techName, source);
}
+ } else {
+ _V_.log("No compatible source and playback technology were found.")
}
// Case: Source object { src: "", type: "" ... }
} else if (source instanceof Object) {
+
if (_V_[this.techName].canPlaySource(source)) {
this.src(source.src);
} else {
// Send through tech loop to check for a compatible technology.
this.src([source]);
}
+
// Case: URL String (http://myvideo...)
} else {
// Cache for getting last set source
@@ -646,7 +704,7 @@ _V_.Player = _V_.Component.extend({
this.src(source);
});
} else {
- this.apiCall("src", source);
+ this.techCall("src", source);
if (this.options.preload == "auto") {
this.load();
}
@@ -659,12 +717,15 @@ _V_.Player = _V_.Component.extend({
},
// Begin loading the src data
+ // http://dev.w3.org/html5/spec/video.html#dom-media-load
load: function(){
- this.apiCall("load");
+ this.techCall("load");
return this;
},
+
+ // http://dev.w3.org/html5/spec/video.html#dom-media-currentsrc
currentSrc: function(){
- return this.apiCall("currentSrc");
+ return this.techCall("currentSrc") || "";
},
textTrackValue: function(kind, value){
@@ -679,52 +740,52 @@ _V_.Player = _V_.Component.extend({
// Attributes/Options
preload: function(value){
if (value !== undefined) {
- this.apiCall("setPreload", value);
+ this.techCall("setPreload", value);
this.options.preload = value;
return this;
}
- return this.apiCall("preload", value);
+ return this.techCall("preload", value);
},
autoplay: function(value){
if (value !== undefined) {
- this.apiCall("setAutoplay", value);
+ this.techCall("setAutoplay", value);
this.options.autoplay = value;
return this;
}
- return this.apiCall("autoplay", value);
+ return this.techCall("autoplay", value);
},
loop: function(value){
if (value !== undefined) {
- this.apiCall("setLoop", value);
+ this.techCall("setLoop", value);
this.options.loop = value;
return this;
}
- return this.apiCall("loop", value);
+ return this.techCall("loop", value);
},
controls: function(){ return this.options.controls; },
textTracks: function(){ return this.options.tracks; },
- poster: function(){ return this.apiCall("poster"); },
-
- error: function(){ return this.apiCall("error"); },
- networkState: function(){ return this.apiCall("networkState"); },
- readyState: function(){ return this.apiCall("readyState"); },
- seeking: function(){ return this.apiCall("seeking"); },
- initialTime: function(){ return this.apiCall("initialTime"); },
- startOffsetTime: function(){ return this.apiCall("startOffsetTime"); },
- played: function(){ return this.apiCall("played"); },
- seekable: function(){ return this.apiCall("seekable"); },
- ended: function(){ return this.apiCall("ended"); },
- videoTracks: function(){ return this.apiCall("videoTracks"); },
- audioTracks: function(){ return this.apiCall("audioTracks"); },
- videoWidth: function(){ return this.apiCall("videoWidth"); },
- videoHeight: function(){ return this.apiCall("videoHeight"); },
- defaultPlaybackRate: function(){ return this.apiCall("defaultPlaybackRate"); },
- playbackRate: function(){ return this.apiCall("playbackRate"); },
- // mediaGroup: function(){ return this.apiCall("mediaGroup"); },
- // controller: function(){ return this.apiCall("controller"); },
- controls: function(){ return this.apiCall("controls"); },
- defaultMuted: function(){ return this.apiCall("defaultMuted"); }
+ poster: function(){ return this.techCall("poster"); },
+ error: function(){ return this.techCall("error"); },
+ ended: function(){ return this.techCall("ended"); }
+
+ // Methods to add support for
+ // networkState: function(){ return this.techCall("networkState"); },
+ // readyState: function(){ return this.techCall("readyState"); },
+ // seeking: function(){ return this.techCall("seeking"); },
+ // initialTime: function(){ return this.techCall("initialTime"); },
+ // startOffsetTime: function(){ return this.techCall("startOffsetTime"); },
+ // played: function(){ return this.techCall("played"); },
+ // seekable: function(){ return this.techCall("seekable"); },
+ // videoTracks: function(){ return this.techCall("videoTracks"); },
+ // audioTracks: function(){ return this.techCall("audioTracks"); },
+ // videoWidth: function(){ return this.techCall("videoWidth"); },
+ // videoHeight: function(){ return this.techCall("videoHeight"); },
+ // defaultPlaybackRate: function(){ return this.techCall("defaultPlaybackRate"); },
+ // playbackRate: function(){ return this.techCall("playbackRate"); },
+ // mediaGroup: function(){ return this.techCall("mediaGroup"); },
+ // controller: function(){ return this.techCall("controller"); },
+ // defaultMuted: function(){ return this.techCall("defaultMuted"); }
});
// RequestFullscreen API
View
50 src/setup.js
@@ -1,3 +1,53 @@
+// Automatically set up any tags that have a data-setup attribute
+_V_.autoSetup = function(){
+ var options, vid, player,
+ vids = document.getElementsByTagName("video");
+
+ // Check if any media elements exist
+ if (vids && vids.length > 0) {
+
+ for (var i=0,j=vids.length; i<j; i++) {
+ vid = vids[i];
+
+ // Check if element exists, has getAttribute func.
+ // IE seems to consider typeof el.getAttribute == "object" instead of "function" like expected, at least when loading the player immediately.
+ if (vid && vid.getAttribute) {
+
+ // Make sure this player hasn't already been set up.
+ if (vid.player === undefined) {
+ options = vid.getAttribute("data-setup");
+
+ // Check if data-setup attr exists.
+ // We only auto-setup if they've added the data-setup attr.
+ if (options !== null) {
+
+ // Parse options JSON
+ // If empty string, make it a parsable json object.
+ options = JSON.parse(options || "{}");
+
+ // Create new video.js instance.
+ player = _V_(vid, options);
+ }
+ }
+
+ // If getAttribute isn't defined, we need to wait for the DOM.
+ } else {
+ _V_.autoSetupTimeout(1);
+ break;
+ }
+ }
+
+ // No videos were found, so keep looping unless page is finisehd loading.
+ } else if (!_V_.windowLoaded) {
+ _V_.autoSetupTimeout(1);
+ }
+};
+
+// Pause to let the DOM keep processing
+_V_.autoSetupTimeout = function(wait){
+ setTimeout(_V_.autoSetup, wait);
+};
+
_V_.addEvent(window, "load", function(){
_V_.windowLoaded = true;
});
Please sign in to comment.
Something went wrong with that request. Please try again.