2011-11-29 11:40:05 -08:00
|
|
|
/* UI Component- Base class for all UI objects
|
|
|
|
================================================================================ */
|
|
|
|
_V_.Player = _V_.Component.extend({
|
|
|
|
|
|
|
|
init: function(tag, addOptions, ready){
|
|
|
|
|
|
|
|
this.tag = tag; // Store the original tag used to set options
|
|
|
|
|
|
|
|
var el = this.el = _V_.createElement("div"), // Div to contain video and controls
|
|
|
|
options = this.options = {},
|
|
|
|
width = options.width = tag.width,
|
|
|
|
height = options.height = tag.height,
|
|
|
|
|
|
|
|
// Browsers default to 300x150 if there's no width/height or video size data.
|
|
|
|
initWidth = width || 300,
|
|
|
|
initHeight = height || 150,
|
|
|
|
|
|
|
|
// If the HTML5 video is already playing, we'll adjust
|
|
|
|
paused = tag.paused;
|
|
|
|
|
|
|
|
// Make player findable on elements
|
|
|
|
tag.player = el.player = this;
|
|
|
|
|
|
|
|
// Wrap video tag in div (el/box) container
|
|
|
|
tag.parentNode.insertBefore(el, tag);
|
|
|
|
el.appendChild(tag); // Breaks iPhone, fixed in HTML5 setup.
|
|
|
|
|
|
|
|
// Safari (5.1.1) and Chrome (15) both have issues when you use autoplay and a poster and no controls.
|
|
|
|
// Chrome just hides the video. Safari hides the video if you move it in the DOM like VJS does.
|
|
|
|
// This fixes the Safari issue by removing the poster, which is currently never used again after
|
|
|
|
// the video starts playing.
|
|
|
|
if (!paused) {
|
2011-11-29 16:39:43 -08:00
|
|
|
// options.poster = tag.poster
|
|
|
|
// tag.poster = null;
|
|
|
|
// tag.play();
|
2011-11-29 11:40:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Give video tag properties to box
|
|
|
|
el.id = this.id = tag.id; // ID will now reference box, not the video tag
|
|
|
|
el.className = tag.className;
|
|
|
|
// Update tag id/class for use as HTML5 playback tech
|
|
|
|
tag.id += "_html5_api";
|
|
|
|
tag.className = "vjs-tech";
|
|
|
|
|
|
|
|
// Make player easily findable by ID
|
|
|
|
_V_.players[el.id] = this;
|
|
|
|
|
|
|
|
// Make box use width/height of tag, or default 300x150
|
|
|
|
el.setAttribute("width", initWidth);
|
|
|
|
el.setAttribute("height", initHeight);
|
|
|
|
// Enforce with CSS since width/height attrs don't work on divs
|
|
|
|
el.style.width = initWidth+"px";
|
|
|
|
el.style.height = initHeight+"px";
|
|
|
|
// Remove width/height attrs from tag so CSS can make it 100% width/height
|
|
|
|
tag.removeAttribute("width");
|
|
|
|
tag.removeAttribute("height");
|
|
|
|
|
|
|
|
// Set Options
|
|
|
|
_V_.merge(options, _V_.options); // Copy Global Defaults
|
|
|
|
_V_.merge(options, this.getVideoTagSettings()); // Override with Video Tag Options
|
|
|
|
_V_.merge(options, addOptions); // Override/extend with options from setup call
|
|
|
|
|
|
|
|
// Store controls setting, and then remove immediately so native controls don't flash.
|
|
|
|
tag.removeAttribute("controls");
|
|
|
|
|
|
|
|
// Empty video tag sources and tracks so the built in player doesn't use them also.
|
|
|
|
if (tag.hasChildNodes()) {
|
|
|
|
for (var i=0,j=tag.childNodes;i<j.length;i++) {
|
|
|
|
if (j[i].nodeName == "SOURCE" || j[i].nodeName == "TRACK") {
|
|
|
|
tag.removeChild(j[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add callback to ready queue
|
|
|
|
this.apiIsReady = false;
|
|
|
|
this.readyQueue = [];
|
|
|
|
if (ready) { this.ready(ready); }
|
|
|
|
|
|
|
|
// Holder for playback tech components
|
|
|
|
this.techs = {};
|
|
|
|
|
|
|
|
// Cache for video property values.
|
|
|
|
this.values = {};
|
|
|
|
|
|
|
|
this.addClass("vjs-paused");
|
|
|
|
|
|
|
|
this.addEvent("ended", this.onEnded);
|
|
|
|
this.addEvent("play", this.onPlay);
|
|
|
|
this.addEvent("pause", this.onPause);
|
|
|
|
|
|
|
|
// When the API is ready, loop through the components and add to the player.
|
|
|
|
this.components = [];
|
|
|
|
if (this.options.controls) {
|
|
|
|
this.addEvent("techready", function(){
|
|
|
|
this.each(this.options.components, function(set){
|
|
|
|
this.addComponent(set);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Loop through playback technologies (HTML5, Flash) and check for support
|
|
|
|
// Then load the best source.
|
|
|
|
this.src(this.options.sources);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Cache for video property values.
|
|
|
|
values: {},
|
|
|
|
|
|
|
|
destroy: function(){},
|
|
|
|
|
|
|
|
createElement: function(type, options){
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
getVideoTagSettings: function(){
|
|
|
|
var options = {
|
|
|
|
sources: [],
|
|
|
|
tracks: []
|
|
|
|
};
|
|
|
|
|
|
|
|
options.src = this.tag.src;
|
|
|
|
options.controls = this.tag.getAttribute("controls") !== null;
|
|
|
|
options.poster = this.tag.poster;
|
|
|
|
options.preload = this.tag.preload;
|
|
|
|
options.autoplay = this.tag.getAttribute("autoplay") !== null; // hasAttribute not IE <8 compatible
|
|
|
|
options.loop = this.tag.getAttribute("loop") !== null;
|
|
|
|
options.muted = this.tag.getAttribute("muted") !== null;
|
|
|
|
|
|
|
|
for (var c,i=0,j=this.tag.children;i<j.length;i++) {
|
|
|
|
c = j[i];
|
|
|
|
if (c.nodeName == "SOURCE") {
|
|
|
|
options.sources.push({
|
|
|
|
src: c.src,
|
|
|
|
type: c.type,
|
|
|
|
media: c.media,
|
|
|
|
title: c.title
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (c.nodeName == "TRACK") {
|
|
|
|
options.tracks.push(new _V_.Track({
|
|
|
|
src: c.getAttribute("src"),
|
|
|
|
kind: c.getAttribute("kind"),
|
|
|
|
srclang: c.getAttribute("srclang"),
|
|
|
|
label: c.getAttribute("label"),
|
|
|
|
'default': c.getAttribute("default") !== null,
|
|
|
|
title: c.getAttribute("title")
|
|
|
|
}, this));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return options;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* PLayback Technology (tech)
|
|
|
|
================================================================================ */
|
|
|
|
// Load/Create an instance of playback technlogy including element and API methods
|
|
|
|
// And append playback element in player div.
|
|
|
|
loadTech: function(techName, source){
|
|
|
|
|
|
|
|
// Pause and remove current playback technology
|
|
|
|
if (this.tech) {
|
|
|
|
this.removeTech(tech);
|
|
|
|
|
|
|
|
// If the first time loading, HTML5 tag will exist but won't be initialized
|
|
|
|
// So we need to remove it if we're not loading HTML5
|
|
|
|
} else if (!this.tech && techName != "HTML5") {
|
|
|
|
this.removeTechElement(this.tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.techName = techName;
|
|
|
|
|
|
|
|
// Turn off API access because we're loading a new tech that might load asynchronously
|
|
|
|
this.isReady = false;
|
|
|
|
|
|
|
|
// Finsh API Setup when tech is ready
|
|
|
|
this.addEvent("techready", _V_.proxy(this, function(){
|
|
|
|
// Reomve this so it's not called twice next load
|
|
|
|
this.removeEvent("techready", arguments.callee);
|
|
|
|
|
|
|
|
// Set up playback technology's event triggers
|
|
|
|
this.tech.setupTriggers();
|
|
|
|
this.triggerReady();
|
|
|
|
|
|
|
|
// Manually track progress in cases where the browser/flash player doesn't report it.
|
|
|
|
if (!_V_.techSupports(techName, "event", "progress")) { this.manualProgressOn(); }
|
|
|
|
|
|
|
|
// Manually track timeudpates in cases where the browser/flash player doesn't report it.
|
|
|
|
if (!_V_.techSupports(techName, "event", "timeupdate")) { this.manualTimeUpdatesOn(); }
|
|
|
|
}));
|
|
|
|
|
|
|
|
// Initialize new tech if it hasn't been yet and load source
|
|
|
|
// Add tech element to player div
|
|
|
|
if (this.techs[techName] === undefined) {
|
|
|
|
this.techs[techName] = this.tech = new _V_[techName](this, { source: source });
|
|
|
|
} else {
|
|
|
|
this.tech = this.techs[techName];
|
|
|
|
_V_.insertFirst(this.techs[techName].el, this.el);
|
|
|
|
this.src(source);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
removeTech: function(tech){
|
|
|
|
this.removeTechElement(tech.el);
|
|
|
|
// TODO: Remove API listeners as well
|
|
|
|
},
|
|
|
|
|
|
|
|
removeTechElement: function(el){
|
|
|
|
this.el.removeChild(el);
|
|
|
|
},
|
|
|
|
|
|
|
|
/* Fallbacks for unsupported event types
|
|
|
|
================================================================================ */
|
|
|
|
// Manually trigger progress events based on changes to the buffered amount
|
|
|
|
// Many flash players and older HTML5 browsers don't send progress or progress-like events
|
|
|
|
manualProgressOn: function(){
|
|
|
|
this.manualProgress = true;
|
|
|
|
|
|
|
|
// Trigger progress watching when a source begins loading
|
|
|
|
this.trackProgress();
|
|
|
|
|
|
|
|
// Watch for a native progress event call on the tech element
|
|
|
|
// In HTML5, some older versions don't support the progress event
|
|
|
|
// So we're assuming they don't, and turning off manual progress if they do.
|
|
|
|
this.tech.addEvent("progress", function(){
|
|
|
|
|
|
|
|
// Remove this listener from the element
|
|
|
|
this.removeEvent("progress", arguments.callee);
|
|
|
|
|
|
|
|
// Update known progress support for this playback technology
|
|
|
|
_V_.updateTechSupport(this.name, "event", "progress", true);
|
|
|
|
|
|
|
|
// Turn off manual progress tracking
|
|
|
|
this.player.manualProgressOff();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
manualProgressOff: function(){
|
|
|
|
this.manualProgress = false;
|
|
|
|
this.stopTrackingProgress();
|
|
|
|
},
|
|
|
|
|
|
|
|
trackProgress: function(){
|
|
|
|
this.progressInterval = setInterval(_V_.proxy(this, function(){
|
|
|
|
// Don't trigger unless buffered amount is greater than last time
|
|
|
|
// log(this.values.bufferEnd, this.buffered().end(0), this.duration())
|
|
|
|
/* TODO: update for multiple buffered regions */
|
|
|
|
if (this.values.bufferEnd < this.buffered().end(0)) {
|
|
|
|
this.triggerEvent("progress");
|
|
|
|
} else if (this.bufferedPercent() == 1) {
|
|
|
|
this.stopTrackingProgress();
|
|
|
|
this.triggerEvent("progress"); // Last update
|
|
|
|
}
|
|
|
|
}), 500);
|
|
|
|
},
|
|
|
|
stopTrackingProgress: function(){ clearInterval(this.progressInterval); },
|
|
|
|
|
|
|
|
/* Time Tracking -------------------------------------------------------------- */
|
|
|
|
manualTimeUpdatesOn: function(){
|
|
|
|
this.manualTimeUpdates = true;
|
|
|
|
|
|
|
|
this.addEvent("play", this.trackCurrentTime);
|
|
|
|
this.addEvent("pause", this.stopTrackingCurrentTime);
|
|
|
|
// timeupdate is also called by .currentTime whenever current time is set
|
|
|
|
|
|
|
|
// Watch for native timeupdate event
|
|
|
|
this.tech.addEvent("timeupdate", function(){
|
|
|
|
|
|
|
|
// Remove this listener from the element
|
|
|
|
this.removeEvent("timeupdate", arguments.callee);
|
|
|
|
|
|
|
|
// Update known progress support for this playback technology
|
|
|
|
_V_.updateTechSupport(this.name, "event", "timeupdate", true);
|
|
|
|
|
|
|
|
// Turn off manual progress tracking
|
|
|
|
this.player.manualTimeUpdatesOff();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
manualTimeUpdatesOff: function(){
|
|
|
|
this.manualTimeUpdates = false;
|
|
|
|
this.stopTrackingCurrentTime();
|
|
|
|
this.removeEvent("play", this.trackCurrentTime);
|
|
|
|
this.removeEvent("pause", this.stopTrackingCurrentTime);
|
|
|
|
},
|
|
|
|
|
|
|
|
trackCurrentTime: function(){
|
|
|
|
if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); }
|
|
|
|
this.currentTimeInterval = setInterval(_V_.proxy(this, function(){
|
|
|
|
this.triggerEvent("timeupdate");
|
|
|
|
}), 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
|
|
|
|
},
|
|
|
|
|
|
|
|
// Turn off play progress tracking (when paused or dragging)
|
|
|
|
stopTrackingCurrentTime: function(){ clearInterval(this.currentTimeInterval); },
|
|
|
|
|
|
|
|
/* Player event handlers (how the player reacts to certain events)
|
|
|
|
================================================================================ */
|
|
|
|
onEnded: function(){
|
|
|
|
if (this.options.loop) {
|
|
|
|
this.currentTime(0);
|
|
|
|
this.play();
|
|
|
|
} else {
|
|
|
|
// this.pause();
|
|
|
|
// this.currentTime(0);
|
|
|
|
// this.pause();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
onPlay: function(){
|
|
|
|
_V_.removeClass(this.el, "vjs-paused");
|
|
|
|
_V_.addClass(this.el, "vjs-playing");
|
|
|
|
},
|
|
|
|
|
|
|
|
onPause: function(){
|
|
|
|
_V_.removeClass(this.el, "vjs-playing");
|
|
|
|
_V_.addClass(this.el, "vjs-paused");
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
/* Player API
|
|
|
|
================================================================================ */
|
|
|
|
_V_.Player.prototype.extend({
|
|
|
|
|
|
|
|
apiCall: function(method, arg){
|
|
|
|
if (this.isReady) {
|
|
|
|
return this.tech[method](arg);
|
|
|
|
} else {
|
|
|
|
throw new Error("The playback technology API is not ready yet. Use player.ready(myFunction).");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
play: function(){
|
|
|
|
this.apiCall("play"); return this;
|
|
|
|
},
|
|
|
|
pause: function(){
|
|
|
|
this.apiCall("pause"); return this;
|
|
|
|
},
|
|
|
|
paused: function(){
|
|
|
|
return this.apiCall("paused");
|
|
|
|
},
|
|
|
|
|
|
|
|
currentTime: function(seconds){
|
|
|
|
if (seconds !== undefined) {
|
|
|
|
this.values.currentTime = seconds; // Cache the last set value for smoother scrubbing.
|
|
|
|
this.apiCall("setCurrentTime", seconds);
|
|
|
|
if (this.manualTimeUpdates) { this.triggerEvent("timeupdate"); }
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return this.apiCall("currentTime");
|
|
|
|
},
|
|
|
|
duration: function(){
|
|
|
|
return this.apiCall("duration");
|
|
|
|
},
|
|
|
|
remainingTime: function(){
|
|
|
|
return this.duration() - this.currentTime();
|
|
|
|
},
|
|
|
|
|
|
|
|
buffered: function(){
|
|
|
|
var buffered = this.apiCall("buffered"),
|
|
|
|
start = 0, end = this.values.bufferEnd = this.values.bufferEnd || 0,
|
|
|
|
timeRange;
|
|
|
|
|
|
|
|
if (buffered && buffered.length > 0 && buffered.end(0) > end) {
|
|
|
|
end = buffered.end(0);
|
|
|
|
// Storing values allows them be overridden by setBufferedFromProgress
|
|
|
|
this.values.bufferEnd = end;
|
|
|
|
}
|
|
|
|
|
|
|
|
return _V_.createTimeRange(start, end);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Calculates amount of buffer is full
|
|
|
|
bufferedPercent: function(){
|
|
|
|
return (this.duration()) ? this.buffered().end(0) / this.duration() : 0;
|
|
|
|
},
|
|
|
|
|
|
|
|
volume: function(percentAsDecimal){
|
|
|
|
if (percentAsDecimal !== undefined) {
|
|
|
|
var vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1
|
|
|
|
this.values.volume = vol;
|
|
|
|
this.apiCall("setVolume", vol);
|
|
|
|
_V_.setLocalStorage("volume", vol);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
// if (this.values.volume) { return this.values.volume; }
|
|
|
|
return this.apiCall("volume");
|
|
|
|
},
|
|
|
|
muted: function(muted){
|
|
|
|
if (muted !== undefined) {
|
|
|
|
this.apiCall("setMuted", muted);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return this.apiCall("muted");
|
|
|
|
},
|
|
|
|
|
|
|
|
width: function(width, skipListeners){
|
|
|
|
if (width !== undefined) {
|
|
|
|
this.el.width = width;
|
|
|
|
this.el.style.width = width+"px";
|
|
|
|
if (!skipListeners) { this.triggerEvent("resize"); }
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return parseInt(this.el.getAttribute("width"));
|
|
|
|
},
|
|
|
|
height: function(height){
|
|
|
|
if (height !== undefined) {
|
|
|
|
this.el.height = height;
|
|
|
|
this.el.style.height = height+"px";
|
|
|
|
this.triggerEvent("resize");
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return parseInt(this.el.getAttribute("height"));
|
|
|
|
},
|
|
|
|
size: function(width, height){
|
|
|
|
// Skip resize listeners on width for optimization
|
|
|
|
return this.width(width, true).height(height);
|
|
|
|
},
|
|
|
|
|
|
|
|
supportsFullScreen: function(){ return this.apiCall("supportsFullScreen"); },
|
|
|
|
|
|
|
|
// Turn on fullscreen (or window) mode
|
|
|
|
enterFullScreen: function(){
|
|
|
|
if (this.supportsFullScreen()) {
|
|
|
|
this.apiCall("enterFullScreen");
|
|
|
|
} else {
|
|
|
|
this.enterFullWindow();
|
|
|
|
}
|
|
|
|
this.triggerEvent("enterFullScreen");
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
exitFullScreen: function(){
|
|
|
|
if (true || !this.supportsFullScreen()) {
|
|
|
|
this.exitFullWindow();
|
|
|
|
}
|
|
|
|
this.triggerEvent("exitFullScreen");
|
|
|
|
|
|
|
|
// Otherwise Shouldn't be called since native fullscreen uses own controls.
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
enterFullWindow: function(){
|
|
|
|
this.videoIsFullScreen = true;
|
|
|
|
|
|
|
|
// Storing original doc overflow value to return to when fullscreen is off
|
|
|
|
this.docOrigOverflow = document.documentElement.style.overflow;
|
|
|
|
|
|
|
|
// Add listener for esc key to exit fullscreen
|
|
|
|
_V_.addEvent(document, "keydown", _V_.proxy(this, this.fullWindowOnEscKey));
|
|
|
|
|
|
|
|
// Hide any scroll bars
|
|
|
|
document.documentElement.style.overflow = 'hidden';
|
|
|
|
|
|
|
|
// Apply fullscreen styles
|
|
|
|
_V_.addClass(document.body, "vjs-full-window");
|
|
|
|
_V_.addClass(this.el, "vjs-fullscreen");
|
|
|
|
|
|
|
|
this.triggerEvent("enterFullWindow");
|
|
|
|
},
|
|
|
|
|
|
|
|
fullWindowOnEscKey: function(event){
|
|
|
|
if (event.keyCode == 27) {
|
|
|
|
this.exitFullScreen();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
exitFullWindow: function(){
|
|
|
|
this.videoIsFullScreen = false;
|
|
|
|
_V_.removeEvent(document, "keydown", this.fullWindowOnEscKey);
|
|
|
|
|
|
|
|
// Unhide scroll bars.
|
|
|
|
document.documentElement.style.overflow = this.docOrigOverflow;
|
|
|
|
|
|
|
|
// Remove fullscreen styles
|
|
|
|
_V_.removeClass(document.body, "vjs-full-window");
|
|
|
|
_V_.removeClass(this.el, "vjs-fullscreen");
|
|
|
|
|
|
|
|
// Resize the box, controller, and poster to original sizes
|
|
|
|
// this.positionAll();
|
|
|
|
this.triggerEvent("exitFullWindow");
|
|
|
|
},
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
// If you pass it an object, it will set the source to object.src
|
|
|
|
// If you pass it anything else (url string) it will set the video source to that
|
|
|
|
src: function(source){
|
|
|
|
// Case: Array of source objects to choose from and pick the best to play
|
|
|
|
if (source instanceof Array) {
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
// Check if the browser supports this technology
|
|
|
|
if (tech.isSupported()) {
|
|
|
|
|
|
|
|
// Loop through each source object
|
|
|
|
for (var a=0,b=this.options.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.currentTechName) {
|
|
|
|
this.src(source); // Passing the source object
|
|
|
|
|
|
|
|
// Otherwise load this technology with chosen source
|
|
|
|
} else {
|
|
|
|
this.loadTech(techName, source);
|
|
|
|
}
|
|
|
|
|
|
|
|
break techLoop; // Break both loops
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Case: Source object { src: "", type: "" ... }
|
|
|
|
} else if (source instanceof Object) {
|
|
|
|
this.src(source.src);
|
|
|
|
|
|
|
|
// Case: URL String (http://myvideo...)
|
|
|
|
} else {
|
|
|
|
this.apiCall("src", source);
|
|
|
|
this.load();
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Begin loading the src data
|
|
|
|
load: function(){
|
|
|
|
this.apiCall("load");
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
currentSrc: function(){
|
|
|
|
return this.apiCall("currentSrc");
|
|
|
|
},
|
|
|
|
|
|
|
|
textTrackValue: function(kind, value){
|
|
|
|
if (value !== undefined) {
|
|
|
|
this.values[kind] = value;
|
|
|
|
this.triggerEvent(kind+"update");
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return this.values[kind];
|
|
|
|
},
|
|
|
|
|
|
|
|
// Attributes/Options
|
|
|
|
preload: function(value){
|
|
|
|
if (value !== undefined) {
|
|
|
|
this.apiCall("setPreload", value);
|
|
|
|
this.options.preload = value;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return this.apiCall("preload", value);
|
|
|
|
},
|
|
|
|
autoplay: function(value){
|
|
|
|
if (value !== undefined) {
|
|
|
|
this.apiCall("setAutoplay", value);
|
|
|
|
this.options.autoplay = value;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return this.apiCall("autoplay", value);
|
|
|
|
},
|
|
|
|
loop: function(value){
|
|
|
|
if (value !== undefined) {
|
|
|
|
this.apiCall("setLoop", value);
|
|
|
|
this.options.loop = value;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return this.apiCall("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"); }
|
|
|
|
});
|
|
|
|
|