/* 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; // Make player findable on elements tag.player = el.player = this; // Add callback to ready queue this.ready(ready); // Wrap video tag in div (el/box) container tag.parentNode.insertBefore(el, tag); el.appendChild(tag); // Breaks iPhone, fixed in HTML5 setup. // 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 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(){ this.videoIsFullScreen = true; if (typeof this.el.webkitRequestFullScreen == 'function') { this.el.webkitRequestFullScreen(); } else if (typeof this.el.mozRequestFullScreen == 'function') { this.el.mozRequestFullScreen(); } else if (this.supportsFullScreen()) { this.apiCall("enterFullScreen"); } else { this.enterFullWindow(); } this.triggerEvent("enterFullScreen"); return this; }, exitFullScreen: function(){ this.videoIsFullScreen = false; if (typeof this.el.webkitRequestFullScreen == 'function') { document.webkitCancelFullScreen(); } else if (this.supportsFullScreen()) { document.webkitExitFullScreen(); } else { 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) { var sources = source; 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