1
0
mirror of https://github.com/videojs/video.js.git synced 2024-11-24 08:42:25 +02:00

Continued updating all library pieces to support closure compiler.

Renamed internal lib var to vjs instead of _V_.
This commit is contained in:
Steve Heffernan 2013-01-04 16:58:23 -08:00
parent e125ee878e
commit 428203c466
23 changed files with 1315 additions and 1208 deletions

View File

@ -17,7 +17,7 @@ cp dev.html.example dev.html
You can use dev.html to test new code. It's simple HTML doc that includes all the source files. Send a pull request for any updates.
---
BETA NOTES
BETA NOTES
Version 3 is almost a complete rewrite of the previous versions of VideoJS. New features includes:
- HTML/CSS Controls and API now work for both the HTML5 and Flash versions.
@ -27,3 +27,10 @@ Version 3 is almost a complete rewrite of the previous versions of VideoJS. New
- No more embedding of Flash fallback within the video tag HTML.
---
TESTING FLASH LOCALLY IN CHROME
-------------------------------
Chrome 21+ (as of 2013/01/01) doens't run Flash files that are local and loaded into a locally accessed page (file:///). To get around this you need to [disable the version of Flash](http://helpx.adobe.com/flash-player/kb/flash-player-google-chrome.html#How_can_I_run_debugger_or_alternate_versions_of_Flash_Player_in_Google_Chrome) included with Chrome and enable a system-wide version of Flash.

View File

@ -4,6 +4,16 @@ require 'httparty'
namespace :build do
desc "Compile"
task :compiled do
Rake::Shell['java -jar build/compiler/compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js=src/goog.base.js --js=src/core.js --js=src/lib.js --js=src/events.js --js=src/component.js --js=src/player.js --js=src/media.js --js=src/media.html5.js --js=src/media.flash.js --js=src/controls.js --js=src/tracks.js --js=src/setup.js --js=src/json.js --js=src/exports.js --formatting=pretty_print --js_output_file=closure-test/video.compiled.js --create_source_map closure-test/video.compiled.js.map --source_map_format=V3 --externs src/media.flash.externs.js --externs closure-test/qunit-externs.js --output_wrapper "(function() {%output%})();//@ sourceMappingURL=video.compiled.js.map"']
end
desc "Compile with test"
task :compiled_tests do
Rake::Shell['java -jar build/compiler/compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js=src/goog.base.js --js=src/core.js --js=src/lib.js --js=src/events.js --js=src/component.js --js=src/player.js --js=src/media.js --js=src/media.html5.js --js=src/media.flash.js --js=src/controls.js --js=src/tracks.js --js=src/setup.js --js=src/json.js --js=src/exports.js --js=closure-test/unit/component.js --js=closure-test/unit/lib.js --js=closure-test/unit/events.js --js=closure-test/unit/player.js --formatting=pretty_print --js_output_file=closure-test/video.test.compiled.js --create_source_map closure-test/video.test.compiled.js.map --source_map_format=V3 --externs src/media.flash.externs.js --externs closure-test/qunit-externs.js --output_wrapper "(function() {%output%})();//@ sourceMappingURL=video.test.compiled.js.map"']
end
desc "Build version for current '/c/' CDN copy and locked in version"
task :current do
Rake::Task["build:source"].execute
@ -118,7 +128,7 @@ namespace :build do
file.puts "var vjsSourceList = [];"
src_array = ["src/core", "src/lib"]
last = ["src/setup"] # "flash/swfobject",
last = ["src/setup"] # "flash/swfobject",
exclude = [".", "..", ".DS_Store", "_end.js", "_begin.js"]
Dir.foreach('src') do |item|
@ -141,7 +151,7 @@ namespace :build do
end
end
desc "Build list of source files for easy inclusion in projects"
task :source_html do
@ -149,7 +159,7 @@ namespace :build do
file.puts "<!-- Video.js Source Files -->"
src_array = ["src/core", "src/lib"]
last = ["src/setup"] # "flash/swfobject",
last = ["src/setup"] # "flash/swfobject",
exclude = [".", "..", ".DS_Store", "_end.js", "_begin.js"]
Dir.foreach('src') do |item|
@ -169,7 +179,7 @@ namespace :build do
end
# file.puts "vjsSourceList.push('src/#{item.sub(".js", "")}')"
# file.puts "vjsSourceList.push('flash/swfobject.js')"
file.puts "<!-- END Video.js Source Files -->"
end

View File

@ -23,14 +23,14 @@
<script src="tech/html5/html5.js"></script>
<script src="tech/flash/flash.js"></script>
<script src="src/setup.js"></script>
<script type="text/javascript" charset="utf-8">
// Easy access to test Flash over HTML5. Add ?flash to URL
if (window.location.href.indexOf("?flash") !== -1) {
_V_.options.techOrder = ["flash"];
_V_.options.flash.swf = "tech/flash/video-js.swf";
_V_.options.Flash.swf = "tech/flash/video-js.swf";
}
</script>

View File

@ -6,7 +6,7 @@ Video.js is pretty easy to set up. It can take a matter of seconds to get the pl
Step 1: Include the Video.js Javascript and CSS files in the head of your page.
------------------------------------------------------------------------------
You can download the Video.js source and host it on your own servers, or use the free CDN hosted version. It's often recommended now to put JavaScript before the end body tag (&lt;/body>) instead of the head (&lt;head>), but Video.js includes an 'HTML5 Shiv', which needs to be in the head for older IE versions to respect the video tag as a valid element.
You can download the Video.js source and host it on your own servers, or use the free CDN hosted version. It's often recommended now to put JavaScript before the end body tag (&lt;/body>) instead of the head (&lt;head>), but Video.js includes an 'HTML5 Shiv', which needs to be in the head for older IE versions to respect the video tag as a valid element.
> NOTE: If you're already using an HTML5 shiv like [Modernizr](http://modernizr.com/) you can include the Video.js JavaScript anywhere, however make sure your version of Modernizr includes the shiv for video.
@ -22,7 +22,7 @@ With the self hosted option you'll also want to update the location of the video
<link href="http://example.com/path/to/video-js.css" rel="stylesheet">
<script src="http://example.com/path/to/video.js"></script>
<script>
_V_.options.flash.swf = "http://example.com/path/to/video-js.swf"
_V_.options.Flash.swf = "http://example.com/path/to/video-js.swf"
</script>
```
@ -42,13 +42,13 @@ With Video.js you just use an HTML5 video tag to embed a video. Video.js will th
Otherwise include/exclude attributes, settings, sources, and tracks exactly as you would for HTML5 video.
```html
<video id="example_video_1" class="video-js vjs-default-skin"
controls preload="auto" width="640" height="264"
poster="http://video-js.zencoder.com/oceans-clip.png"
data-setup='{"example_option":true}'>
<source src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4' />
<source src="http://video-js.zencoder.com/oceans-clip.webm" type='video/webm' />
<source src="http://video-js.zencoder.com/oceans-clip.ogv" type='video/ogg' />
<video id="example_video_1" class="video-js vjs-default-skin"
controls preload="auto" width="640" height="264"
poster="http://video-js.zencoder.com/oceans-clip.png"
data-setup='{"example_option":true}'>
<source src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4' />
<source src="http://video-js.zencoder.com/oceans-clip.webm" type='video/webm' />
<source src="http://video-js.zencoder.com/oceans-clip.ogv" type='video/ogg' />
</video>
```
@ -62,9 +62,9 @@ _V_("example_video_1", {}, function(){
});
```
The first argument in the \_V_ function is the ID of your video tag. Replace it with your own.
The first argument in the \_V_ function is the ID of your video tag. Replace it with your own.
The second argument is an options object. It allows you to set additional options like you can with the data-setup attribute.
The second argument is an options object. It allows you to set additional options like you can with the data-setup attribute.
The third argument is a 'ready' callback. Once Video.js has initialized it will call this function.

View File

@ -1,24 +0,0 @@
/*!
Video.js - HTML5 Video Player
Version GENERATED_AT_BUILD
LGPL v3 LICENSE INFO
This file is part of Video.js. Copyright 2011 Zencoder, Inc.
Video.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Video.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Video.js. If not, see <http://www.gnu.org/licenses/>.
*/
// Self-executing function to prevent global vars and help with minification
;(function(window, undefined){
var document = window.document;

View File

@ -1,6 +0,0 @@
// Expose to global
window.VideoJS = window._V_ = VideoJS;
// End self-executing function
})(window);

View File

@ -2,9 +2,9 @@
* Player Component - Base class for all UI objects
*/
goog.provide('_V_.Component');
goog.provide('vjs.Component');
goog.require('_V_');
goog.require('vjs');
/**
* Base UI Component class
@ -12,20 +12,24 @@ goog.require('_V_');
* @param {Object=} options
* @constructor
*/
_V_.Component = function(player, options, ready){
vjs.Component = function(player, options, ready){
this.player = player;
// // Allow for overridding default component options
options = this.options = _V_.merge(this.options || {}, options);
options = this.options = vjs.merge(this.options || {}, options);
// Get ID from options, element, or create using player ID and unique ID
this.id_ = options.id || ((options.el && options.el.id) ? options.el.id : player.id + "_component_" + _V_.guid++);
this.id_ = options.id || ((options.el && options.el.id) ? options.el.id : player.id + "_component_" + vjs.guid++);
this.name_ = options.name || null;
// Create element if one wasn't provided in potions
this.el_ = (options.el) ? options.el : this.createEl();
this.children_ = [];
this.childIndex_ = {};
this.childNameIndex_ = {};
// Add any child components in options
this.initChildren();
@ -37,7 +41,7 @@ _V_.Component = function(player, options, ready){
/**
* Dispose of the component and all child components.
*/
_V_.Component.prototype.dispose = function(){
vjs.Component.prototype.dispose = function(){
// Dispose all children.
if (this.children_) {
for (var i = this.children_.length - 1; i >= 0; i--) {
@ -58,7 +62,7 @@ _V_.Component.prototype.dispose = function(){
this.el_.parentNode.removeChild(this.el_);
}
_V_.removeData(this.el_);
vjs.removeData(this.el_);
this.el_ = null;
};
@ -67,14 +71,14 @@ _V_.Component.prototype.dispose = function(){
* @type {Object}
* @private
*/
_V_.Component.prototype.options;
vjs.Component.prototype.options;
/**
* The DOM element for the component.
* @type {Element}
* @private
*/
_V_.Component.prototype.el_;
vjs.Component.prototype.el_;
/**
* Create the component's DOM element.
@ -82,15 +86,15 @@ _V_.Component.prototype.el_;
* @param {Object=} attributes An object of element attributes that should be set on the element.
* @return {Element}
*/
_V_.Component.prototype.createEl = function(tagName, attributes){
return _V_.createEl(tagName, attributes);
vjs.Component.prototype.createEl = function(tagName, attributes){
return vjs.createEl(tagName, attributes);
};
/**
* Return the component's DOM element.
* @return {Element}
*/
_V_.Component.prototype.getEl = function(){
vjs.Component.prototype.getEl = function(){
return this.el_;
};
@ -99,13 +103,13 @@ _V_.Component.prototype.getEl = function(){
* @type {String}
* @private
*/
_V_.Component.prototype.id_;
vjs.Component.prototype.id_;
/**
* Return the component's ID.
* @return {String}
*/
_V_.Component.prototype.getId = function(){
vjs.Component.prototype.getId = function(){
return this.id_;
};
@ -114,13 +118,13 @@ _V_.Component.prototype.getId = function(){
* @type {String}
* @private
*/
_V_.Component.prototype.name_;
vjs.Component.prototype.name_;
/**
* Return the component's ID.
* @return {String}
*/
_V_.Component.prototype.getName = function(){
vjs.Component.prototype.getName = function(){
return this.name_;
};
@ -129,13 +133,13 @@ _V_.Component.prototype.getName = function(){
* @type {Array}
* @private
*/
_V_.Component.prototype.children_;
vjs.Component.prototype.children_;
/**
* Returns array of all child components.
* @return {Array}
*/
_V_.Component.prototype.getChildren = function(){
vjs.Component.prototype.getChildren = function(){
return this.children_;
}
@ -144,13 +148,13 @@ _V_.Component.prototype.getChildren = function(){
* @type {Object}
* @private
*/
_V_.Component.prototype.childIndex_;
vjs.Component.prototype.childIndex_;
/**
* Returns a child component with the provided ID.
* @return {Array}
*/
_V_.Component.prototype.getChildById = function(id){
vjs.Component.prototype.getChildById = function(id){
return this.childIndex_[id];
}
@ -159,25 +163,25 @@ _V_.Component.prototype.getChildById = function(id){
* @type {Object}
* @private
*/
_V_.Component.prototype.childNameIndex_;
vjs.Component.prototype.childNameIndex_;
/**
* Returns a child component with the provided ID.
* @return {Array}
*/
_V_.Component.prototype.getChild = function(name){
vjs.Component.prototype.getChild = function(name){
return this.childNameIndex_[name];
}
/**
* Adds a child component inside this component.
* @param {String|_V_.Component} child The class name or instance of a child to add.
* @param {String|vjs.Component} child The class name or instance of a child to add.
* @param {Object=} options Optional options, including options to be passed to
* children of the child.
* @return {_V_.Component} The child component, because it might be created in this process.
* @return {vjs.Component} The child component, because it might be created in this process.
* @suppress {accessControls|checkRegExp|checkTypes|checkVars|const|constantProperty|deprecated|duplicate|es5Strict|fileoverviewTags|globalThis|invalidCasts|missingProperties|nonStandardJsDocs|strictModuleDepCheck|undefinedNames|undefinedVars|unknownDefines|uselessCode|visibility}
*/
_V_.Component.prototype.addChild = function(child, options){
vjs.Component.prototype.addChild = function(child, options){
var component, componentClass, componentName, componentId;
// If string, create new component with options
@ -189,16 +193,16 @@ _V_.Component.prototype.addChild = function(child, options){
options = options || {};
// Assume name of set is a lowercased name of the UI Class (PlayButton, etc.)
componentClass = options.componentClass || _V_.capitalize(componentName);
componentClass = options.componentClass || vjs.capitalize(componentName);
// Set name through options
options.name = componentName;
// Create a new object & element for this controls set
// If there's no .player, this is a player
// Closure Compiler throws an 'incomplete alias' warning if we use the _V_ variable directly.
// Closure Compiler throws an 'incomplete alias' warning if we use the vjs variable directly.
// Every class should be exported, so this should never be a problem here.
component = new window['_V_'][componentClass](this.player || this, options);
component = new window['videojs'][componentClass](this.player || this, options);
// child is a component instance
} else {
@ -208,10 +212,6 @@ _V_.Component.prototype.addChild = function(child, options){
componentName = component.getName();
componentId = component.getId();
this.children_ = this.children_ || [];
this.childIndex_ = this.childNameIndex_ || {};
this.childNameIndex_ = this.childNameIndex_ || {};
this.children_.push(component);
if (componentId) {
@ -229,7 +229,7 @@ _V_.Component.prototype.addChild = function(child, options){
return component;
};
_V_.Component.prototype.removeChild = function(component){
vjs.Component.prototype.removeChild = function(component){
if (typeof component === 'string') {
component = this.getChild(component);
}
@ -259,17 +259,17 @@ _V_.Component.prototype.removeChild = function(component){
/**
* Initialize default child components from options
*/
_V_.Component.prototype.initChildren = function(){
vjs.Component.prototype.initChildren = function(){
var options = this.options;
if (options && options.children) {
var self = this;
// Loop through components and add them to the player
_V_.eachProp(options.children, function(name, opts){
vjs.eachProp(options.children, function(name, opts){
// Allow for disabling default components
// e.g. _V_.options.components.posterImage = false
// e.g. vjs.options.components.posterImage = false
if (opts === false) return;
// Allow waiting to add components until a specific event is called
@ -287,7 +287,7 @@ _V_.Component.prototype.initChildren = function(){
}
};
_V_.Component.prototype.buildCSSClass = function(){
vjs.Component.prototype.buildCSSClass = function(){
// Child classes can include a function that does:
// return "CLASS NAME" + this._super();
return "";
@ -300,10 +300,10 @@ _V_.Component.prototype.buildCSSClass = function(){
* Add an event listener to this component's element. Context will be the component.
* @param {String} type Event type e.g. 'click'
* @param {Function} fn Event listener
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.on = function(type, fn){
_V_.on(this.el_, type, _V_.bind(this, fn));
vjs.Component.prototype.on = function(type, fn){
vjs.on(this.el_, type, vjs.bind(this, fn));
return this;
};
@ -311,10 +311,10 @@ _V_.Component.prototype.on = function(type, fn){
* Remove an event listener from the component's element
* @param {String=} type Optional event type. Without type it will remove all listeners.
* @param {Function=} fn Optional event listener. Without fn it will remove all listeners for a type.
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.off = function(type, fn){
_V_.off(this.el_, type, fn);
vjs.Component.prototype.off = function(type, fn){
vjs.off(this.el_, type, fn);
return this;
};
@ -322,10 +322,10 @@ _V_.Component.prototype.off = function(type, fn){
* Add an event listener to be triggered only once and then removed
* @param {String} type Event type
* @param {Function} fn Event listener
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.one = function(type, fn) {
_V_.one(this.el_, type, _V_.bind(this, fn));
vjs.Component.prototype.one = function(type, fn) {
vjs.one(this.el_, type, vjs.bind(this, fn));
return this;
};
@ -333,10 +333,10 @@ _V_.Component.prototype.one = function(type, fn) {
* Trigger an event on an element
* @param {String} type Event type to trigger
* @param {Event|Object} event Event object to be passed to the listener
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.trigger = function(type, event){
_V_.trigger(this.el_, type, event);
vjs.Component.prototype.trigger = function(type, event){
vjs.trigger(this.el_, type, event);
return this;
};
@ -347,7 +347,7 @@ _V_.Component.prototype.trigger = function(type, event){
* @type {Boolean}
* @private
*/
_V_.Component.prototype.isReady_;
vjs.Component.prototype.isReady_;
/**
* Trigger ready as soon as initialization is finished.
@ -357,23 +357,23 @@ _V_.Component.prototype.isReady_;
* @type {Boolean}
* @private
*/
_V_.Component.prototype.isReadyOnInitFinish_ = true;
vjs.Component.prototype.isReadyOnInitFinish_ = true;
/**
* List of ready listeners
* @type {Array}
* @private
*/
_V_.Component.prototype.readyQueue_;
vjs.Component.prototype.readyQueue_;
/**
* Bind a listener to the component's ready state.
* Different from event listeners in that if the ready event has already happend
* it will trigger the function immediately.
* @param {Function} fn Ready listener
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.ready = function(fn){
vjs.Component.prototype.ready = function(fn){
if (fn) {
if (this.isReady_) {
fn.call(this);
@ -389,9 +389,9 @@ _V_.Component.prototype.ready = function(fn){
/**
* Trigger the ready listeners
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.triggerReady = function(){
vjs.Component.prototype.triggerReady = function(){
this.isReady_ = true;
var readyQueue = this.readyQueue_;
@ -416,46 +416,46 @@ _V_.Component.prototype.triggerReady = function(){
/**
* Add a CSS class name to the component's element
* @param {String} classToAdd Classname to add
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.addClass = function(classToAdd){
_V_.addClass(this.el_, classToAdd);
vjs.Component.prototype.addClass = function(classToAdd){
vjs.addClass(this.el_, classToAdd);
return this;
};
/**
* Remove a CSS class name from the component's element
* @param {String} classToRemove Classname to remove
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.removeClass = function(classToRemove){
_V_.removeClass(this.el_, classToRemove);
vjs.Component.prototype.removeClass = function(classToRemove){
vjs.removeClass(this.el_, classToRemove);
return this;
};
/**
* Show the component element if hidden
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.show = function(){
vjs.Component.prototype.show = function(){
this.el_.style.display = "block";
return this;
};
/**
* Hide the component element if hidden
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.hide = function(){
vjs.Component.prototype.hide = function(){
this.el_.style.display = "none";
return this;
};
/**
* Fade a component in using CSS
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.fadeIn = function(){
vjs.Component.prototype.fadeIn = function(){
this.removeClass("vjs-fade-out");
this.addClass("vjs-fade-in");
return this;
@ -463,9 +463,9 @@ _V_.Component.prototype.fadeIn = function(){
/**
* Fade a component out using CSS
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.fadeOut = function(){
vjs.Component.prototype.fadeOut = function(){
this.removeClass("vjs-fade-in");
this.addClass("vjs-fade-out");
return this;
@ -473,9 +473,9 @@ _V_.Component.prototype.fadeOut = function(){
/**
* Lock an item in its visible state. To be used with fadeIn/fadeOut.
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.lockShowing = function(){
vjs.Component.prototype.lockShowing = function(){
var style = this.el_.style;
style.display = "block";
style.opacity = 1;
@ -485,9 +485,9 @@ _V_.Component.prototype.lockShowing = function(){
/**
* Unlock an item to be hidden. To be used with fadeIn/fadeOut.
* @return {_V_.Component}
* @return {vjs.Component}
*/
_V_.Component.prototype.unlockShowing = function(){
vjs.Component.prototype.unlockShowing = function(){
var style = this.el.style;
style.display = "";
style.opacity = "";
@ -503,10 +503,10 @@ _V_.Component.prototype.unlockShowing = function(){
* But allowing limited percents use. e.g. width() will return number+%, not computed width
* @param {Number|String=} num Optional width number
* @param {[type]} skipListeners Skip the 'resize' event trigger
* @return {_V_.Component|Number|String} Returns 'this' if dimension was set.
* @return {vjs.Component|Number|String} Returns 'this' if dimension was set.
* Otherwise it returns the dimension.
*/
_V_.Component.prototype.width = function(num, skipListeners){
vjs.Component.prototype.width = function(num, skipListeners){
return this.dimension("width", num, skipListeners);
};
@ -514,9 +514,9 @@ _V_.Component.prototype.width = function(num, skipListeners){
* Get or set the height of the player
* @param {Number|String=} num Optional new player height
* @param {Boolean=} skipListeners Optional skip resize event trigger
* @return {_V_.Component|Number|String} The player, or the dimension
* @return {vjs.Component|Number|String} The player, or the dimension
*/
_V_.Component.prototype.height = function(num, skipListeners){
vjs.Component.prototype.height = function(num, skipListeners){
return this.dimension("height", num, skipListeners);
};
@ -524,9 +524,9 @@ _V_.Component.prototype.height = function(num, skipListeners){
* Set both width and height at the same time.
* @param {Number|String} width
* @param {Number|String} height
* @return {_V_.Component} The player.
* @return {vjs.Component} The player.
*/
_V_.Component.prototype.dimensions = function(width, height){
vjs.Component.prototype.dimensions = function(width, height){
// Skip resize listeners on width for optimization
return this.width(width, true).height(height);
};
@ -545,7 +545,7 @@ _V_.Component.prototype.dimensions = function(width, height){
* @return {vjs.Component|Number|String} Return the player if setting a dimension.
* Otherwise it returns the dimension.
*/
_V_.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
vjs.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
if (num !== undefined) {
// Check if using css width/height (% or px) and adjust
@ -578,13 +578,13 @@ _V_.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
// TODO: handle display:none and no dimension style using px
} else {
return parseInt(this.el_['offset'+_V_.capitalize(widthOrHeight)], 10);
return parseInt(this.el_['offset'+vjs.capitalize(widthOrHeight)], 10);
// ComputedStyle version.
// Only difference is if the element is hidden it will return
// the percent value (e.g. '100%'')
// instead of zero like offsetWidth returns.
// var val = _V_.getComputedStyleValue(this.el_, widthOrHeight);
// var val = vjs.getComputedStyleValue(this.el_, widthOrHeight);
// var pxIndex = val.indexOf("px");
// if (pxIndex !== -1) {
@ -597,11 +597,11 @@ _V_.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
// /* Utility
// ================================================================================ */
// _V_.Component.prototype.each = function(arr, fn){ _V_.each.call(this, arr, fn); };
// vjs.Component.prototype.each = function(arr, fn){ vjs.each.call(this, arr, fn); };
// _V_.Component.prototype.eachProp = function(obj, fn){ _V_.eachProp.call(this, obj, fn); };
// vjs.Component.prototype.eachProp = function(obj, fn){ vjs.eachProp.call(this, obj, fn); };
// _V_.Component.prototype.extend = function(obj){ _V_.merge(this, obj) };
// vjs.Component.prototype.extend = function(obj){ vjs.merge(this, obj) };
// // More easily attach 'this' to functions
// _V_.Component.prototype.proxy = function(fn, uid){ return _V_.proxy(this, fn, uid); };
// vjs.Component.prototype.proxy = function(fn, uid){ return vjs.proxy(this, fn, uid); };

680
src/controls.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,18 @@
// HTML5 Shiv. Must be in <head> to support older browsers.
document.createElement("video");document.createElement("audio");
goog.provide('_V_');
goog.provide('VideoJS');
goog.provide('vjs');
var VideoJS = function(id, options, ready){
/**
* Doubles as the main function for users to create a player instance and also
* the main library object.
*
* @param {String|Element} id Video element or video element ID
* @param {Object=} options Optional options object for config/settings
* @param {Function=} ready Optional ready callback
* @return {vjs.Player} A player instance
*/
vjs = function(id, options, ready){
var tag; // Element of ID
// Allow for element or ID to be passed in
@ -17,12 +25,12 @@ var VideoJS = function(id, options, ready){
}
// If a player instance has already been created for this ID return it.
if (_V_.players[id]) {
return _V_.players[id];
if (vjs.players[id]) {
return vjs.players[id];
// Otherwise get element for ID
} else {
tag = _V_.el(id)
tag = vjs.el(id)
}
// ID is a media element
@ -32,16 +40,17 @@ var VideoJS = function(id, options, ready){
// Check for a useable element
if (!tag || !tag.nodeName) { // re: nodeName, could be a box div also
throw new TypeError("The element or ID supplied is not valid. (VideoJS)"); // Returns
throw new TypeError("The element or ID supplied is not valid. (videojs)"); // Returns
}
// Element may have a player attr referring to an already created player instance.
// If not, set up a new player and return the instance.
return tag.player || new _V_.Player(tag, options, ready);
return tag.player || new vjs.Player(tag, options, ready);
};
// Shortcut
// VideoJS = _V_;
var videojs = vjs;
// videojs = vjs;
// CDN Version. Used to target right flash swf.
CDN_VERSION = "GENERATED_CDN_VSN";
@ -50,27 +59,29 @@ CDN_VERSION = "GENERATED_CDN_VSN";
* Global Player instance options
* @type {Object}
*/
_V_.options = {
// var vjs = videojs;
vjs.options = {
// Default order of fallback technology
techOrder: ["html5","flash"],
'techOrder': ["html5","flash"],
// techOrder: ["flash","html5"],
html5: {},
flash: { swf: "http://vjs.zencdn.net/c/video-js.swf" },
'html5': {},
'flash': { swf: "http://vjs.zencdn.net/c/video-js.swf" },
// Default of web browser is 300x150. Should rely on source width/height.
width: 300,
height: 150,
'width': 300,
'height': 150,
// defaultVolume: 0.85,
defaultVolume: 0.00, // The freakin seaguls are driving me crazy!
'defaultVolume': 0.00, // The freakin seaguls are driving me crazy!
// Included control sets
// TODO: just use uppercase Class name
children: {
'children': {
"mediaLoader": {},
"posterImage": {},
// // "textTrackDisplay": {},
// "textTrackDisplay": {},
"loadingSpinner": {},
"bigPlayButton": {},
"controlBar": {}
@ -81,10 +92,10 @@ _V_.options = {
* Global player list
* @type {Object}
*/
_V_.players = {};
vjs.players = {};
// Set CDN Version of swf
if (CDN_VERSION != "GENERATED_CDN_VSN") {
_V_.options.flash.swf = "http://vjs.zencdn.net/"+CDN_VERSION+"/video-js.swf"
vjs.options.Flash.swf = "http://vjs.zencdn.net/"+CDN_VERSION+"/video-js.swf"
}

View File

@ -13,15 +13,15 @@
* @param {String} type Type of event to bind to.
* @param {Function} fn Event listener.
*/
_V_.on = function(elem, type, fn){
var data = _V_.getData(elem);
vjs.on = function(elem, type, fn){
var data = vjs.getData(elem);
// We need a place to store all our handler data
if (!data.handlers) data.handlers = {};
if (!data.handlers[type]) data.handlers[type] = [];
if (!fn.guid) fn.guid = _V_.guid++;
if (!fn.guid) fn.guid = vjs.guid++;
data.handlers[type].push(fn);
@ -31,7 +31,7 @@ _V_.on = function(elem, type, fn){
data.dispatcher = function (event){
if (data.disabled) return;
event = _V_.fixEvent(event);
event = vjs.fixEvent(event);
var handlers = data.handlers[event.type];
@ -67,11 +67,11 @@ _V_.on = function(elem, type, fn){
* @param {String=} type Type of listener to remove. Don't include to remove all events from element.
* @param {Function} fn Specific listener to remove. Don't incldue to remove listeners for an event type.
*/
_V_.off = function(elem, type, fn) {
vjs.off = function(elem, type, fn) {
// Don't want to add a cache object through getData if not needed
if (!_V_.hasData(elem)) return;
if (!vjs.hasData(elem)) return;
var data = _V_.getData(elem);
var data = vjs.getData(elem);
// If no events exist, nothing to unbind
if (!data.handlers) { return; }
@ -79,7 +79,7 @@ _V_.off = function(elem, type, fn) {
// Utility function
var removeType = function(t){
data.handlers[t] = [];
_V_.cleanUpEvents(elem,t);
vjs.cleanUpEvents(elem,t);
};
// Are we removing all bound events?
@ -108,7 +108,7 @@ _V_.off = function(elem, type, fn) {
}
}
_V_.cleanUpEvents(elem, type);
vjs.cleanUpEvents(elem, type);
};
/**
@ -116,8 +116,8 @@ _V_.off = function(elem, type, fn) {
* @param {Element|Object} elem Element to clean up
* @param {String} type Type of event to clean up
*/
_V_.cleanUpEvents = function(elem, type) {
var data = _V_.getData(elem);
vjs.cleanUpEvents = function(elem, type) {
var data = vjs.getData(elem);
// Remove the events of a particular type if there are none left
if (data.handlers[type].length === 0) {
@ -134,7 +134,7 @@ _V_.cleanUpEvents = function(elem, type) {
}
// Remove the events object if there are no types left
if (_V_.isEmpty(data.handlers)) {
if (vjs.isEmpty(data.handlers)) {
delete data.handlers;
delete data.dispatcher;
delete data.disabled;
@ -145,8 +145,8 @@ _V_.cleanUpEvents = function(elem, type) {
}
// Finally remove the expando if there is no data left
if (_V_.isEmpty(data)) {
_V_.removeData(elem);
if (vjs.isEmpty(data)) {
vjs.removeData(elem);
}
};
@ -155,7 +155,7 @@ _V_.cleanUpEvents = function(elem, type) {
* @param {Object} event Event object to fix
* @return {Object}
*/
_V_.fixEvent = function(event) {
vjs.fixEvent = function(event) {
function returnTrue() { return true; }
function returnFalse() { return false; }
@ -240,11 +240,11 @@ _V_.fixEvent = function(event) {
* @param {Element|Object} elem Element to trigger an event on
* @param {String} event Type of event to trigger
*/
_V_.trigger = function(elem, event) {
vjs.trigger = function(elem, event) {
// Fetches element data and a reference to the parent (for bubbling).
// Don't want to add a data object to cache for every parent,
// so checking hasData first.
var elemData = (_V_.hasData(elem)) ? _V_.getData(elem) : {};
var elemData = (vjs.hasData(elem)) ? vjs.getData(elem) : {};
var parent = elem.parentNode || elem.ownerDocument;
// type = event.type || event,
// handler;
@ -254,7 +254,7 @@ _V_.trigger = function(elem, event) {
event = { type:event, target:elem };
}
// Normalizes the event properties.
event = _V_.fixEvent(event);
event = vjs.fixEvent(event);
// If the passed element has a dispatcher, executes the established handlers.
if (elemData.dispatcher) {
@ -263,11 +263,11 @@ _V_.trigger = function(elem, event) {
// Unless explicitly stopped, recursively calls this function to bubble the event up the DOM.
if (parent && !event.isPropagationStopped()) {
_V_.trigger(parent, event);
vjs.trigger(parent, event);
// If at the top of the DOM, triggers the default action unless disabled.
} else if (!parent && !event.isDefaultPrevented()) {
var targetData = _V_.getData(event.target);
var targetData = vjs.getData(event.target);
// Checks if the target has a default action for this event.
if (event.target[event.type]) {
@ -287,10 +287,10 @@ _V_.trigger = function(elem, event) {
*/
// // Added in attion to book. Book code was broke.
// event = typeof event === "object" ?
// event[_V_.expando] ?
// event[vjs.expando] ?
// event :
// new _V_.Event(type, event) :
// new _V_.Event(type);
// new vjs.Event(type, event) :
// new vjs.Event(type);
// event.type = type;
// if (handler) {
@ -309,9 +309,9 @@ _V_.trigger = function(elem, event) {
* @param {Function} fn [description]
* @return {[type]}
*/
_V_.one = function(elem, type, fn) {
_V_.on(elem, type, function(){
_V_.off(elem, type, arguments.callee)
vjs.one = function(elem, type, fn) {
vjs.on(elem, type, function(){
vjs.off(elem, type, arguments.callee)
fn.apply(this, arguments);
});
}

View File

@ -1,79 +1,117 @@
goog.require('_V_');
goog.require('_V_.Component');
goog.require('_V_.Player');
/**
* @fileoverview Exports for Video.js.
* Exports are publically available variables.
* All other variables (including function names) will probably
* be renamed by closure compiler.
*/
goog.exportSymbol('VideoJS', VideoJS);
/**
* vjs (internal only) = videojs = _V_ (external only)
*
* vjs is the same as the goog var in Closure Library. It holds all variables
* used in Video.js development. Closure compiler will rename all variables,
* including class prototype functions, except those specifcally
* exported (eports.js). Don't assume any function you can use in Video.js
* development will be available on window.videojs for use with other js.
*
* For example, vjs.trim is an internal function and will be renamed by compiler
* to something like 'a.b', or actually more likely 'a' removing it from
* a parent object.
*
* videojs is a var that helps bridge bewteen internal and external development.
* Avoid using it over vjs when developing the Video.js core.
*
* _V_ is only external. It's just cute and short(er). Like jQuery === $.
* Also because it's nice having a different var for internal (vjs) vs.
* external (_V_) because it makes it clearer what context we're in.
*/
goog.exportSymbol('videojs', vjs);
goog.exportSymbol('_V_', vjs);
goog.exportSymbol('_V_.Component', _V_.Component);
goog.exportProperty(_V_.Component.prototype, "dispose", _V_.Component.prototype.dispose);
goog.exportProperty(_V_.Component.prototype, "createEl", _V_.Component.prototype.createEl);
goog.exportProperty(_V_.Component.prototype, "getEl", _V_.Component.prototype.getEl);
goog.exportProperty(_V_.Component.prototype, "addChild", _V_.Component.prototype.addChild);
goog.exportProperty(_V_.Component.prototype, "getChildren", _V_.Component.prototype.getChildren);
goog.exportProperty(_V_.Component.prototype, "on", _V_.Component.prototype.on);
goog.exportProperty(_V_.Component.prototype, "off", _V_.Component.prototype.off);
goog.exportProperty(_V_.Component.prototype, "one", _V_.Component.prototype.one);
goog.exportProperty(_V_.Component.prototype, "trigger", _V_.Component.prototype.trigger);
goog.exportProperty(_V_.Component.prototype, "show", _V_.Component.prototype.show);
goog.exportProperty(_V_.Component.prototype, "hide", _V_.Component.prototype.hide);
goog.exportProperty(_V_.Component.prototype, "width", _V_.Component.prototype.width);
goog.exportProperty(_V_.Component.prototype, "height", _V_.Component.prototype.height);
goog.exportProperty(_V_.Component.prototype, "dimensions", _V_.Component.prototype.dimensions);
goog.exportSymbol('videojs.options', vjs.options);
goog.exportSymbol('_V_.Player', _V_.Player);
// Allow external components to use global cache
goog.exportSymbol('videojs.cache', vjs.cache);
goog.exportSymbol('_V_.MediaLoader', _V_.MediaLoader);
goog.exportSymbol('_V_.PosterImage', _V_.PosterImage);
goog.exportSymbol('_V_.LoadingSpinner', _V_.LoadingSpinner);
goog.exportSymbol('_V_.BigPlayButton', _V_.BigPlayButton);
goog.exportSymbol('_V_.ControlBar', _V_.ControlBar);
goog.exportSymbol('_V_.TextTrackDisplay', _V_.TextTrackDisplay);
goog.exportSymbol('videojs.Component', vjs.Component);
goog.exportProperty(vjs.Component.prototype, "dispose", vjs.Component.prototype.dispose);
goog.exportProperty(vjs.Component.prototype, "createEl", vjs.Component.prototype.createEl);
goog.exportProperty(vjs.Component.prototype, "getEl", vjs.Component.prototype.getEl);
goog.exportProperty(vjs.Component.prototype, "addChild", vjs.Component.prototype.addChild);
goog.exportProperty(vjs.Component.prototype, "getChildren", vjs.Component.prototype.getChildren);
goog.exportProperty(vjs.Component.prototype, "on", vjs.Component.prototype.on);
goog.exportProperty(vjs.Component.prototype, "off", vjs.Component.prototype.off);
goog.exportProperty(vjs.Component.prototype, "one", vjs.Component.prototype.one);
goog.exportProperty(vjs.Component.prototype, "trigger", vjs.Component.prototype.trigger);
goog.exportProperty(vjs.Component.prototype, "show", vjs.Component.prototype.show);
goog.exportProperty(vjs.Component.prototype, "hide", vjs.Component.prototype.hide);
goog.exportProperty(vjs.Component.prototype, "width", vjs.Component.prototype.width);
goog.exportProperty(vjs.Component.prototype, "height", vjs.Component.prototype.height);
goog.exportProperty(vjs.Component.prototype, "dimensions", vjs.Component.prototype.dimensions);
goog.exportSymbol('_V_.Control', _V_.Control);
goog.exportSymbol('_V_.ControlBar', _V_.ControlBar);
goog.exportSymbol('_V_.Button', _V_.Button);
goog.exportSymbol('_V_.PlayButton', _V_.PlayButton);
goog.exportSymbol('_V_.PauseButton', _V_.PauseButton);
goog.exportSymbol('_V_.PlayToggle', _V_.PlayToggle);
goog.exportSymbol('_V_.FullscreenToggle', _V_.FullscreenToggle);
goog.exportSymbol('_V_.BigPlayButton', _V_.BigPlayButton);
goog.exportSymbol('_V_.LoadingSpinner', _V_.LoadingSpinner);
goog.exportSymbol('_V_.CurrentTimeDisplay', _V_.CurrentTimeDisplay);
goog.exportSymbol('_V_.DurationDisplay', _V_.DurationDisplay);
goog.exportSymbol('_V_.TimeDivider', _V_.TimeDivider);
goog.exportSymbol('_V_.RemainingTimeDisplay', _V_.RemainingTimeDisplay);
goog.exportSymbol('_V_.Slider', _V_.Slider);
goog.exportSymbol('_V_.ProgressControl', _V_.ProgressControl);
goog.exportSymbol('_V_.SeekBar', _V_.SeekBar);
goog.exportSymbol('_V_.LoadProgressBar', _V_.LoadProgressBar);
goog.exportSymbol('_V_.PlayProgressBar', _V_.PlayProgressBar);
goog.exportSymbol('_V_.SeekHandle', _V_.SeekHandle);
goog.exportSymbol('_V_.VolumeControl', _V_.VolumeControl);
goog.exportSymbol('_V_.VolumeBar', _V_.VolumeBar);
goog.exportSymbol('_V_.VolumeLevel', _V_.VolumeLevel);
goog.exportSymbol('_V_.VolumeHandle', _V_.VolumeHandle);
goog.exportSymbol('_V_.MuteToggle', _V_.MuteToggle);
goog.exportSymbol('_V_.PosterImage', _V_.PosterImage);
goog.exportSymbol('_V_.Menu', _V_.Menu);
goog.exportSymbol('_V_.MenuItem', _V_.MenuItem);
goog.exportSymbol('videojs.Player', vjs.Player);
goog.exportSymbol('_V_.MediaTechController', _V_.MediaTechController);
goog.exportSymbol('videojs.MediaLoader', vjs.MediaLoader);
goog.exportSymbol('videojs.PosterImage', vjs.PosterImage);
goog.exportSymbol('videojs.LoadingSpinner', vjs.LoadingSpinner);
goog.exportSymbol('videojs.BigPlayButton', vjs.BigPlayButton);
goog.exportSymbol('videojs.ControlBar', vjs.ControlBar);
goog.exportSymbol('videojs.TextTrackDisplay', vjs.TextTrackDisplay);
goog.exportSymbol('_V_.Html5', _V_.Html5);
goog.exportProperty(_V_.Html5, "Supports", _V_.Html5.Supports);
goog.exportProperty(_V_.Html5, "Events", _V_.Html5.Events);
goog.exportProperty(_V_.Html5, "isSupported", _V_.Html5.isSupported);
goog.exportProperty(_V_.Html5, "canPlaySource", _V_.Html5.canPlaySource);
goog.exportSymbol('videojs.Control', vjs.Control);
goog.exportSymbol('videojs.ControlBar', vjs.ControlBar);
goog.exportSymbol('videojs.Button', vjs.Button);
goog.exportSymbol('videojs.PlayButton', vjs.PlayButton);
goog.exportSymbol('videojs.PauseButton', vjs.PauseButton);
goog.exportSymbol('videojs.PlayToggle', vjs.PlayToggle);
goog.exportSymbol('videojs.FullscreenToggle', vjs.FullscreenToggle);
goog.exportSymbol('videojs.BigPlayButton', vjs.BigPlayButton);
goog.exportSymbol('videojs.LoadingSpinner', vjs.LoadingSpinner);
goog.exportSymbol('videojs.CurrentTimeDisplay', vjs.CurrentTimeDisplay);
goog.exportSymbol('videojs.DurationDisplay', vjs.DurationDisplay);
goog.exportSymbol('videojs.TimeDivider', vjs.TimeDivider);
goog.exportSymbol('videojs.RemainingTimeDisplay', vjs.RemainingTimeDisplay);
goog.exportSymbol('videojs.Slider', vjs.Slider);
goog.exportSymbol('videojs.ProgressControl', vjs.ProgressControl);
goog.exportSymbol('videojs.SeekBar', vjs.SeekBar);
goog.exportSymbol('videojs.LoadProgressBar', vjs.LoadProgressBar);
goog.exportSymbol('videojs.PlayProgressBar', vjs.PlayProgressBar);
goog.exportSymbol('videojs.SeekHandle', vjs.SeekHandle);
goog.exportSymbol('videojs.VolumeControl', vjs.VolumeControl);
goog.exportSymbol('videojs.VolumeBar', vjs.VolumeBar);
goog.exportSymbol('videojs.VolumeLevel', vjs.VolumeLevel);
goog.exportSymbol('videojs.VolumeHandle', vjs.VolumeHandle);
goog.exportSymbol('videojs.MuteToggle', vjs.MuteToggle);
goog.exportSymbol('videojs.PosterImage', vjs.PosterImage);
goog.exportSymbol('videojs.Menu', vjs.Menu);
goog.exportSymbol('videojs.MenuItem', vjs.MenuItem);
goog.exportSymbol('videojs.SubtitlesButton', vjs.SubtitlesButton);
goog.exportSymbol('videojs.CaptionsButton', vjs.CaptionsButton);
goog.exportSymbol('videojs.ChaptersButton', vjs.ChaptersButton);
goog.exportSymbol('videojs.MediaTechController', vjs.MediaTechController);
goog.exportSymbol('videojs.Html5', vjs.Html5);
goog.exportProperty(vjs.Html5, "Events", vjs.Html5.Events);
goog.exportProperty(vjs.Html5, "isSupported", vjs.Html5.isSupported);
goog.exportProperty(vjs.Html5, "canPlaySource", vjs.Html5.canPlaySource);
// Export non-standard HTML5 video API methods.
// Standard method names already protected by default externs.
goog.exportProperty(_V_.Html5.prototype, "setCurrentTime", _V_.Html5.prototype.setCurrentTime);
goog.exportProperty(_V_.Html5.prototype, "setVolume", _V_.Html5.prototype.setVolume);
goog.exportProperty(_V_.Html5.prototype, "setMuted", _V_.Html5.prototype.setMuted);
goog.exportProperty(_V_.Html5.prototype, "setPreload", _V_.Html5.prototype.setPreload);
goog.exportProperty(_V_.Html5.prototype, "setAutoplay", _V_.Html5.prototype.setAutoplay);
goog.exportProperty(_V_.Html5.prototype, "setLoop", _V_.Html5.prototype.setLoop);
goog.exportProperty(vjs.Html5.prototype, "setCurrentTime", vjs.Html5.prototype.setCurrentTime);
goog.exportProperty(vjs.Html5.prototype, "setVolume", vjs.Html5.prototype.setVolume);
goog.exportProperty(vjs.Html5.prototype, "setMuted", vjs.Html5.prototype.setMuted);
goog.exportProperty(vjs.Html5.prototype, "setPreload", vjs.Html5.prototype.setPreload);
goog.exportProperty(vjs.Html5.prototype, "setAutoplay", vjs.Html5.prototype.setAutoplay);
goog.exportProperty(vjs.Html5.prototype, "setLoop", vjs.Html5.prototype.setLoop);
goog.exportSymbol('videojs.Flash', vjs.Flash);
goog.exportProperty(vjs.Flash, "Events", vjs.Flash.Events);
goog.exportProperty(vjs.Flash, "isSupported", vjs.Flash.isSupported);
goog.exportProperty(vjs.Flash, "canPlaySource", vjs.Flash.canPlaySource);
goog.exportProperty(vjs.Flash, "onReady", vjs.Flash['onReady']);
// Allow external components to use global cache
goog.exportSymbol('_V_.cache', _V_.cache);
goog.exportSymbol('videojs.CaptionsTrack', vjs.CaptionsTrack);
goog.exportSymbol('videojs.SubtitlesTrack', vjs.SubtitlesTrack);
goog.exportSymbol('videojs.ChaptersTrack', vjs.ChaptersTrack);

View File

@ -2,53 +2,58 @@
// (Parse Method Only)
// https://github.com/douglascrockford/JSON-js/blob/master/json2.js
var JSON;
if (!JSON) { JSON = {}; }
/**
* JSON shim. Only using for parse method when parsing data-setup attribute JSON.
*/
vjs.JSON;
if (JSON && JSON.parse === 'function') {
vjs.JSON = JSON;
} else {
vjs.JSON = {};
(function(){
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
var j;
vjs.JSON.parse = function (text, reviver) {
var j;
function walk(holder, key) {
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
function walk(holder, key) {
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
return reviver.call(holder, key, value);
}
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
return reviver.call(holder, key, value);
}
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
j = eval('(' + text + ')');
j = eval('(' + text + ')');
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
throw new SyntaxError('JSON.parse');
};
}
}());
throw new SyntaxError('JSON.parse');
};
}

View File

@ -4,7 +4,7 @@
* @param {Object=} properties Element properties to be applied.
* @return {Element}
*/
_V_.createEl = function(tagName, properties){
vjs.createEl = function(tagName, properties){
var el = document.createElement(tagName || 'div');
for (var propName in properties){
@ -27,7 +27,7 @@ _V_.createEl = function(tagName, properties){
* @param {String} string String to be uppercased
* @return {String}
*/
_V_.capitalize = function(string){
vjs.capitalize = function(string){
return string.charAt(0).toUpperCase() + string.slice(1);
};
@ -38,7 +38,7 @@ _V_.capitalize = function(string){
* @param {Function} fn Function to be called on each property.
* @this {*}
*/
_V_.eachProp = function(obj, fn){
vjs.eachProp = function(obj, fn){
if (!obj) { return; }
for (var name in obj) {
if (obj.hasOwnProperty(name)) {
@ -54,7 +54,7 @@ _V_.eachProp = function(obj, fn){
* @param {[type]} safe [description]
* @return {[type]}
*/
_V_.merge = function(obj1, obj2, safe){
vjs.merge = function(obj1, obj2, safe){
// Make sure second object exists
if (!obj2) { return obj1; }
@ -63,7 +63,7 @@ _V_.merge = function(obj1, obj2, safe){
}
return obj1;
};
// _V_.extend = function(obj){ this.merge(this, obj, true); };
// vjs.extend = function(obj){ this.merge(this, obj, true); };
/**
* Bind (a.k.a proxy or Context). A simple method for changing the context of a function
@ -73,9 +73,9 @@ _V_.merge = function(obj1, obj2, safe){
* @param {Number=} uid An optional unique ID for the function to be set
* @return {Function}
*/
_V_.bind = function(context, fn, uid) {
vjs.bind = function(context, fn, uid) {
// Make sure the function has a unique ID
if (!fn.guid) { fn.guid = _V_.guid++; }
if (!fn.guid) { fn.guid = vjs.guid++; }
// Create the new function that changes the context
var ret = function() {
@ -107,7 +107,7 @@ _V_.bind = function(context, fn, uid) {
* @return {!Function} A partially-applied form of the function bind() was
* invoked as a method of.
*/
_V_.partial = function(fn, var_args) {
vjs.partial = function(fn, var_args) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
// Prepend the bound arguments to the current arguments.
@ -123,33 +123,33 @@ _V_.partial = function(fn, var_args) {
* (also from jsninja.com, slightly modified and updated for closure compiler)
* @type {Object}
*/
_V_.cache = {};
vjs.cache = {};
/**
* Unique ID for an element or function
* @type {Number}
*/
_V_.guid = 1;
vjs.guid = 1;
/**
* Unique attribute name to store an element's guid in
* @type {String}
* @constant
*/
_V_.expando = "vdata" + (new Date).getTime();
vjs.expando = "vdata" + (new Date).getTime();
/**
* Returns the cache object where data for an element is stored
* @param {Element} el Element to store data for.
* @return {Object}
*/
_V_.getData = function(el){
var id = el[_V_.expando];
vjs.getData = function(el){
var id = el[vjs.expando];
if (!id) {
id = el[_V_.expando] = _V_.guid++;
_V_.cache[id] = {};
id = el[vjs.expando] = vjs.guid++;
vjs.cache[id] = {};
}
return _V_.cache[id];
return vjs.cache[id];
};
/**
@ -157,38 +157,38 @@ _V_.getData = function(el){
* @param {Element} el Element to store data for.
* @return {Object}
*/
_V_.hasData = function(el){
var id = el[_V_.expando];
return !(!id || _V_.isEmpty(_V_.cache[id]));
vjs.hasData = function(el){
var id = el[vjs.expando];
return !(!id || vjs.isEmpty(vjs.cache[id]));
};
/**
* Delete data for the element from the cache and the guid attr from getElementById
* @param {Element} el Remove data for an element
*/
_V_.removeData = function(el){
var id = el[_V_.expando];
vjs.removeData = function(el){
var id = el[vjs.expando];
if (!id) { return; }
// Remove all stored data
// Changed to = null
// http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
// _V_.cache[id] = null;
delete _V_.cache[id];
// vjs.cache[id] = null;
delete vjs.cache[id];
// Remove the expando property from the DOM node
try {
delete el[_V_.expando];
delete el[vjs.expando];
} catch(e) {
if (el.removeAttribute) {
el.removeAttribute(_V_.expando);
el.removeAttribute(vjs.expando);
} else {
// IE doesn't appear to support removeAttribute on the document element
el[_V_.expando] = null;
el[vjs.expando] = null;
}
}
};
_V_.isEmpty = function(obj) {
vjs.isEmpty = function(obj) {
for (var prop in obj) {
// Inlude null properties as empty.
if (obj[prop] !== null) {
@ -203,7 +203,7 @@ _V_.isEmpty = function(obj) {
* @param {Element} element Element to add class name to
* @param {String} classToAdd Classname to add
*/
_V_.addClass = function(element, classToAdd){
vjs.addClass = function(element, classToAdd){
if ((" "+element.className+" ").indexOf(" "+classToAdd+" ") == -1) {
element.className = element.className === "" ? classToAdd : element.className + " " + classToAdd;
}
@ -214,7 +214,7 @@ _V_.addClass = function(element, classToAdd){
* @param {Element} element Element to remove from class name
* @param {String} classToAdd Classname to remove
*/
_V_.removeClass = function(element, classToRemove){
vjs.removeClass = function(element, classToRemove){
if (element.className.indexOf(classToRemove) == -1) { return; }
var classNames = element.className.split(" ");
classNames.splice(classNames.indexOf(classToRemove),1);
@ -226,32 +226,32 @@ _V_.removeClass = function(element, classToRemove){
* @type {Element}
* @constant
*/
_V_.TEST_VID = document.createElement("video");
vjs.TEST_VID = document.createElement("video");
/**
* Useragent for browser testing.
* @type {String}
* @constant
*/
_V_.UA = navigator.userAgent;
vjs.USER_AGENT = navigator.userAgent;
/**
* Device is an iPhone
* @type {Boolean}
* @constant
*/
_V_.IS_IPHONE = !!navigator.userAgent.match(/iPad/i);
_V_.IS_IPAD = !!navigator.userAgent.match(/iPhone/i);
_V_.IS_IPOD = !!navigator.userAgent.match(/iPod/i);
_V_.IS_IOS = _V_.IS_IPHONE || _V_.IS_IPAD || _V_.IS_IPOD;
vjs.IS_IPHONE = !!navigator.userAgent.match(/iPad/i);
vjs.IS_IPAD = !!navigator.userAgent.match(/iPhone/i);
vjs.IS_IPOD = !!navigator.userAgent.match(/iPod/i);
vjs.IS_IOS = vjs.IS_IPHONE || vjs.IS_IPAD || vjs.IS_IPOD;
_V_.IOS_VERSION = (function(){
vjs.IOS_VERSION = (function(){
var match = navigator.userAgent.match(/OS (\d+)_/i);
if (match && match[1]) { return match[1]; }
})();
_V_.IS_ANDROID = !!navigator.userAgent.match(/Android.*AppleWebKit/i);
_V_.ANDROID_VERSION = (function() {
vjs.IS_ANDROID = !!navigator.userAgent.match(/Android.*AppleWebKit/i);
vjs.ANDROID_VERSION = (function() {
var match = navigator.userAgent.match(/Android (\d+)\./i);
if (match && match[1]) {
return match[1];
@ -259,6 +259,13 @@ _V_.ANDROID_VERSION = (function() {
return null;
})();
// http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
// IE9+ returns false
vjs.IS_IE6to8 = function(){ return !+"\v1"; };
vjs.IS_FIREFOX = function(){ return !!vjs.USER_AGENT.match("Firefox") };
/**
* Get an element's attribute values, as defined on the HTML tag
* Attributs are not the same as properties. They're defined on the tag
@ -267,7 +274,7 @@ _V_.ANDROID_VERSION = (function() {
* @param {Element} tag Element from which to get tag attributes
* @return {Object}
*/
_V_.getAttributeValues = function(tag){
vjs.getAttributeValues = function(tag){
var obj = {};
// Known boolean attributes
@ -307,7 +314,7 @@ _V_.getAttributeValues = function(tag){
* @param {String} strCssRule Style name
* @return {String} Style value
*/
_V_.getComputedStyleValue = function(el, strCssRule){
vjs.getComputedStyleValue = function(el, strCssRule){
var strValue = "";
if(document.defaultView && document.defaultView.getComputedStyle){
strValue = document.defaultView.getComputedStyle(el, "").getPropertyValue(strCssRule);
@ -326,7 +333,7 @@ _V_.getComputedStyleValue = function(el, strCssRule){
* @param {Element} child Element to insert
* @param {[type]} parent Element to insert child into
*/
_V_.insertFirst = function(child, parent){
vjs.insertFirst = function(child, parent){
if (parent.firstChild) {
parent.insertBefore(child, parent.firstChild);
} else {
@ -338,7 +345,7 @@ _V_.insertFirst = function(child, parent){
* Object to hold browser support information
* @type {Object}
*/
_V_.support = {};
vjs.support = {};
/**
* Shorthand for document.getElementById()
@ -346,7 +353,7 @@ _V_.support = {};
* @param {String} id Element ID
* @return {Element} Element with supplied ID
*/
_V_.el = function(id){
vjs.el = function(id){
if (id.indexOf("#") === 0) {
id = id.slice(1);
}
@ -362,7 +369,7 @@ _V_.el = function(id){
* @param {Number} guide Number (in seconds) to model the string after
* @return {String} Time formatted as H:MM:SS or M:SS
*/
_V_.formatTime = function(seconds, guide) {
vjs.formatTime = function(seconds, guide) {
guide = guide || seconds; // Default to using seconds as guide
var s = Math.floor(seconds % 60),
m = Math.floor(seconds / 60 % 60),
@ -384,19 +391,19 @@ _V_.formatTime = function(seconds, guide) {
};
// Attempt to block the ability to select text while dragging controls
_V_.blockTextSelection = function(){
vjs.blockTextSelection = function(){
document.body.focus();
document.onselectstart = function () { return false; };
};
// Turn off text selection blocking
_V_.unblockTextSelection = function(){ document.onselectstart = function () { return true; }; };
vjs.unblockTextSelection = function(){ document.onselectstart = function () { return true; }; };
/**
* Trim whitespace from the ends of a string.
* @param {String} string String to trim
* @return {String} Trimmed string
*/
_V_.trim = function(string){
vjs.trim = function(string){
return string.toString().replace(/^\s+/, "").replace(/\s+$/, "");
};
@ -406,7 +413,7 @@ _V_.trim = function(string){
* @param {Number} dec Number of decimal places to round to
* @return {Number} Rounded number
*/
_V_.round = function(num, dec) {
vjs.round = function(num, dec) {
if (!dec) { dec = 0; }
return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
};
@ -420,7 +427,7 @@ _V_.round = function(num, dec) {
* @param {Number} end End time in seconds
* @return {Object} Fake TimeRange object
*/
_V_.createTimeRange = function(start, end){
vjs.createTimeRange = function(start, end){
return {
length: 1,
start: function() { return start; },
@ -428,10 +435,7 @@ _V_.createTimeRange = function(start, end){
};
};
// _V_.extend({
// // Device Checks
// isIE: function(){ return !+"\v1"; },
// isFF: function(){ return !!_V_.ua.match("Firefox") },
// vjs.extend({
// each: function(arr, fn){
// if (!arr || arr.length === 0) { return; }
@ -442,7 +446,7 @@ _V_.createTimeRange = function(start, end){
// // Return the relative horizonal position of an event as a value from 0-1
// getRelativePosition: function(x, relativeElement){
// return Math.max(0, Math.min(1, (x - _V_.findPosX(relativeElement)) / relativeElement.offsetWidth));
// return Math.max(0, Math.min(1, (x - vjs.findPosX(relativeElement)) / relativeElement.offsetWidth));
// },
// get: function(url, onSuccess, onError){
@ -466,12 +470,12 @@ _V_.createTimeRange = function(start, end){
// try {
// request.open("GET", url);
// } catch(e) {
// _V_.log("VideoJS XMLHttpRequest (open)", e);
// vjs.log("VideoJS XMLHttpRequest (open)", e);
// // onError(e);
// return false;
// }
// request.onreadystatechange = _V_.proxy(this, function() {
// request.onreadystatechange = vjs.proxy(this, function() {
// if (request.readyState == 4) {
// if (request.status == 200 || local && request.status == 0) {
// onSuccess(request.responseText);
@ -486,7 +490,7 @@ _V_.createTimeRange = function(start, end){
// try {
// request.send();
// } catch(e) {
// _V_.log("VideoJS XMLHttpRequest (send)", e);
// vjs.log("VideoJS XMLHttpRequest (send)", e);
// if (onError) {
// onError(e);
// }
@ -495,7 +499,7 @@ _V_.createTimeRange = function(start, end){
/* Local Storage
================================================================================ */
_V_.setLocalStorage = function(key, value){
vjs.setLocalStorage = function(key, value){
// IE was throwing errors referencing the var anywhere without this
var localStorage = window.localStorage || false;
if (!localStorage) { return; }
@ -503,9 +507,9 @@ _V_.setLocalStorage = function(key, value){
localStorage[key] = value;
} catch(e) {
if (e.code == 22 || e.code == 1014) { // Webkit == 22 / Firefox == 1014
_V_.log("LocalStorage Full (VideoJS)", e);
vjs.log("LocalStorage Full (VideoJS)", e);
} else {
_V_.log("LocalStorage Error (VideoJS)", e);
vjs.log("LocalStorage Error (VideoJS)", e);
}
}
};
@ -516,12 +520,12 @@ _V_.setLocalStorage = function(key, value){
* @param {String} url URL to make absolute
* @return {String} Absolute URL
*/
_V_.getAbsoluteURL = function(url){
vjs.getAbsoluteURL = function(url){
// Check if absolute URL
if (!url.match(/^https?:\/\//)) {
// Convert to absolute URL. Flash hosted off-site needs an absolute URL.
url = _V_.createEl('div', {
url = vjs.createEl('div', {
innerHTML: '<a href="'+url+'">x</a>'
}).firstChild.href;
}
@ -529,17 +533,15 @@ _V_.getAbsoluteURL = function(url){
return url;
};
// });
// usage: log('inside coolFunc', this, arguments);
// paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
_V_.log = function(){
_V_.log.history = _V_.log.history || [];// store logs to an array for reference
_V_.log.history.push(arguments);
vjs.log = function(){
vjs.log.history = vjs.log.history || [];// store logs to an array for reference
vjs.log.history.push(arguments);
if(window.console) {
arguments.callee = arguments.callee.caller;
var newarr = [].slice.call(arguments);
(typeof console.log === 'object' ? _V_.log.apply.call(console.log, console, newarr) : console.log.apply(console, newarr));
(typeof console.log === 'object' ? vjs.log.apply.call(console.log, console, newarr) : console.log.apply(console, newarr));
}
};
@ -550,7 +552,7 @@ _V_.log = function(){
// Offset Left
// getBoundingClientRect technique from John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/
if ("getBoundingClientRect" in document.documentElement) {
_V_.findPosX = function(el) {
vjs.findPosX = function(el) {
var box;
try {
@ -568,14 +570,14 @@ if ("getBoundingClientRect" in document.documentElement) {
return left;
};
} else {
_V_.findPosX = function(el) {
vjs.findPosX = function(el) {
var curleft = el.offsetLeft;
// _V_.log(obj.className, obj.offsetLeft)
// vjs.log(obj.className, obj.offsetLeft)
while(el = obj.offsetParent) {
if (el.className.indexOf("video-js") == -1) {
// _V_.log(el.offsetParent, "OFFSETLEFT", el.offsetLeft)
// _V_.log("-webkit-full-screen", el.webkitMatchesSelector("-webkit-full-screen"));
// _V_.log("-webkit-full-screen", el.querySelectorAll(".video-js:-webkit-full-screen"));
// vjs.log(el.offsetParent, "OFFSETLEFT", el.offsetLeft)
// vjs.log("-webkit-full-screen", el.webkitMatchesSelector("-webkit-full-screen"));
// vjs.log("-webkit-full-screen", el.querySelectorAll(".video-js:-webkit-full-screen"));
} else {
}
curleft += el.offsetLeft;

View File

@ -0,0 +1,27 @@
/**
* @fileoverview Externs for video-js.swf. Externs are functions
* that the compiler shouldn't obfuscate.
*/
/**
* @param {string} name
*/
HTMLObjectElement.prototype.vjs_getProperty = function(name) {};
/**
* @param {string} name
* @param {string|number} value
*/
HTMLObjectElement.prototype.vjs_setProperty = function(name, value) {}
/**
* Control methods
*/
HTMLObjectElement.prototype.vjs_play = function() {}
HTMLObjectElement.prototype.vjs_pause = function() {}
HTMLObjectElement.prototype.vjs_load = function() {}
/**
* @param {string} src
*/
HTMLObjectElement.prototype.vjs_src = function(src) {}

View File

@ -1,18 +1,19 @@
goog.provide('_V_.Flash');
goog.provide('_V_.media.flash');
goog.provide('vjs.Flash');
goog.provide('vjs.media.flash');
goog.require('_V_.MediaTechController');
goog.require('vjs.MediaTechController');
/* VideoJS-SWF - Custom Flash Player with HTML5-ish API - https://github.com/zencoder/video-js-swf
Not using setupTriggers. Using global onEvent func to distribute events
================================================================================ */
/**
* HTML5 Media Controller - Wrapper for HTML5 Media API
* @param {_V_.Player|Object} player
* @param {vjs.Player|Object} player
* @param {Object=} options
* @param {Function=} ready
* @constructor
*/
_V_.Flash = function(player, options, ready){
vjs.Flash = function(player, options, ready){
goog.base(this, player, options, ready);
var source = options.source,
@ -21,51 +22,53 @@ _V_.Flash = function(player, options, ready){
parentEl = options.parentEl,
// Create a temporary element to be replaced by swf object
placeHolder = this.el = _V_.createElement("div", { id: parentEl.id + "_temp_flash" }),
placeHolder = this.el_ = vjs.createEl("div", { id: player.getId() + "_temp_flash" }),
// Generate ID for swf object
objId = player.el.id+"_flash_api",
objId = player.getId()+"_flash_api",
// Store player options in local var for optimization
// TODO: switch to using player methods instead of options
// e.g. player.autoplay();
playerOptions = player.options,
// Merge default flashvars with ones passed in to init
flashVars = _V_.merge({
flashVars = vjs.merge({
// SWF Callback Functions
readyFunction: "_V_.Flash.onReady",
eventProxyFunction: "_V_.Flash.onEvent",
errorEventProxyFunction: "_V_.Flash.onError",
'readyFunction': "videojs.Flash.onReady",
'eventProxyFunction': "videojs.Flash.onEvent",
'errorEventProxyFunction': "videojs.Flash.onError",
// Player Settings
autoplay: playerOptions.autoplay,
preload: playerOptions.preload,
loop: playerOptions.loop,
muted: playerOptions.muted
'autoplay': playerOptions.autoplay,
'preload': playerOptions.preload,
'loop': playerOptions.loop,
'muted': playerOptions.muted
}, options.flashVars),
}, options['flashVars']),
// Merge default parames with ones passed in
params = _V_.merge({
wmode: "opaque", // Opaque is needed to overlay controls, but can affect playback performance
bgcolor: "#000000" // Using bgcolor prevents a white flash when the object is loading
}, options.params),
params = vjs.merge({
'wmode': "opaque", // Opaque is needed to overlay controls, but can affect playback performance
'bgcolor': "#000000" // Using bgcolor prevents a white flash when the object is loading
}, options['params']),
// Merge default attributes with ones passed in
attributes = _V_.merge({
id: objId,
name: objId, // Both ID and Name needed or swf to identifty itself
attributes = vjs.merge({
'id': objId,
'name': objId, // Both ID and Name needed or swf to identifty itself
'class': 'vjs-tech'
}, options.attributes)
}, options['attributes'])
;
// If source was supplied pass as a flash var.
if (source) {
flashVars.src = encodeURIComponent(_V_.getAbsoluteURL(source.src));
flashVars['src'] = encodeURIComponent(vjs.getAbsoluteURL(source.src));
}
// Add placeholder to player div
_V_.insertFirst(placeHolder, parentEl);
vjs.insertFirst(placeHolder, parentEl);
// Having issues with Flash reloading on certain page actions (hide/resize/fullscreen) in certain browsers
// This allows resetting the playhead when we catch the reload
@ -97,43 +100,43 @@ _V_.Flash = function(player, options, ready){
// Not sure why that even works, but it causes the browser to look like it's continuously trying to load the page.
// Firefox 3.6 keeps calling the iframe onload function anytime I write to it, causing an endless loop.
if (options.iFrameMode === true && !_V_.isFF) {
if (options.iFrameMode === true && !vjs.IS_FIREFOX) {
// Create iFrame with vjs-tech class so it's 100% width/height
var iFrm = _V_.createElement("iframe", {
id: objId + "_iframe",
name: objId + "_iframe",
className: "vjs-tech",
scrolling: "no",
marginWidth: 0,
marginHeight: 0,
frameBorder: 0
var iFrm = vjs.createEl("iframe", {
'id': objId + "_iframe",
'name': objId + "_iframe",
'className': "vjs-tech",
'scrolling': "no",
'marginWidth': 0,
'marginHeight': 0,
'frameBorder': 0
});
// Update ready function names in flash vars for iframe window
flashVars.readyFunction = "ready";
flashVars.eventProxyFunction = "events";
flashVars.errorEventProxyFunction = "errors";
flashVars['readyFunction'] = "ready";
flashVars['eventProxyFunction'] = "events";
flashVars['errorEventProxyFunction'] = "errors";
// Tried multiple methods to get this to work in all browsers
// Tried embedding the flash object in the page first, and then adding a place holder to the iframe, then replacing the placeholder with the page object.
// The goal here was to try to load the swf URL in the parent page first and hope that got around the firefox security error
// var newObj = _V_.Flash.embed(options.swf, placeHolder, flashVars, params, attributes);
// var newObj = vjs.Flash.embed(options.swf, placeHolder, flashVars, params, attributes);
// (in onload)
// var temp = _V_.createElement("a", { id:"asdf", innerHTML: "asdf" } );
// var temp = vjs.createEl("a", { id:"asdf", innerHTML: "asdf" } );
// iDoc.body.appendChild(temp);
// Tried embedding the flash object through javascript in the iframe source.
// This works in webkit but still triggers the firefox security error
// iFrm.src = "javascript: document.write('"+_V_.Flash.getEmbedCode(options.swf, flashVars, params, attributes)+"');";
// iFrm.src = "javascript: document.write('"+vjs.Flash.getEmbedCode(options.swf, flashVars, params, attributes)+"');";
// Tried an actual local iframe just to make sure that works, but it kills the easiness of the CDN version if you require the user to host an iframe
// We should add an option to host the iframe locally though, because it could help a lot of issues.
// iFrm.src = "iframe.html";
// Wait until iFrame has loaded to write into it.
_V_.addEvent(iFrm, "load", _V_.proxy(this, function(){
vjs.on(iFrm, "load", vjs.bind(this, function(){
var iDoc, objTag, swfLoc,
iWin = iFrm.contentWindow,
@ -145,7 +148,7 @@ _V_.Flash = function(player, options, ready){
// I did find a hack where if I call the iframe's window.location.href="", it would get around the security error
// However, the main page would look like it was loading indefinitely (URL bar loading spinner would never stop)
// Plus Firefox 3.6 didn't work no matter what I tried.
// if (_V_.ua.match("Firefox")) {
// if (vjs.USER_AGENT.match("Firefox")) {
// iWin.location.href = "";
// }
@ -166,14 +169,14 @@ _V_.Flash = function(player, options, ready){
// Using document.write actually got around the security error that browsers were throwing.
// Again, it's a dynamically generated (same domain) iframe, loading an external Flash swf.
// Not sure why that's a security issue, but apparently it is.
iDoc.write(_V_.Flash.getEmbedCode(options.swf, flashVars, params, attributes));
iDoc.write(vjs.Flash.getEmbedCode(options['swf'], flashVars, params, attributes));
// Setting variables on the window needs to come after the doc write because otherwise they can get reset in some browsers
// So far no issues with swf ready event being called before it's set on the window.
iWin.player = this.player;
// Create swf ready function for iFrame window
iWin.ready = _V_.proxy(this.player, function(currSwf){
iWin.ready = vjs.bind(this.player, function(currSwf){
var el = iDoc.getElementById(currSwf),
player = this,
tech = player.tech;
@ -182,23 +185,23 @@ _V_.Flash = function(player, options, ready){
tech.el = el;
// Now that the element is ready, make a click on the swf play the video
_V_.addEvent(el, "click", tech.proxy(tech.onClick));
vjs.on(el, "click", tech.bind(tech.onClick));
// Make sure swf is actually ready. Sometimes the API isn't actually yet.
_V_.Flash.checkReady(tech);
vjs.Flash.checkReady(tech);
});
// Create event listener for all swf events
iWin.events = _V_.proxy(this.player, function(swfID, eventName, other){
iWin.events = vjs.bind(this.player, function(swfID, eventName, other){
var player = this;
if (player && player.techName == "flash") {
player.triggerEvent(eventName);
player.trigger(eventName);
}
});
// Create error listener for all swf errors
iWin.errors = _V_.proxy(this.player, function(swfID, eventName){
_V_.log("Flash Error", eventName);
iWin.errors = vjs.bind(this.player, function(swfID, eventName){
vjs.log("Flash Error", eventName);
});
}));
@ -208,98 +211,105 @@ _V_.Flash = function(player, options, ready){
// If not using iFrame mode, embed as normal object
} else {
_V_.Flash.embed(options.swf, placeHolder, flashVars, params, attributes);
vjs.Flash.embed(options['swf'], placeHolder, flashVars, params, attributes);
}
};
goog.inherits(_V_.Flash, _V_.MediaTechController);
goog.inherits(vjs.Flash, vjs.MediaTechController);
_V_.Flash = _V_.PlaybackTech.extend({
vjs.Flash.prototype.dispose = function(){
goog.base(this, 'dispose');
};
init: function(player, options){
},
vjs.Flash.prototype.play = function(){
this.el_.vjs_play();
}
destroy: function(){
this.el.parentNode.removeChild(this.el);
},
vjs.Flash.prototype.pause = function(){
this.el_.vjs_pause();
}
// setupTriggers: function(){}, // Using global onEvent func to distribute events
vjs.Flash.prototype.src = function(src){
// Make sure source URL is abosolute.
src = vjs.getAbsoluteURL(src);
play: function(){ this.el.vjs_play(); },
pause: function(){ this.el.vjs_pause(); },
src: function(src){
// Make sure source URL is abosolute.
src = _V_.getAbsoluteURL(src);
this.el_.vjs_src(src);
this.el.vjs_src(src);
// Currently the SWF doesn't autoplay if you load a source later.
// e.g. Load player w/ no source, wait 2s, set src.
if (this.player.autoplay()) {
var tech = this;
setTimeout(function(){ tech.play(); }, 0);
}
},
load: function(){ this.el.vjs_load(); },
poster: function(){ this.el.vjs_getProperty("poster"); },
buffered: function(){
return _V_.createTimeRange(0, this.el.vjs_getProperty("buffered"));
},
supportsFullScreen: function(){
return false; // Flash does not allow fullscreen through javascript
},
enterFullScreen: function(){
return false;
// Currently the SWF doesn't autoplay if you load a source later.
// e.g. Load player w/ no source, wait 2s, set src.
if (this.player.autoplay()) {
var tech = this;
setTimeout(function(){ tech.play(); }, 0);
}
});
}
vjs.Flash.prototype.load = function(){
this.el_.vjs_load();
}
vjs.Flash.prototype.poster = function(){
this.el_.vjs_getProperty("poster");
}
vjs.Flash.prototype.buffered = function(){
return vjs.createTimeRange(0, this.el_.vjs_getProperty("buffered"));
}
vjs.Flash.prototype.supportsFullScreen = function(){
return false; // Flash does not allow fullscreen through javascript
}
vjs.Flash.prototype.enterFullScreen = function(){
return false;
}
// Create setters and getters for attributes
(function(){
var api = vjs.Flash.prototype,
readWrite = "preload,currentTime,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted".split(","),
readOnly = "error,currentSrc,networkState,readyState,seeking,initialTime,duration,startOffsetTime,paused,played,seekable,ended,videoTracks,audioTracks,videoWidth,videoHeight,textTracks".split(","),
callOnly = "load,play,pause".split(",");
// Overridden: buffered
var api = _V_.Flash.prototype,
readWrite = "preload,currentTime,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted".split(","),
readOnly = "error,currentSrc,networkState,readyState,seeking,initialTime,duration,startOffsetTime,paused,played,seekable,ended,videoTracks,audioTracks,videoWidth,videoHeight,textTracks".split(","),
callOnly = "load,play,pause".split(",");
// Overridden: buffered
/**
* @this {*}
*/
createSetter = function(attr){
var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);
api["set"+attrUpper] = function(val){ return this.el_.vjs_setProperty(attr, val); };
},
createSetter = function(attr){
var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);
api["set"+attrUpper] = function(val){ return this.el.vjs_setProperty(attr, val); };
},
/**
* @this {*}
*/
createGetter = function(attr){
api[attr] = function(){ return this.el_.vjs_getProperty(attr); };
}
;
createGetter = function(attr){
api[attr] = function(){ return this.el.vjs_getProperty(attr); };
}
;
// Create getter and setters for all read/write attributes
for (var i = 0; i < readWrite.length; i++) {
createGetter(readWrite[i]);
createSetter(readWrite[i]);
};
// Create getter and setters for all read/write attributes
_V_.each(readWrite, function(attr){
createGetter(attr);
createSetter(attr);
});
// Create getters for read-only attributes
_V_.each(readOnly, function(attr){
createGetter(attr);
});
})();
// Create getters for read-only attributes
for (var i = 0; i < readOnly.length; i++) {
createGetter(readOnly[i]);
};
/* Flash Support Testing -------------------------------------------------------- */
_V_.Flash.isSupported = function(){
return _V_.Flash.version()[0] >= 10;
vjs.Flash.isSupported = function(){
return vjs.Flash.version()[0] >= 10;
// return swfobject.hasFlashPlayerVersion("10");
};
_V_.Flash.canPlaySource = function(srcObj){
if (srcObj.type in _V_.Flash.prototype.support.formats) { return "maybe"; }
vjs.Flash.canPlaySource = function(srcObj){
if (srcObj.type in vjs.Flash.prototype.features.formats) { return "maybe"; }
};
_V_.Flash.prototype.support = {
vjs.Flash.prototype.features = {
formats: {
"video/flv": "FLV",
"video/x-flv": "FLV",
@ -308,19 +318,19 @@ _V_.Flash.prototype.support = {
},
// Optional events that we can manually mimic with timers
progressEvent: false,
timeupdateEvent: false,
// currently not triggered by video-js-swf
progressEvents: false,
timeupdateEvents: false,
// Resizing plugins using request fullscreen reloads the plugin
fullscreenResize: false,
// Resizing plugins in Firefox always reloads the plugin (e.g. full window mode)
parentResize: !(_V_.ua.match("Firefox"))
parentResize: !(vjs.USER_AGENT.match("Firefox"))
};
_V_.Flash.onReady = function(currSwf){
var el = _V_.el(currSwf);
vjs.Flash['onReady'] = function(currSwf){
var el = vjs.el(currSwf);
// Get player from box
// On firefox reloads, el might already have a player
@ -331,20 +341,20 @@ _V_.Flash.onReady = function(currSwf){
el.player = player;
// Update reference to playback technology element
tech.el = el;
tech.el_ = el;
// Now that the element is ready, make a click on the swf play the video
tech.addEvent("click", tech.onClick);
tech.on("click", tech.onClick);
_V_.Flash.checkReady(tech);
vjs.Flash.checkReady(tech);
};
// The SWF isn't alwasy ready when it says it is. Sometimes the API functions still need to be added to the object.
// If it's not ready, we set a timeout to check again shortly.
_V_.Flash.checkReady = function(tech){
vjs.Flash.checkReady = function(tech){
// Check if API property exists
if (tech.el.vjs_getProperty) {
if (tech.getEl().vjs_getProperty) {
// If so, tell tech it's ready
tech.triggerReady();
@ -353,27 +363,27 @@ _V_.Flash.checkReady = function(tech){
} else {
setTimeout(function(){
_V_.Flash.checkReady(tech);
vjs.Flash.checkReady(tech);
}, 50);
}
};
// Trigger events from the swf on the player
_V_.Flash.onEvent = function(swfID, eventName){
var player = _V_.el(swfID).player;
player.triggerEvent(eventName);
vjs.Flash['onEvent'] = function(swfID, eventName){
var player = vjs.el(swfID).player;
player.trigger(eventName);
};
// Log errors from the swf
_V_.Flash.onError = function(swfID, err){
var player = _V_.el(swfID).player;
player.triggerEvent("error");
_V_.log("Flash Error", err, swfID);
vjs.Flash['onError'] = function(swfID, err){
var player = vjs.el(swfID).player;
player.trigger("error");
vjs.log("Flash Error", err, swfID);
};
// Flash Version Check
_V_.Flash.version = function(){
vjs.Flash.version = function(){
var version = '0,0,0';
// IE
@ -392,11 +402,11 @@ _V_.Flash.version = function(){
};
// Flash embedding method. Only used in non-iframe mode
_V_.Flash.embed = function(swf, placeHolder, flashVars, params, attributes){
var code = _V_.Flash.getEmbedCode(swf, flashVars, params, attributes),
vjs.Flash.embed = function(swf, placeHolder, flashVars, params, attributes){
var code = vjs.Flash.getEmbedCode(swf, flashVars, params, attributes),
// Get element by embedding code and retrieving created element
obj = _V_.createElement("div", { innerHTML: code }).childNodes[0],
obj = vjs.createEl("div", { innerHTML: code }).childNodes[0],
par = placeHolder.parentNode
;
@ -405,7 +415,7 @@ _V_.Flash.embed = function(swf, placeHolder, flashVars, params, attributes){
// IE6 seems to have an issue where it won't initialize the swf object after injecting it.
// This is a dumb temporary fix
if (_V_.isIE()) {
if (vjs.IS_IE6to8()) {
var newObj = par.childNodes[0];
setTimeout(function(){
newObj.style.display = "block";
@ -416,7 +426,7 @@ _V_.Flash.embed = function(swf, placeHolder, flashVars, params, attributes){
};
_V_.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
var objTag = '<object type="application/x-shockwave-flash"',
flashVarsString = '',
@ -425,36 +435,36 @@ _V_.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
// Convert flash vars to string
if (flashVars) {
_V_.eachProp(flashVars, function(key, val){
vjs.eachProp(flashVars, function(key, val){
flashVarsString += (key + "=" + val + "&amp;");
});
}
// Add swf, flashVars, and other default params
params = _V_.merge({
movie: swf,
flashvars: flashVarsString,
allowScriptAccess: "always", // Required to talk to swf
allowNetworking: "all" // All should be default, but having security issues.
params = vjs.merge({
'movie': swf,
'flashvars': flashVarsString,
'allowScriptAccess': "always", // Required to talk to swf
'allowNetworking': "all" // All should be default, but having security issues.
}, params);
// Create param tags string
_V_.eachProp(params, function(key, val){
vjs.eachProp(params, function(key, val){
paramsString += '<param name="'+key+'" value="'+val+'" />';
});
attributes = _V_.merge({
attributes = vjs.merge({
// Add swf to attributes (need both for IE and Others to work)
data: swf,
'data': swf,
// Default to 100% width/height
width: "100%",
height: "100%"
'width': "100%",
'height': "100%"
}, attributes);
// Create Attributes string
_V_.eachProp(attributes, function(key, val){
vjs.eachProp(attributes, function(key, val){
attrsString += (key + '="' + val + '" ');
});

View File

@ -1,22 +1,21 @@
goog.provide('_V_.Html5');
goog.provide('_V_.media.html5');
goog.provide('_V_.Html5.Supports');
goog.provide('_V_.Html5.Events');
goog.provide('_V_.Html5.isSupported');
goog.provide('_V_.Html5.canPlaySource');
goog.provide('vjs.Html5');
goog.provide('vjs.media.html5');
goog.provide('vjs.Html5.Events');
goog.provide('vjs.Html5.isSupported');
goog.provide('vjs.Html5.canPlaySource');
goog.require('_V_.MediaTechController');
goog.require('vjs.MediaTechController');
/* HTML5 Media Controller - Wrapper for HTML5 Media API
================================================================================ */
============================================================================= */
/**
* HTML5 Media Controller - Wrapper for HTML5 Media API
* @param {_V_.Player|Object} player
* @param {vjs.Player|Object} player
* @param {Object=} options
* @param {Function=} ready
* @constructor
*/
_V_.Html5 = function(player, options, ready){
vjs.Html5 = function(player, options, ready){
goog.base(this, player, options, ready);
var source = options.source;
@ -48,16 +47,16 @@ _V_.Html5 = function(player, options, ready){
this.triggerReady();
};
goog.inherits(_V_.Html5, _V_.MediaTechController);
goog.inherits(vjs.Html5, vjs.MediaTechController);
_V_.Html5.prototype.dispose = function(){
vjs.Html5.prototype.dispose = function(){
// this.player.tag = false;
this.removeTriggers();
goog.base(this, 'dispose');
};
_V_.Html5.prototype.createEl = function(){
vjs.Html5.prototype.createEl = function(){
var player = this.player,
// If possible, reuse original tag for HTML5 playback technology element
el = player.tag,
@ -66,20 +65,20 @@ _V_.Html5.prototype.createEl = function(){
// Check if this browser supports moving the element into the box.
// On the iPhone video will break if you move the element,
// So we have to create a brand new element.
if (!el || _V_.Html5.Supports.movingElementInDOM === false) {
if (!el || this.features.movingMediaElementInDOM === false) {
// If the original tag is still there, remove it.
if (el) {
player.getEl().removeChild(el);
}
newEl = _V_.createElement("video", {
newEl = vjs.createElement("video", {
id: el.id || player.id + "_html5_api",
className: el.className || "vjs-tech"
});
el = newEl;
_V_.insertFirst(el, player.el);
vjs.insertFirst(el, player.el);
}
// Update specific tag settings, in case they were overridden
@ -97,50 +96,50 @@ _V_.Html5.prototype.createEl = function(){
// Make video events trigger player events
// May seem verbose here, but makes other APIs possible.
_V_.Html5.prototype.setupTriggers = function(){
for (var i = _V_.Html5.Events.length - 1; i >= 0; i--) {
_V_.on(this.el_, _V_.Html5.Events[i], _V_.bind(this.player, this.eventHandler));
vjs.Html5.prototype.setupTriggers = function(){
for (var i = vjs.Html5.Events.length - 1; i >= 0; i--) {
vjs.on(this.el_, vjs.Html5.Events[i], vjs.bind(this.player, this.eventHandler));
};
};
_V_.Html5.prototype.removeTriggers = function(){
for (var i = _V_.Html5.Events.length - 1; i >= 0; i--) {
_V_.off(this.el_, _V_.Html5.Events[i], _V_.bind(this.player, this.eventHandler));
vjs.Html5.prototype.removeTriggers = function(){
for (var i = vjs.Html5.Events.length - 1; i >= 0; i--) {
vjs.off(this.el_, vjs.Html5.Events[i], vjs.bind(this.player, this.eventHandler));
};
// console.log("removeTriggers", _V_.getData(this.el_));
// console.log("removeTriggers", vjs.getData(this.el_));
};
_V_.Html5.prototype.eventHandler = function(e){
vjs.Html5.prototype.eventHandler = function(e){
// console.log('eventHandler', e.type, e, this.el_)
this.trigger(e);
e.stopPropagation();
};
_V_.Html5.prototype.play = function(){ this.el_.play(); };
_V_.Html5.prototype.pause = function(){ this.el_.pause(); };
_V_.Html5.prototype.paused = function(){ return this.el_.paused; };
vjs.Html5.prototype.play = function(){ this.el_.play(); };
vjs.Html5.prototype.pause = function(){ this.el_.pause(); };
vjs.Html5.prototype.paused = function(){ return this.el_.paused; };
_V_.Html5.prototype.currentTime = function(){ return this.el_.currentTime; };
_V_.Html5.prototype.setCurrentTime = function(seconds){
vjs.Html5.prototype.currentTime = function(){ return this.el_.currentTime; };
vjs.Html5.prototype.setCurrentTime = function(seconds){
try {
this.el_.currentTime = seconds;
} catch(e) {
_V_.log(e, "Video isn't ready. (Video.js)");
vjs.log(e, "Video isn't ready. (Video.js)");
// this.warning(VideoJS.warnings.videoNotReady);
}
};
_V_.Html5.prototype.duration = function(){ return this.el_.duration || 0; };
_V_.Html5.prototype.buffered = function(){ return this.el_.buffered; };
vjs.Html5.prototype.duration = function(){ return this.el_.duration || 0; };
vjs.Html5.prototype.buffered = function(){ return this.el_.buffered; };
_V_.Html5.prototype.volume = function(){ return this.el_.volume; };
_V_.Html5.prototype.setVolume = function(percentAsDecimal){ this.el_.volume = percentAsDecimal; };
_V_.Html5.prototype.muted = function(){ return this.el_.muted; };
_V_.Html5.prototype.setMuted = function(muted){ this.el_.muted = muted; };
vjs.Html5.prototype.volume = function(){ return this.el_.volume; };
vjs.Html5.prototype.setVolume = function(percentAsDecimal){ this.el_.volume = percentAsDecimal; };
vjs.Html5.prototype.muted = function(){ return this.el_.muted; };
vjs.Html5.prototype.setMuted = function(muted){ this.el_.muted = muted; };
_V_.Html5.prototype.width = function(){ return this.el_.offsetWidth; };
_V_.Html5.prototype.height = function(){ return this.el_.offsetHeight; };
vjs.Html5.prototype.width = function(){ return this.el_.offsetWidth; };
vjs.Html5.prototype.height = function(){ return this.el_.offsetHeight; };
_V_.Html5.prototype.supportsFullScreen = function(){
vjs.Html5.prototype.supportsFullScreen = function(){
if (typeof this.el_.webkitEnterFullScreen == 'function') {
// Seems to be broken in Chromium/Chrome && Safari in Leopard
@ -151,46 +150,46 @@ _V_.Html5.prototype.supportsFullScreen = function(){
return false;
};
_V_.Html5.prototype.enterFullScreen = function(){
vjs.Html5.prototype.enterFullScreen = function(){
try {
this.el_.webkitEnterFullScreen();
} catch (e) {
if (e.code == 11) {
// this.warning(VideoJS.warnings.videoNotReady);
_V_.log("Video.js: Video not ready.");
vjs.log("Video.js: Video not ready.");
}
}
};
_V_.Html5.prototype.exitFullScreen = function(){
vjs.Html5.prototype.exitFullScreen = function(){
try {
this.el_.webkitExitFullScreen();
} catch (e) {
if (e.code == 11) {
// this.warning(VideoJS.warnings.videoNotReady);
_V_.log("Video.js: Video not ready.");
vjs.log("Video.js: Video not ready.");
}
}
};
_V_.Html5.prototype.src = function(src){ this.el_.src = src; };
_V_.Html5.prototype.load = function(){ this.el_.load(); };
_V_.Html5.prototype.currentSrc = function(){ return this.el_.currentSrc; };
vjs.Html5.prototype.src = function(src){ this.el_.src = src; };
vjs.Html5.prototype.load = function(){ this.el_.load(); };
vjs.Html5.prototype.currentSrc = function(){ return this.el_.currentSrc; };
_V_.Html5.prototype.preload = function(){ return this.el_.preload; };
_V_.Html5.prototype.setPreload = function(val){ this.el_.preload = val; };
_V_.Html5.prototype.autoplay = function(){ return this.el_.autoplay; };
_V_.Html5.prototype.setAutoplay = function(val){ this.el_.autoplay = val; };
_V_.Html5.prototype.loop = function(){ return this.el_.loop; };
_V_.Html5.prototype.setLoop = function(val){ this.el_.loop = val; };
vjs.Html5.prototype.preload = function(){ return this.el_.preload; };
vjs.Html5.prototype.setPreload = function(val){ this.el_.preload = val; };
vjs.Html5.prototype.autoplay = function(){ return this.el_.autoplay; };
vjs.Html5.prototype.setAutoplay = function(val){ this.el_.autoplay = val; };
vjs.Html5.prototype.loop = function(){ return this.el_.loop; };
vjs.Html5.prototype.setLoop = function(val){ this.el_.loop = val; };
_V_.Html5.prototype.error = function(){ return this.el_.error; };
vjs.Html5.prototype.error = function(){ return this.el_.error; };
// networkState: function(){ return this.el_.networkState; },
// readyState: function(){ return this.el_.readyState; },
_V_.Html5.prototype.seeking = function(){ return this.el_.seeking; };
vjs.Html5.prototype.seeking = function(){ return this.el_.seeking; };
// initialTime: function(){ return this.el_.initialTime; },
// startOffsetTime: function(){ return this.el_.startOffsetTime; },
// played: function(){ return this.el_.played; },
// seekable: function(){ return this.el_.seekable; },
_V_.Html5.prototype.ended = function(){ return this.el_.ended; };
vjs.Html5.prototype.ended = function(){ return this.el_.ended; };
// videoTracks: function(){ return this.el_.videoTracks; },
// audioTracks: function(){ return this.el_.audioTracks; },
// videoWidth: function(){ return this.el_.videoWidth; },
@ -200,16 +199,16 @@ _V_.Html5.prototype.ended = function(){ return this.el_.ended; };
// playbackRate: function(){ return this.el_.playbackRate; },
// mediaGroup: function(){ return this.el_.mediaGroup; },
// controller: function(){ return this.el_.controller; },
_V_.Html5.prototype.controls = function(){ return this.player.options.controls; };
_V_.Html5.prototype.defaultMuted = function(){ return this.el_.defaultMuted; };
vjs.Html5.prototype.controls = function(){ return this.player.options.controls; };
vjs.Html5.prototype.defaultMuted = function(){ return this.el_.defaultMuted; };
/* HTML5 Support Testing -------------------------------------------------------- */
/* HTML5 Support Testing ---------------------------------------------------- */
_V_.Html5.isSupported = function(){
vjs.Html5.isSupported = function(){
return !!document.createElement("video").canPlayType;
};
_V_.Html5.canPlaySource = function(srcObj){
vjs.Html5.canPlaySource = function(srcObj){
return !!document.createElement("video").canPlayType(srcObj.type);
// TODO: Check Type
// If no Type, check ext
@ -217,28 +216,31 @@ _V_.Html5.canPlaySource = function(srcObj){
};
// List of all HTML5 events (various uses).
_V_.Html5.Events = "loadstart,suspend,abort,error,emptied,stalled,loadedmetadata,loadeddata,canplay,canplaythrough,playing,waiting,seeking,seeked,ended,durationchange,timeupdate,progress,play,pause,ratechange,volumechange".split(",");
vjs.Html5.Events = "loadstart,suspend,abort,error,emptied,stalled,loadedmetadata,loadeddata,canplay,canplaythrough,playing,waiting,seeking,seeked,ended,durationchange,timeupdate,progress,play,pause,ratechange,volumechange".split(",");
// HTML5 Device Fixes ---------------------------------------------------------- //
_V_.Html5.Supports = {
// HTML5 Feature detection and Device Fixes --------------------------------- //
vjs.Html5.prototype.features = {
// Support for video element specific full screen. (webkitEnterFullScreen, not requestFullscreen which we use on the player div)
// http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html
// Seems to be broken in Chromium/Chrome && Safari in Leopard
'fullscreen': (_V_.TEST_VID.webkitEnterFullScreen) ? (!_V_.UA.match("Chrome") && !_V_.UA.match("Mac OS X 10.5") ? true : false) : false,
fullscreen: (vjs.TEST_VID.webkitEnterFullScreen)
? ((!vjs.USER_AGENT.match("Chrome") && !vjs.USER_AGENT.match("Mac OS X 10.5")
? true
: false))
: false,
// In iOS, if you move a video element in the DOM, it breaks video playback.
'movingElementInDOM': !_V_.IS_IOS
movingMediaElementInDOM: !vjs.IS_IOS
};
// Android
if (_V_.IS_ANDROID) {
if (vjs.IS_ANDROID) {
// Override Android 2.2 and less canPlayType method which is broken
if (_V_.ANDROID_VERSION < 3) {
if (vjs.ANDROID_VERSION < 3) {
document.createElement("video").constructor.prototype.canPlayType = function(type){
return (type && type.toLowerCase().indexOf("video/mp4") != -1) ? "maybe" : "";
};

View File

@ -1,18 +1,18 @@
goog.provide('_V_.media');
goog.provide('_V_.MediaTechController');
goog.provide('vjs.media');
goog.provide('vjs.MediaTechController');
goog.require('_V_.Component');
goog.require('vjs.Component');
/* Media Technology Controller - Base class for media playback technologies
================================================================================ */
/**
* Base class for media (HTML5 Video, Flash) controllers
* @param {_V_.Player|Object} player Central player instance
* @param {vjs.Player|Object} player Central player instance
* @param {Object=} options Options object
* @constructor
*/
_V_.MediaTechController = function(player, options, ready){
vjs.MediaTechController = function(player, options, ready){
goog.base(this, player, options, ready);
// Make playback element clickable
@ -20,7 +20,7 @@ _V_.MediaTechController = function(player, options, ready){
// player.triggerEvent("techready");
};
goog.inherits(_V_.MediaTechController, _V_.Component);
goog.inherits(vjs.MediaTechController, vjs.Component);
// destroy: function(){},
// createElement: function(){},
@ -28,7 +28,7 @@ goog.inherits(_V_.MediaTechController, _V_.Component);
/**
* Handle a click on the media element. By default will play the media.
*/
_V_.MediaTechController.prototype.onClick = function(){
vjs.MediaTechController.prototype.onClick = function(){
if (this.player.options.controls) {
if (this.player.paused()) {
this.player.play();
@ -42,13 +42,13 @@ _V_.MediaTechController.prototype.onClick = function(){
* List of default API methods for any MediaTechController
* @type {String}
*/
_V_.apiMethods = "play,pause,paused,currentTime,setCurrentTime,duration,buffered,volume,setVolume,muted,setMuted,width,height,supportsFullScreen,enterFullScreen,src,load,currentSrc,preload,setPreload,autoplay,setAutoplay,loop,setLoop,error,networkState,readyState,seeking,initialTime,startOffsetTime,played,seekable,ended,videoTracks,audioTracks,videoWidth,videoHeight,textTracks,defaultPlaybackRate,playbackRate,mediaGroup,controller,controls,defaultMuted".split(",");
vjs.media.ApiMethods = "play,pause,paused,currentTime,setCurrentTime,duration,buffered,volume,setVolume,muted,setMuted,width,height,supportsFullScreen,enterFullScreen,src,load,currentSrc,preload,setPreload,autoplay,setAutoplay,loop,setLoop,error,networkState,readyState,seeking,initialTime,startOffsetTime,played,seekable,ended,videoTracks,audioTracks,videoWidth,videoHeight,textTracks,defaultPlaybackRate,playbackRate,mediaGroup,controller,controls,defaultMuted".split(",");
// Create placeholder methods for each that warn when a method isn't supported by the current playback technology
for (var i = _V_.apiMethods.length - 1; i >= 0; i--) {
var methodName = _V_.apiMethods[i];
for (var i = vjs.media.ApiMethods.length - 1; i >= 0; i--) {
var methodName = vjs.media.ApiMethods[i];
_V_.MediaTechController.prototype[_V_.apiMethods[i]] = (function(methodName){
vjs.MediaTechController.prototype[vjs.media.ApiMethods[i]] = (function(methodName){
return function(){
throw new Error("The '"+methodName+"' method is not available on the playback technology's API");
}

View File

@ -1,15 +1,15 @@
goog.provide('_V_.Player');
goog.provide('vjs.Player');
goog.require('_V_.Component');
goog.require('vjs.Component');
/**
* Main player class. Returned by _V_(id);
* Main player class. Returned by vjs(id);
* @param {Element} tag The original video tag used for configuring options
* @param {Object=} options Player options
* @param {Function=} ready Ready callback function
* @constructor
*/
_V_.Player = function(tag, options, ready){
vjs.Player = function(tag, options, ready){
this.tag = tag; // Store the original tag used to set options
// Set Options
@ -18,17 +18,25 @@ _V_.Player = function(tag, options, ready){
// This latter part coincides with the load order
// (tag must exist before Player)
var opts = {};
_V_.merge(opts, _V_.options); // Copy Global Defaults
_V_.merge(opts, this.getTagSettings(tag)); // Override with Video Tag Options
_V_.merge(opts, options); // Override/extend with options from setup call
vjs.merge(opts, vjs.options); // Copy Global Defaults
vjs.merge(opts, this.getTagSettings(tag)); // Override with Video Tag Options
vjs.merge(opts, options); // Override/extend with options from setup call
// Cache for video property values.
this.cache_ = {};
// Tracks defined in tracks.js
this.textTracks = [];
// this.ready(function() {
// if (opts.tracks && opts.tracks.length > 0) {
// this.addTextTracks(opts.tracks);
// }
// });
// Run base component initializing with new options.
// Builds the element through createEl()
// Inits and embeds any child components in opts
_V_.Component.call(this, this, opts, ready);
vjs.Component.call(this, this, opts, ready);
this.on("ended", this.onEnded);
this.on("play", this.onPlay);
@ -37,22 +45,16 @@ _V_.Player = function(tag, options, ready){
this.on("durationchange", this.onDurationChange);
this.on("error", this.onError);
// Tracks defined in tracks.js
// this.textTracks = [];
// if (opts.tracks && opts.tracks.length > 0) {
// this.addTextTracks(opts.tracks);
// }
// Make player easily findable by ID
_V_.players[this.id] = this;
vjs.players[this.id] = this;
};
goog.inherits(_V_.Player, _V_.Component);
goog.inherits(vjs.Player, vjs.Component);
_V_.Player.prototype.dispose = function(){
vjs.Player.prototype.dispose = function(){
// this.isReady_ = false;
// Kill reference to this player
_V_.players[this.id] = null;
vjs.players[this.id] = null;
if (this.tag && this.tag.player) { this.tag.player = null; }
if (this.el_ && this.el_.player) { this.el_.player = null; }
@ -66,13 +68,13 @@ _V_.Player.prototype.dispose = function(){
goog.base(this, 'dispose');
};
_V_.Player.prototype.getTagSettings = function(tag){
vjs.Player.prototype.getTagSettings = function(tag){
var options = {
sources: [],
tracks: []
};
_V_.merge(options, _V_.getAttributeValues(tag));
vjs.merge(options, vjs.getAttributeValues(tag));
// Get tag children settings
if (tag.hasChildNodes()) {
@ -87,10 +89,10 @@ _V_.Player.prototype.getTagSettings = function(tag){
childName = child.nodeName.toLowerCase();
if (childName === "source") {
options.sources.push(_V_.getAttributeValues(child));
options.sources.push(vjs.getAttributeValues(child));
} else if (childName === "track") {
options.tracks.push(_V_.getAttributeValues(child));
options.tracks.push(vjs.getAttributeValues(child));
}
}
@ -98,7 +100,7 @@ _V_.Player.prototype.getTagSettings = function(tag){
return options;
};
_V_.Player.prototype.createEl = function(){
vjs.Player.prototype.createEl = function(){
var el = this.el_ = goog.base(this, 'createEl', 'div');
var tag = this.tag;
@ -124,7 +126,7 @@ _V_.Player.prototype.createEl = function(){
}
// Make sure tag ID exists
tag.id = tag.id || "vjs_video_" + _V_.guid++;
tag.id = tag.id || "vjs_video_" + vjs.guid++;
// Give video tag ID and class to player div
// ID will now reference player box, not the video tag
@ -152,7 +154,7 @@ _V_.Player.prototype.createEl = function(){
if (tag.parentNode) {
tag.parentNode.insertBefore(el, tag);
}
_V_.insertFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup.
vjs.insertFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup.
return el;
}
@ -161,7 +163,7 @@ _V_.Player.prototype.createEl = function(){
// ================================================================================ */
// Load/Create an instance of playback technlogy including element and API methods
// And append playback element in player div.
_V_.Player.prototype.loadTech = function(techName, source){
vjs.Player.prototype.loadTech = function(techName, source){
// Pause and remove current playback technology
if (this.tech) {
@ -183,18 +185,18 @@ _V_.Player.prototype.loadTech = function(techName, source){
this.player.triggerReady();
// Manually track progress in cases where the browser/flash player doesn't report it.
if (!window['_V_'][techName]['Supports']['progressEvent']) {
if (!this.features.progressEvents) {
this.player.manualProgressOn();
}
// Manually track timeudpates in cases where the browser/flash player doesn't report it.
if (!window['_V_'][techName]['Supports']['timeupdateEvent']) {
if (!this.features.timeupdateEvents) {
this.player.manualTimeUpdatesOn();
}
}
// Grab tech-specific options from player options and add source and parent element to use.
var techOptions = _V_.merge({ source: source, parentEl: this.el_ }, this.options[techName])
var techOptions = vjs.merge({ source: source, parentEl: this.el_ }, this.options[techName.toLowerCase()])
if (source) {
if (source.src == this.cache_.src && this.cache_.currentTime > 0) {
@ -205,11 +207,12 @@ _V_.Player.prototype.loadTech = function(techName, source){
}
// Initialize tech instance
this.tech = new window['_V_'][techName](this, techOptions);
this.tech = new window['videojs'][techName](this, techOptions);
this.tech.ready(techReady);
};
// _V_.Player.prototype.unloadTech = function(){
// vjs.Player.prototype.unloadTech = function(){
// this.tech.destroy();
// // Turn off any manual progress or timeupdate tracking
@ -225,20 +228,20 @@ _V_.Player.prototype.loadTech = function(techName, source){
// Then with the new fullscreen API, Mozilla and webkit browsers will reload the flash object after going to fullscreen.
// To get around this, we're unloading the tech, caching source and currentTime values, and reloading the tech once the plugin is resized.
// reloadTech: function(betweenFn){
// _V_.log("unloadingTech")
// vjs.log("unloadingTech")
// this.unloadTech();
// _V_.log("unloadedTech")
// vjs.log("unloadedTech")
// if (betweenFn) { betweenFn.call(); }
// _V_.log("LoadingTech")
// vjs.log("LoadingTech")
// this.loadTech(this.techName, { src: this.cache_.src })
// _V_.log("loadedTech")
// vjs.log("loadedTech")
// },
/* 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
_V_.Player.prototype.manualProgressOn = function(){
vjs.Player.prototype.manualProgressOn = function(){
this.manualProgress = true;
// Trigger progress watching when a source begins loading
@ -253,21 +256,21 @@ _V_.Player.prototype.manualProgressOn = function(){
this.tech.one("progress", function(){
// Update known progress support for this playback technology
window['_V_'][techName]['Supports']['progressEvent'] = true;
this.features.progressEvents = true;
// Turn off manual progress tracking
this.player.manualProgressOff();
});
};
_V_.Player.prototype.manualProgressOff = function(){
vjs.Player.prototype.manualProgressOff = function(){
this.manualProgress = false;
this.stopTrackingProgress();
};
_V_.Player.prototype.trackProgress = function(){
vjs.Player.prototype.trackProgress = function(){
this.progressInterval = setInterval(_V_.bind(this, function(){
this.progressInterval = setInterval(vjs.bind(this, function(){
// Don't trigger unless buffered amount is greater than last time
// log(this.cache_.bufferEnd, this.buffered().end(0), this.duration())
/* TODO: update for multiple buffered regions */
@ -279,69 +282,62 @@ _V_.Player.prototype.trackProgress = function(){
}
}), 500);
};
_V_.Player.prototype.stopTrackingProgress = function(){ clearInterval(this.progressInterval); };
vjs.Player.prototype.stopTrackingProgress = function(){ clearInterval(this.progressInterval); };
/* Time Tracking -------------------------------------------------------------- */
_V_.Player.prototype.manualTimeUpdatesOn = function(){
vjs.Player.prototype.manualTimeUpdatesOn = function(){
this.manualTimeUpdates = true;
this.on("play", this.trackCurrentTime);
this.on("pause", this.stopTrackingCurrentTime);
// timeupdate is also called by .currentTime whenever current time is set
var techName = this.techName;
// Watch for native timeupdate event
this.tech.on("timeupdate", function(){
// Remove this listener from the element
this.off("timeupdate", arguments.callee);
this.tech.one("timeupdate", function(){
// Update known progress support for this playback technology
window['_V_'][techName]['Supports']['timeupdateEvent'] = true;
this.features.timeupdateEvents = true;
// Turn off manual progress tracking
this.player.manualTimeUpdatesOff();
});
};
_V_.Player.prototype.manualTimeUpdatesOff = function(){
vjs.Player.prototype.manualTimeUpdatesOff = function(){
this.manualTimeUpdates = false;
this.stopTrackingCurrentTime();
this.off("play", this.trackCurrentTime);
this.off("pause", this.stopTrackingCurrentTime);
};
_V_.Player.prototype.trackCurrentTime = function(){
vjs.Player.prototype.trackCurrentTime = function(){
if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); }
this.currentTimeInterval = setInterval(_V_.bind(this, function(){
this.currentTimeInterval = setInterval(vjs.bind(this, function(){
this.trigger("timeupdate");
}), 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
};
// Turn off play progress tracking (when paused or dragging)
_V_.Player.prototype.stopTrackingCurrentTime = function(){ clearInterval(this.currentTimeInterval); };
vjs.Player.prototype.stopTrackingCurrentTime = function(){ clearInterval(this.currentTimeInterval); };
// /* Player event handlers (how the player reacts to certain events)
// ================================================================================ */
_V_.Player.prototype.onEnded = function(){
vjs.Player.prototype.onEnded = function(){
if (this.options.loop) {
this.currentTime(0);
this.play();
}
};
_V_.Player.prototype.onPlay = function(){
_V_.removeClass(this.el_, "vjs-paused");
_V_.addClass(this.el_, "vjs-playing");
vjs.Player.prototype.onPlay = function(){
vjs.removeClass(this.el_, "vjs-paused");
vjs.addClass(this.el_, "vjs-playing");
};
_V_.Player.prototype.onPause = function(){
_V_.removeClass(this.el_, "vjs-playing");
_V_.addClass(this.el_, "vjs-paused");
vjs.Player.prototype.onPause = function(){
vjs.removeClass(this.el_, "vjs-playing");
vjs.addClass(this.el_, "vjs-paused");
};
_V_.Player.prototype.onProgress = function(){
vjs.Player.prototype.onProgress = function(){
// Add custom event for when source is finished downloading.
if (this.bufferedPercent() == 1) {
this.trigger("loadedalldata");
@ -350,12 +346,12 @@ _V_.Player.prototype.onProgress = function(){
// Update duration with durationchange event
// Allows for cacheing value instead of asking player each time.
_V_.Player.prototype.onDurationChange = function(){
vjs.Player.prototype.onDurationChange = function(){
this.duration(this.techGet("duration"));
};
_V_.Player.prototype.onError = function(e) {
_V_.log("Video Error", e);
vjs.Player.prototype.onError = function(e) {
vjs.log("Video Error", e);
};
// /* Player API
@ -365,15 +361,14 @@ _V_.Player.prototype.onError = function(e) {
* Object for cached values.
* @private
*/
_V_.Player.prototype.cache_;
vjs.Player.prototype.cache_;
_V_.Player.prototype.getCache = function(){
vjs.Player.prototype.getCache = function(){
return this.cache_;
};
// Pass values to the playback tech
_V_.Player.prototype.techCall = function(method, arg){
vjs.Player.prototype.techCall = function(method, arg){
// If it's not ready yet, call method when it is
if (!this.tech.isReady_) {
this.tech.ready(function(){
@ -385,13 +380,13 @@ _V_.Player.prototype.techCall = function(method, arg){
try {
this.tech[method](arg);
} catch(e) {
_V_.log(e);
vjs.log(e);
}
}
};
// Get calls can't wait for the tech, and sometimes don't need to.
_V_.Player.prototype.techGet = function(method){
vjs.Player.prototype.techGet = function(method){
// Make sure tech is ready
if (this.tech.isReady_) {
@ -405,18 +400,18 @@ _V_.Player.prototype.techGet = function(method){
// When building additional tech libs, an expected method may not be defined yet
if (this.tech[method] === undefined) {
_V_.log("Video.js: " + method + " method not defined for "+this.techName+" playback technology.", e);
vjs.log("Video.js: " + method + " method not defined for "+this.techName+" playback technology.", e);
} else {
// When a method isn't available on the object it throws a TypeError
if (e.name == "TypeError") {
window['e'] = e
_V_.log("Video.js: " + method + " unavailable on "+this.techName+" playback technology element.", e);
vjs.log("Video.js: " + method + " unavailable on "+this.techName+" playback technology element.", e);
this.tech.isReady_ = false;
throw e;
} else {
_V_.log(e);
vjs.log(e);
}
}
}
@ -426,25 +421,25 @@ _V_.Player.prototype.techGet = function(method){
};
// http://dev.w3.org/html5/spec/video.html#dom-media-play
_V_.Player.prototype.play = function(){
vjs.Player.prototype.play = function(){
this.techCall("play");
return this;
};
// http://dev.w3.org/html5/spec/video.html#dom-media-pause
_V_.Player.prototype.pause = function(){
vjs.Player.prototype.pause = function(){
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)
_V_.Player.prototype.paused = function(){
vjs.Player.prototype.paused = function(){
return (this.techGet("paused") === false) ? false : true;
};
// http://dev.w3.org/html5/spec/video.html#dom-media-currenttime
_V_.Player.prototype.currentTime = function(seconds){
vjs.Player.prototype.currentTime = function(seconds){
if (seconds !== undefined) {
// Cache the last set value for smoother scrubbing.
@ -465,7 +460,7 @@ _V_.Player.prototype.currentTime = function(seconds){
// 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.
_V_.Player.prototype.duration = function(seconds){
vjs.Player.prototype.duration = function(seconds){
if (seconds !== undefined) {
// Cache the last set value for optimiized scrubbing (esp. Flash)
@ -478,14 +473,14 @@ _V_.Player.prototype.duration = function(seconds){
};
// Calculates how much time is left. Not in spec, but useful.
_V_.Player.prototype.remainingTime = function(){
vjs.Player.prototype.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)
_V_.Player.prototype.buffered = function(){
vjs.Player.prototype.buffered = function(){
var buffered = this.techGet("buffered"),
start = 0,
end = this.cache_.bufferEnd = this.cache_.bufferEnd || 0, // Default end to 0 and store in values
@ -497,23 +492,23 @@ _V_.Player.prototype.buffered = function(){
this.cache_.bufferEnd = end;
}
return _V_.createTimeRange(start, end);
return vjs.createTimeRange(start, end);
};
// Calculates amount of buffer is full. Not in spec but useful.
_V_.Player.prototype.bufferedPercent = function(){
vjs.Player.prototype.bufferedPercent = function(){
return (this.duration()) ? this.buffered().end(0) / this.duration() : 0;
};
// http://dev.w3.org/html5/spec/video.html#dom-media-volume
_V_.Player.prototype.volume = function(percentAsDecimal){
vjs.Player.prototype.volume = function(percentAsDecimal){
var vol;
if (percentAsDecimal !== undefined) {
vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1
this.cache_.volume = vol;
this.techCall("setVolume", vol);
_V_.setLocalStorage("volume", vol);
vjs.setLocalStorage("volume", vol);
return this;
}
@ -523,7 +518,7 @@ _V_.Player.prototype.volume = function(percentAsDecimal){
};
// http://dev.w3.org/html5/spec/video.html#attr-media-muted
_V_.Player.prototype.muted = function(muted){
vjs.Player.prototype.muted = function(muted){
if (muted !== undefined) {
this.techCall("setMuted", muted);
return this;
@ -532,11 +527,11 @@ _V_.Player.prototype.muted = function(muted){
};
// Check if current tech can support native fullscreen (e.g. with built in controls lik iOS, so not our flash swf)
_V_.Player.prototype.supportsFullScreen = function(){ return this.techGet("supportsFullScreen") || false; };
vjs.Player.prototype.supportsFullScreen = function(){ return this.techGet("supportsFullScreen") || false; };
// Turn on fullscreen (or window) mode
_V_.Player.prototype.requestFullScreen = function(){
var requestFullScreen = _V_.support.requestFullScreen;
vjs.Player.prototype.requestFullScreen = function(){
var requestFullScreen = vjs.support.requestFullScreen;
this.isFullScreen = true;
@ -544,12 +539,12 @@ _V_.Player.prototype.requestFullScreen = function(){
if (requestFullScreen) {
// Trigger fullscreenchange event after change
_V_.on(document, requestFullScreen.eventName, _V_.bind(this, function(){
vjs.on(document, requestFullScreen.eventName, vjs.bind(this, function(){
this.isFullScreen = document[requestFullScreen.isFullScreen];
// If cancelling fullscreen, remove event listener.
if (this.isFullScreen == false) {
_V_.off(document, requestFullScreen.eventName, arguments.callee);
vjs.off(document, requestFullScreen.eventName, arguments.callee);
}
this.trigger("fullscreenchange");
@ -557,13 +552,13 @@ _V_.Player.prototype.requestFullScreen = function(){
// Flash and other plugins get reloaded when you take their parent to fullscreen.
// To fix that we'll remove the tech, and reload it after the resize has finished.
if (window['_V_'][this.techName]['Supports']['fullscreenResize'] === false && this.options.flash.iFrameMode != true) {
if (this.tech.features.fullscreenResize === false && this.options.Flash.iFrameMode != true) {
this.pause();
this.unloadTech();
_V_.on(document, requestFullScreen.eventName, _V_.bind(this, function(){
_V_.off(document, requestFullScreen.eventName, arguments.callee);
vjs.on(document, requestFullScreen.eventName, vjs.bind(this, function(){
vjs.off(document, requestFullScreen.eventName, arguments.callee);
this.loadTech(this.techName, { src: this.cache_.src });
}));
@ -585,8 +580,8 @@ _V_.Player.prototype.requestFullScreen = function(){
return this;
};
_V_.Player.prototype.cancelFullScreen = function(){
var requestFullScreen = _V_.support.requestFullScreen;
vjs.Player.prototype.cancelFullScreen = function(){
var requestFullScreen = vjs.support.requestFullScreen;
this.isFullScreen = false;
@ -595,13 +590,13 @@ _V_.Player.prototype.cancelFullScreen = function(){
// Flash and other plugins get reloaded when you take their parent to fullscreen.
// To fix that we'll remove the tech, and reload it after the resize has finished.
if (window['_V_'][this.techName]['Supports']['fullscreenResize'] === false && this.options.flash.iFrameMode != true) {
if (this.tech.features.fullscreenResize === false && this.options.Flash.iFrameMode != true) {
this.pause();
this.unloadTech();
_V_.on(document, requestFullScreen.eventName, _V_.bind(this, function(){
_V_.off(document, requestFullScreen.eventName, arguments.callee);
vjs.on(document, requestFullScreen.eventName, vjs.bind(this, function(){
vjs.off(document, requestFullScreen.eventName, arguments.callee);
this.loadTech(this.techName, { src: this.cache_.src })
}));
@ -624,25 +619,25 @@ _V_.Player.prototype.cancelFullScreen = function(){
};
// When fullscreen isn't supported we can stretch the video container to as wide as the browser will let us.
_V_.Player.prototype.enterFullWindow = function(){
vjs.Player.prototype.enterFullWindow = function(){
this.isFullWindow = 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_.on(document, "keydown", _V_.bind(this, this.fullWindowOnEscKey));
vjs.on(document, "keydown", vjs.bind(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");
vjs.addClass(document.body, "vjs-full-window");
vjs.addClass(this.el_, "vjs-fullscreen");
this.trigger("enterFullWindow");
};
_V_.Player.prototype.fullWindowOnEscKey = function(event){
vjs.Player.prototype.fullWindowOnEscKey = function(event){
if (event.keyCode == 27) {
if (this.isFullScreen == true) {
this.cancelFullScreen();
@ -652,30 +647,28 @@ _V_.Player.prototype.fullWindowOnEscKey = function(event){
}
};
_V_.Player.prototype.exitFullWindow = function(){
vjs.Player.prototype.exitFullWindow = function(){
this.isFullWindow = false;
_V_.off(document, "keydown", this.fullWindowOnEscKey);
vjs.off(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");
vjs.removeClass(document.body, "vjs-full-window");
vjs.removeClass(this.el_, "vjs-fullscreen");
// Resize the box, controller, and poster to original sizes
// this.positionAll();
this.trigger("exitFullWindow");
};
_V_.Player.prototype.selectSource = function(sources){
vjs.Player.prototype.selectSource = function(sources){
// Loop through each playback technology in the options order
for (var i=0,j=this.options.techOrder;i<j.length;i++) {
var techName = _V_.capitalize(j[i]),
tech = window['_V_'][techName];
var techInfo = window['_V_'][j[i]];
for (var i=0,j=this.options['techOrder'];i<j.length;i++) {
var techName = vjs.capitalize(j[i]),
tech = window['videojs'][techName];
// Check if the browser supports this technology
if (tech.isSupported()) {
@ -699,7 +692,7 @@ _V_.Player.prototype.selectSource = function(sources){
// 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
_V_.Player.prototype.src = function(source){
vjs.Player.prototype.src = function(source){
// Case: Array of source objects to choose from and pick the best to play
if (source instanceof Array) {
@ -719,13 +712,13 @@ _V_.Player.prototype.src = function(source){
this.loadTech(techName, source);
}
} else {
_V_.log("No compatible source and media technology were found.")
vjs.log("No compatible source and media technology were found.")
}
// Case: Source object { src: "", type: "" ... }
} else if (source instanceof Object) {
if (window['_V_'][this.techName]['canPlaySource'](source)) {
if (window['videojs'][this.techName]['canPlaySource'](source)) {
this.src(source.src);
} else {
// Send through tech loop to check for a compatible technology.
@ -756,18 +749,18 @@ _V_.Player.prototype.src = function(source){
// Begin loading the src data
// http://dev.w3.org/html5/spec/video.html#dom-media-load
_V_.Player.prototype.load = function(){
vjs.Player.prototype.load = function(){
this.techCall("load");
return this;
};
// http://dev.w3.org/html5/spec/video.html#dom-media-currentsrc
_V_.Player.prototype.currentSrc = function(){
vjs.Player.prototype.currentSrc = function(){
return this.techGet("currentSrc") || this.cache_.src || "";
};
// Attributes/Options
_V_.Player.prototype.preload = function(value){
vjs.Player.prototype.preload = function(value){
if (value !== undefined) {
this.techCall("setPreload", value);
this.options.preload = value;
@ -775,7 +768,7 @@ _V_.Player.prototype.preload = function(value){
}
return this.techGet("preload");
};
_V_.Player.prototype.autoplay = function(value){
vjs.Player.prototype.autoplay = function(value){
if (value !== undefined) {
this.techCall("setAutoplay", value);
this.options.autoplay = value;
@ -783,7 +776,7 @@ _V_.Player.prototype.autoplay = function(value){
}
return this.techGet("autoplay", value);
};
_V_.Player.prototype.loop = function(value){
vjs.Player.prototype.loop = function(value){
if (value !== undefined) {
this.techCall("setLoop", value);
this.options.loop = value;
@ -792,10 +785,10 @@ _V_.Player.prototype.loop = function(value){
return this.techGet("loop");
};
_V_.Player.prototype.controls = function(){ return this.options.controls; };
_V_.Player.prototype.poster = function(){ return this.techGet("poster"); };
_V_.Player.prototype.error = function(){ return this.techGet("error"); };
_V_.Player.prototype.ended = function(){ return this.techGet("ended"); };
vjs.Player.prototype.controls = function(){ return this.options.controls; };
vjs.Player.prototype.poster = function(){ return this.techGet("poster"); };
vjs.Player.prototype.error = function(){ return this.techGet("error"); };
vjs.Player.prototype.ended = function(){ return this.techGet("ended"); };
// Methods to add support for
// networkState: function(){ return this.techCall("networkState"); },
@ -825,7 +818,7 @@ _V_.Player.prototype.ended = function(){ return this.techGet("ended"); };
cancelFn,
eventName,
isFullScreen,
playerProto = _V_.Player.prototype;
playerProto = vjs.Player.prototype;
// Current W3C Spec
// http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html#api
@ -863,7 +856,7 @@ _V_.Player.prototype.ended = function(){ return this.techGet("ended"); };
}
if (requestFn) {
_V_.support.requestFullScreen = {
vjs.support.requestFullScreen = {
requestFn: requestFn,
cancelFn: cancelFn,
eventName: eventName,
@ -876,17 +869,15 @@ _V_.Player.prototype.ended = function(){ return this.techGet("ended"); };
/**
* @constructor
*/
_V_.MediaLoader = function(player, options, ready){
_V_.Component.call(this, player, options, ready);
vjs.MediaLoader = function(player, options, ready){
vjs.Component.call(this, player, options, ready);
// If there are no sources when the player is initialized,
// load the first supported playback technology.
if (!player.options.sources || player.options.sources.length == 0) {
for (var i=0,j=player.options.techOrder; i<j.length; i++) {
var techName = _V_.capitalize(j[i]),
tech = window['_V_'][techName];
var techInfo = window['_V_'][j[i]];
for (var i=0,j=player.options['techOrder']; i<j.length; i++) {
var techName = vjs.capitalize(j[i]),
tech = window['videojs'][techName];
// Check if the browser supports this technology
if (tech && tech.isSupported()) {
@ -902,6 +893,6 @@ _V_.MediaLoader = function(player, options, ready){
player.src(player.options.sources);
}
};
goog.inherits(_V_.MediaLoader, _V_.Component);
goog.inherits(vjs.MediaLoader, vjs.Component);

View File

@ -1,5 +1,5 @@
// Automatically set up any tags that have a data-setup attribute
_V_.autoSetup = function(){
vjs.autoSetup = function(){
var options, vid, player,
vids = document.getElementsByTagName("video");
@ -17,40 +17,40 @@ _V_.autoSetup = function(){
if (vid.player === undefined) {
options = vid.getAttribute("data-setup");
// Check if data-setup attr exists.
// 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 || "{}");
options = vjs.JSON.parse(options || "{}");
// Create new video.js instance.
player = _V_(vid, options);
player = videojs(vid, options);
}
}
// If getAttribute isn't defined, we need to wait for the DOM.
} else {
_V_.autoSetupTimeout(1);
vjs.autoSetupTimeout(1);
break;
}
}
// No videos were found, so keep looping unless page is finisehd loading.
} else if (!_V_.windowLoaded) {
_V_.autoSetupTimeout(1);
} else if (!vjs.windowLoaded) {
vjs.autoSetupTimeout(1);
}
};
// Pause to let the DOM keep processing
_V_.autoSetupTimeout = function(wait){
setTimeout(_V_.autoSetup, wait);
vjs.autoSetupTimeout = function(wait){
setTimeout(vjs.autoSetup, wait);
};
_V_.addEvent(window, "load", function(){
_V_.windowLoaded = true;
vjs.one(window, "load", function(){
vjs.windowLoaded = true;
});
// Run Auto-load players
_V_.autoSetup();
vjs.autoSetup();

View File

@ -9,17 +9,19 @@
// Add an array of text tracks. captions, subtitles, chapters, descriptions
// Track objects will be stored in the player.textTracks array
_V_.Player.prototype.addTextTracks = function(trackObjects){
var tracks = this.textTracks = (this.textTracks) ? this.textTracks : [],
i = 0, j = trackObjects.length, track, Kind;
vjs.Player.prototype.addTextTracks = function(trackObjects){
var track, Kind,
tracks = this.textTracks = this.textTracks || [],
i = 0,
j = trackObjects.length;
for (;i<j;i++) {
// HTML5 Spec says default to subtitles.
// Uppercase (uc) first letter to match class names
Kind = _V_.capitalize(trackObjects[i].kind || "subtitles");
Kind = vjs.capitalize(trackObjects[i].kind || "subtitles");
// Create correct texttrack class. CaptionsTrack, etc.
track = new _V_[Kind + "Track"](this, trackObjects[i]);
track = new window['videojs'][Kind + "Track"](this, trackObjects[i]);
tracks.push(track);
@ -28,7 +30,7 @@ _V_.Player.prototype.addTextTracks = function(trackObjects){
// Incase there are mulitple defaulted tracks of the same kind
// Or the user has a set preference of a specific language that should override the default
if (track['default']) {
this.ready(_V_.bind(track, track.show));
this.ready(vjs.bind(track, track.show));
}
}
@ -38,7 +40,7 @@ _V_.Player.prototype.addTextTracks = function(trackObjects){
// Show a text track
// disableSameKind: disable all other tracks of the same kind. Value should be a track kind (captions, etc.)
_V_.Player.prototype.showTextTrack = function(id, disableSameKind){
vjs.Player.prototype.showTextTrack = function(id, disableSameKind){
var tracks = this.textTracks,
i = 0,
j = tracks.length,
@ -71,18 +73,18 @@ _V_.Player.prototype.showTextTrack = function(id, disableSameKind){
/**
* Track Class
* Contains track methods for loading, showing, parsing cues of tracks
* @param {_V_.Player|Object} player
* @param {vjs.Player|Object} player
* @param {Object=} options
* @constructor
*/
_V_.Track = function(player, options){
vjs.Track = function(player, options){
goog.base(this, player, options);
// Apply track info to track object
// Options will often be a track element
_V_.merge(this, {
vjs.merge(this, {
// Build ID if one doesn't exist
id: options.id || ("vjs_" + options.kind + "_" + options.language + "_" + _V_.guid++),
id: options.id || ("vjs_" + options.kind + "_" + options.language + "_" + vjs.guid++),
src: options.src,
@ -122,10 +124,10 @@ _V_.Track = function(player, options){
mode: 0
});
};
goog.inherits(_V_.Track, _V_.Component);
goog.inherits(vjs.Track, vjs.Component);
// Create basic div to hold cue text
_V_.Track.prototype.createEl = function(){
vjs.Track.prototype.createEl = function(){
return goog.base(this, 'createEl', "div", {
className: "vjs-" + this.kind + " vjs-text-track"
});
@ -139,7 +141,7 @@ _V_.Track.prototype.createEl = function(){
// and for text tracks whose kind is chapters, the user agent is making available to the user a mechanism by which the user can navigate to any point in the media resource by selecting a cue.
// The showing by default state is used in conjunction with the default attribute on track elements to indicate that the text track was enabled due to that attribute.
// This allows the user agent to override the state if a later track is discovered that is more appropriate per the user's preferences.
_V_.Track.prototype.show = function(){
vjs.Track.prototype.show = function(){
this.activate();
this.mode = 2;
@ -152,7 +154,7 @@ _V_.Track.prototype.show = function(){
// Indicates that the text track is active, but that the user agent is not actively displaying the cues.
// If no attempt has yet been made to obtain the track's cues, the user agent will perform such an attempt momentarily.
// The user agent is maintaining a list of which cues are active, and events are being fired accordingly.
_V_.Track.prototype.hide = function(){
vjs.Track.prototype.hide = function(){
// When hidden, cues are still triggered. Disable to stop triggering.
this.activate();
@ -165,7 +167,7 @@ _V_.Track.prototype.hide = function(){
// Disable: Mode Off/Disable (0)
// Indicates that the text track is not active. Other than for the purposes of exposing the track in the DOM, the user agent is ignoring the text track.
// No cues are active, no events are fired, and the user agent will not attempt to obtain the track's cues.
_V_.Track.prototype.disable = function(){
vjs.Track.prototype.disable = function(){
// If showing, hide.
if (this.mode == 2) { this.hide(); }
@ -177,7 +179,7 @@ _V_.Track.prototype.disable = function(){
};
// Turn on cue tracking. Tracks that are showing OR hidden are active.
_V_.Track.prototype.activate = function(){
vjs.Track.prototype.activate = function(){
// Load text file if it hasn't been yet.
if (this.readyState == 0) { this.load(); }
@ -185,23 +187,26 @@ _V_.Track.prototype.activate = function(){
if (this.mode == 0) {
// Update current cue on timeupdate
// Using unique ID for bind function so other tracks don't remove listener
this.player.on("timeupdate", _V_.bind(this, this.update, this.id));
this.player.on("timeupdate", vjs.bind(this, this.update, this.id));
// Reset cue time on media end
this.player.on("ended", _V_.bind(this, this.reset, this.id));
this.player.on("ended", vjs.bind(this, this.reset, this.id));
// Add to display
if (this.kind == "captions" || this.kind == "subtitles") {
console.log('adsf', this.player.childNameIndex_);
this.player.textTrackDisplay.addChild(this);
}
}
};
// Turn off cue tracking.
_V_.Track.prototype.deactivate = function(){
vjs.Track.prototype.deactivate = function(){
// Using unique ID for bind function so other tracks don't remove listener
this.player.off("timeupdate", _V_.bind(this, this.update, this.id));
this.player.off("ended", _V_.bind(this, this.reset, this.id));
this.player.off("timeupdate", vjs.bind(this, this.update, this.id));
this.player.off("ended", vjs.bind(this, this.reset, this.id));
this.reset(); // Reset
// Remove from display
@ -222,17 +227,18 @@ _V_.Track.prototype.deactivate = function(){
//
// Failed to load
// Indicates that the text track was enabled, but when the user agent attempted to obtain it, this failed in some way (e.g. URL could not be resolved, network error, unknown text track format). Some or all of the cues are likely missing and will not be obtained.
_V_.Track.prototype.load = function(){
vjs.Track.prototype.load = function(){
// Only load if not loaded yet.
if (this.readyState == 0) {
this.readyState = 1;
_V_.get(this.src, _V_.bind(this, this.parseCues), _V_.bind(this, this.onError));
console.log('track get method not supported yet')
// vjs.get(this.src, vjs.bind(this, this.parseCues), vjs.bind(this, this.onError));
}
};
_V_.Track.prototype.onError = function(err){
vjs.Track.prototype.onError = function(err){
this.error = err;
this.readyState = 3;
this.trigger("error");
@ -240,7 +246,7 @@ _V_.Track.prototype.onError = function(err){
// Parse the WebVTT text format for cue times.
// TODO: Separate parser into own class so alternative timed text formats can be used. (TTML, DFXP)
_V_.Track.prototype.parseCues = function(srcContent) {
vjs.Track.prototype.parseCues = function(srcContent) {
var cue, time, text,
lines = srcContent.split("\n"),
line = "", id;
@ -248,7 +254,7 @@ _V_.Track.prototype.parseCues = function(srcContent) {
for (var i=1, j=lines.length; i<j; i++) {
// Line 0 should be 'WEBVTT', so skipping i=0
line = _V_.trim(lines[i]); // Trim whitespace and linebreaks
line = vjs.trim(lines[i]); // Trim whitespace and linebreaks
if (line) { // Loop until a line with content
@ -257,7 +263,7 @@ _V_.Track.prototype.parseCues = function(srcContent) {
if (line.indexOf("-->") == -1) {
id = line;
// Advance to next line for timing.
line = _V_.trim(lines[++i]);
line = vjs.trim(lines[++i]);
} else {
id = this.cues.length;
}
@ -278,7 +284,7 @@ _V_.Track.prototype.parseCues = function(srcContent) {
// Loop until a blank line or end of lines
// Assumeing trim("") returns false for blank lines
while (lines[++i] && (line = _V_.trim(lines[i]))) {
while (lines[++i] && (line = vjs.trim(lines[i]))) {
text.push(line);
}
@ -294,7 +300,7 @@ _V_.Track.prototype.parseCues = function(srcContent) {
};
_V_.Track.prototype.parseCueTime = function(timeText) {
vjs.Track.prototype.parseCueTime = function(timeText) {
var parts = timeText.split(':'),
time = 0,
hours, minutes, other, seconds, ms, flags;
@ -335,7 +341,7 @@ _V_.Track.prototype.parseCueTime = function(timeText) {
};
// Update active cues whenever timeupdate events are triggered on the player.
_V_.Track.prototype.update = function(){
vjs.Track.prototype.update = function(){
if (this.cues.length > 0) {
// Get curent player time
@ -445,7 +451,7 @@ _V_.Track.prototype.update = function(){
};
// Add cue HTML to display
_V_.Track.prototype.updateDisplay = function(){
vjs.Track.prototype.updateDisplay = function(){
var cues = this.activeCues,
html = "",
i=0,j=cues.length;
@ -458,7 +464,7 @@ _V_.Track.prototype.updateDisplay = function(){
};
// Set all loop helper values back
_V_.Track.prototype.reset = function(){
vjs.Track.prototype.reset = function(){
this.nextChange = 0;
this.prevChange = this.player.duration();
this.firstActiveIndex = 0;
@ -469,36 +475,54 @@ _V_.Track.prototype.reset = function(){
/**
* @constructor
*/
_V_.CaptionsTrack = function(){};
goog.inherits(_V_.CaptionsTrack, _V_.Track);
_V_.CaptionsTrack.prototype.kind = "captions";
vjs.CaptionsTrack = function(player, options, ready){
goog.base(this, player, options, ready);
};
goog.inherits(vjs.CaptionsTrack, vjs.Track);
vjs.CaptionsTrack.prototype.kind = "captions";
// Exporting here because Track creation requires the track kind
// to be available on global object. e.g. new window['videojs'][Kind + 'Track']
/**
* @constructor
*/
_V_.SubtitlesTrack = function(){};
goog.inherits(_V_.SubtitlesTrack, _V_.Track);
_V_.SubtitlesTrack.prototype.kind = "subtitles";
vjs.SubtitlesTrack = function(player, options, ready){
goog.base(this, player, options, ready);
};
goog.inherits(vjs.SubtitlesTrack, vjs.Track);
vjs.SubtitlesTrack.prototype.kind = "subtitles";
/**
* @constructor
*/
_V_.ChaptersTrack = function(){};
goog.inherits(_V_.ChaptersTrack, _V_.Track);
_V_.ChaptersTrack.prototype.kind = "chapters";
vjs.ChaptersTrack = function(player, options, ready){
goog.base(this, player, options, ready);
};
goog.inherits(vjs.ChaptersTrack, vjs.Track);
vjs.ChaptersTrack.prototype.kind = "chapters";
/* Text Track Display
================================================================================ */
============================================================================= */
// Global container for both subtitle and captions text. Simple div container.
/**
* @constructor
*/
_V_.TextTrackDisplay = function()}{};
goog.inherits(_V_.TextTrackDisplay, _V_.Component);
vjs.TextTrackDisplay = function(player, options, ready){
goog.base(this, player, options, ready);
_V_.TextTrackDisplay.prototype.createEl = function(){
// This used to be called during player init, but was causing an error
// if a track should show by default and the display hadn't loaded yet.
// Should probably be moved to an external track loader when we support
// tracks that don't need a display.
if (player.options.tracks && player.options.tracks.length > 0) {
this.player.addTextTracks(options.tracks);
}
};
goog.inherits(vjs.TextTrackDisplay, vjs.Component);
vjs.TextTrackDisplay.prototype.createEl = function(){
return goog.base(this, 'createEl', "div", {
className: "vjs-text-track-display"
});
@ -506,11 +530,11 @@ _V_.TextTrackDisplay.prototype.createEl = function(){
/* Text Track Menu Items
================================================================================ */
============================================================================= */
/**
* @constructor
*/
_V_.TextTrackMenuItem = function(player, options){
vjs.TextTrackMenuItem = function(player, options){
var track = this.track = options.track;
// Modify options for parent MenuItem class's init.
@ -518,16 +542,16 @@ _V_.TextTrackMenuItem = function(player, options){
options.selected = track["default"];
goog.base(this, player, options);
this.player.on(track.kind + "trackchange", _V_.bind(this, this.update));
this.player.on(track.kind + "trackchange", vjs.bind(this, this.update));
};
goog.inherits(_V_.TextTrackMenuItem, _V_.MenuItem);
goog.inherits(vjs.TextTrackMenuItem, vjs.MenuItem);
_V_.TextTrackMenuItem.prototype.onClick = function(){
vjs.TextTrackMenuItem.prototype.onClick = function(){
goog.base(this, 'onClick');
this.player.showTextTrack(this.track.id, this.track.kind);
};
_V_.TextTrackMenuItem.prototype.update = function(){
vjs.TextTrackMenuItem.prototype.update = function(){
if (this.track.mode == 2) {
this.selected(true);
} else {
@ -538,20 +562,20 @@ _V_.TextTrackMenuItem.prototype.update = function(){
/**
* @constructor
*/
_V_.OffTextTrackMenuItem = function(player, options){
vjs.OffTextTrackMenuItem = function(player, options){
// Create pseudo track info
// Requires options.kind
options.track = { kind: options.kind, player: player, label: "Off" }
goog.base(this, player, options);
};
goog.inherits(_V_.OffTextTrackMenuItem, _V_.TextTrackMenuItem);
goog.inherits(vjs.OffTextTrackMenuItem, vjs.TextTrackMenuItem);
_V_.OffTextTrackMenuItem.prototype.onClick = function(){
vjs.OffTextTrackMenuItem.prototype.onClick = function(){
goog.base(this, 'onClick');
this.player.showTextTrack(this.track.id, this.track.kind);
};
_V_.OffTextTrackMenuItem.prototype.update = function(){
vjs.OffTextTrackMenuItem.prototype.update = function(){
var tracks = this.player.textTracks,
i=0, j=tracks.length, track,
off = true;
@ -575,7 +599,7 @@ _V_.OffTextTrackMenuItem.prototype.update = function(){
/**
* @constructor
*/
_V_.TextTrackButton = function(player, options){
vjs.TextTrackButton = function(player, options){
goog.base(this, player, options);
this.menu = this.createMenu();
@ -584,26 +608,26 @@ _V_.TextTrackButton = function(player, options){
this.hide();
}
};
goog.inherits(_V_.TextTrackButton, _V_.Button);
goog.inherits(vjs.TextTrackButton, vjs.Button);
_V_.TextTrackButton.prototype.createMenu = function(){
var menu = new _V_.Menu(this.player);
vjs.TextTrackButton.prototype.createMenu = function(){
var menu = new vjs.Menu(this.player);
// Add a title list item to the top
menu.el.appendChild(_V_.createElement("li", {
menu.el_.appendChild(vjs.createEl("li", {
className: "vjs-menu-title",
innerHTML: _V_.capitalize(this.kind)
innerHTML: vjs.capitalize(this.kind)
}));
// Add an OFF menu item to turn all tracks off
menu.addItem(new _V_.OffTextTrackMenuItem(this.player, { kind: this.kind }))
menu.addItem(new vjs.OffTextTrackMenuItem(this.player, { kind: this.kind }))
this.items = this.createItems();
// Add menu items to the menu
this.each(this.items, function(item){
menu.addItem(item);
});
for (var i = 0; i < this.items.length; i++) {
menu.addItem(this.items[i]);
};
// Add list to element
this.addChild(menu);
@ -612,41 +636,44 @@ _V_.TextTrackButton.prototype.createMenu = function(){
};
// Create a menu item for each text track
_V_.TextTrackButton.prototype.createItems = function(){
var items = [];
this.each(this.player.textTracks, function(track){
vjs.TextTrackButton.prototype.createItems = function(){
var items = [], track;
for (var i = 0; i < this.player.textTracks.length; i++) {
track = this.player.textTracks[i];
if (track.kind === this.kind) {
items.push(new _V_.TextTrackMenuItem(this.player, {
items.push(new vjs.TextTrackMenuItem(this.player, {
track: track
}));
}
});
};
return items;
};
_V_.TextTrackButton.prototype.buildCSSClass = function(){
vjs.TextTrackButton.prototype.buildCSSClass = function(){
return this.className + " vjs-menu-button " + goog.base(this, 'buildCSSClass');
};
// Focus - Add keyboard functionality to element
_V_.TextTrackButton.prototype.onFocus = function(){
vjs.TextTrackButton.prototype.onFocus = function(){
// Show the menu, and keep showing when the menu items are in focus
this.menu.lockShowing();
// this.menu.el.style.display = "block";
// this.menu.el_.style.display = "block";
// When tabbing through, the menu should hide when focus goes from the last menu item to the next tabbed element.
_V_.one(this.menu.el.childNodes[this.menu.el.childNodes.length - 1], "blur", _V_.bind(this, function(){
vjs.one(this.menu.el_.childNodes[this.menu.el_.childNodes.length - 1], "blur", vjs.bind(this, function(){
this.menu.unlockShowing();
}));
};
// Can't turn off list display that we turned on with focus, because list would go away.
_V_.TextTrackButton.prototype.onBlur = function(){};
vjs.TextTrackButton.prototype.onBlur = function(){};
_V_.TextTrackButton.prototype.onClick = function(){
vjs.TextTrackButton.prototype.onClick = function(){
// When you click the button it adds focus, which will show the menu indefinitely.
// So we'll remove focus when the mouse leaves the button.
// Focus is needed for tab navigation.
this.one("mouseout", _V_.bind(this, function(){
this.one("mouseout", vjs.bind(this, function(){
this.menu.unlockShowing();
this.el_.blur();
}));
@ -655,48 +682,55 @@ _V_.TextTrackButton.prototype.onClick = function(){
/**
* @constructor
*/
_V_.CaptionsButton = function(){};
goog.inherits(_V_.CaptionsButton, _V_.TextTrackButton);
_V_.CaptionsButton.prototype.kind = "captions";
_V_.CaptionsButton.prototype.buttonText = "Captions";
_V_.CaptionsButton.prototype.className = "vjs-captions-button";
vjs.CaptionsButton = function(player, options, ready){
goog.base(this, player, options, ready)
};
goog.inherits(vjs.CaptionsButton, vjs.TextTrackButton);
vjs.CaptionsButton.prototype.kind = "captions";
vjs.CaptionsButton.prototype.buttonText = "Captions";
vjs.CaptionsButton.prototype.className = "vjs-captions-button";
/**
* @constructor
*/
_V_.SubtitlesButton = function(){};
goog.inherits(_V_.SubtitlesButton, _V_.TextTrackButton);
_V_.SubtitlesButton.prototype.kind = "subtitles";
_V_.SubtitlesButton.prototype.buttonText = "Subtitles";
_V_.SubtitlesButton.prototype.className = "vjs-subtitles-button";
vjs.SubtitlesButton = function(player, options, ready){
goog.base(this, player, options, ready);
};
goog.inherits(vjs.SubtitlesButton, vjs.TextTrackButton);
vjs.SubtitlesButton.prototype.kind = "subtitles";
vjs.SubtitlesButton.prototype.buttonText = "Subtitles";
vjs.SubtitlesButton.prototype.className = "vjs-subtitles-button";
// Chapters act much differently than other text tracks
// Cues are navigation vs. other tracks of alternative languages
/**
* @constructor
*/
_V_.ChaptersButton = function(){};
goog.inherits(_V_.ChaptersButton, _V_.TextTrackButton);
_V_.ChaptersButton.prototype.kind = "chapters";
_V_.ChaptersButton.prototype.buttonText = "Chapters";
_V_.ChaptersButton.prototype.className = "vjs-chapters-button";
vjs.ChaptersButton = function(player, options, ready){
goog.base(this, player, options, ready);
};
goog.inherits(vjs.ChaptersButton, vjs.TextTrackButton);
vjs.ChaptersButton.prototype.kind = "chapters";
vjs.ChaptersButton.prototype.buttonText = "Chapters";
vjs.ChaptersButton.prototype.className = "vjs-chapters-button";
// Create a menu item for each text track
_V_.ChaptersButton.prototype.createItems = function(chaptersTrack){
var items = [];
vjs.ChaptersButton.prototype.createItems = function(chaptersTrack){
var items = [], track;
this.each(this.player.textTracks, function(track){
for (var i = 0; i < this.player.textTracks.length; i++) {;
track = this.player.textTracks[i];
if (track.kind === this.kind) {
items.push(new _V_.TextTrackMenuItem(this.player, {
items.push(new vjs.TextTrackMenuItem(this.player, {
track: track
}));
}
});
};
return items;
};
_V_.ChaptersButton.prototype.createMenu = function(){
vjs.ChaptersButton.prototype.createMenu = function(){
var tracks = this.player.textTracks,
i = 0,
j = tracks.length,
@ -708,7 +742,7 @@ _V_.ChaptersButton.prototype.createMenu = function(){
if (track.kind == this.kind && track["default"]) {
if (track.readyState < 2) {
this.chaptersTrack = track;
track.on("loaded", _V_.bind(this, this.createMenu));
track.on("loaded", vjs.bind(this, this.createMenu));
return;
} else {
chaptersTrack = track;
@ -717,11 +751,11 @@ _V_.ChaptersButton.prototype.createMenu = function(){
}
}
var menu = this.menu = new _V_.Menu(this.player);
var menu = this.menu = new vjs.Menu(this.player);
menu.el.appendChild(_V_.createElement("li", {
menu.el_.appendChild(vjs.createEl("li", {
className: "vjs-menu-title",
innerHTML: _V_.capitalize(this.kind)
innerHTML: vjs.capitalize(this.kind)
}));
if (chaptersTrack) {
@ -731,7 +765,7 @@ _V_.ChaptersButton.prototype.createMenu = function(){
for (;i<j;i++) {
cue = cues[i];
mi = new _V_.ChaptersTrackMenuItem(this.player, {
mi = new vjs.ChaptersTrackMenuItem(this.player, {
track: chaptersTrack,
cue: cue
});
@ -756,7 +790,7 @@ _V_.ChaptersButton.prototype.createMenu = function(){
/**
* @constructor
*/
_V_.ChaptersTrackMenuItem = function(player, options){
vjs.ChaptersTrackMenuItem = function(player, options){
var track = this.track = options.track,
cue = this.cue = options.cue,
currentTime = player.currentTime();
@ -766,21 +800,21 @@ _V_.ChaptersTrackMenuItem = function(player, options){
options.selected = (cue.startTime <= currentTime && currentTime < cue.endTime);
goog.base(this, player, options);
track.on("cuechange", _V_.bind(this, this.update));
track.on("cuechange", vjs.bind(this, this.update));
};
goog.inherits(_V_.ChaptersTrackMenuItem, _V_.MenuItem);
goog.inherits(vjs.ChaptersTrackMenuItem, vjs.MenuItem);
_V_.ChaptersTrackMenuItem.prototype.onClick = function(){
vjs.ChaptersTrackMenuItem.prototype.onClick = function(){
goog.base(this, 'onClick');
this.player.currentTime(this.cue.startTime);
this.update(this.cue.startTime);
};
_V_.ChaptersTrackMenuItem.prototype.update = function(time){
vjs.ChaptersTrackMenuItem.prototype.update = function(time){
var cue = this.cue,
currentTime = this.player.currentTime();
// _V_.log(currentTime, cue.startTime);
// vjs.log(currentTime, cue.startTime);
if (cue.startTime <= currentTime && currentTime < cue.endTime) {
this.selected(true);
} else {
@ -789,13 +823,13 @@ _V_.ChaptersTrackMenuItem.prototype.update = function(time){
};
// Add Buttons to controlBar
_V_.merge(_V_.ControlBar.prototype.options.children, {
vjs.merge(vjs.ControlBar.prototype.options.children, {
"subtitlesButton": {},
"captionsButton": {},
"chaptersButton": {}
});
// _V_.Cue = _V_.Component.extend({
// vjs.Cue = vjs.Component.extend({
// init: function(player, options){
// goog.base(this, player, options);
// }

View File

@ -87,7 +87,7 @@ _V_.flash = _V_.PlaybackTech.extend({
// Not sure why that even works, but it causes the browser to look like it's continuously trying to load the page.
// Firefox 3.6 keeps calling the iframe onload function anytime I write to it, causing an endless loop.
if (options.iFrameMode === true && !_V_.isFF) {
if (options.iFrameMode === true && !_V_.IS_FIREFOX) {
// Create iFrame with vjs-tech class so it's 100% width/height
var iFrm = _V_.createElement("iframe", {
@ -290,8 +290,8 @@ _V_.flash.prototype.support = {
},
// Optional events that we can manually mimic with timers
progressEvent: false,
timeupdateEvent: false,
progressEvents: false,
timeupdateEvents: false,
// Resizing plugins using request fullscreen reloads the plugin
fullscreenResize: false,
@ -387,7 +387,7 @@ _V_.flash.embed = function(swf, placeHolder, flashVars, params, attributes){
// IE6 seems to have an issue where it won't initialize the swf object after injecting it.
// This is a dumb temporary fix
if (_V_.isIE()) {
if (_V_.IS_IE6to8()) {
var newObj = par.childNodes[0];
setTimeout(function(){
newObj.style.display = "block";

View File

@ -253,7 +253,7 @@ _V_.vimeo.onFinish = function(id) {
player.vimeoInfo.state = VimeoState.ENDED;
player.triggerEvent("ended");
_V_.vimeo.hideOverlay(player);
// Vimeo looping doesn't seem to play well with VideoJS, so we need to
// implement it manually here
if (player.apiArgs.loop) {
@ -300,8 +300,8 @@ _V_.vimeo.prototype.support = {
},
// Optional events that we can manually mimic with timers
progressEvent: true,
timeupdateEvent: true,
progressEvents: true,
timeupdateEvents: true,
//fullscreen: true,
// In iOS, if you move a video element in the DOM, it breaks video playback.

View File

@ -104,7 +104,7 @@ _V_.youtube = _V_.PlaybackTech.extend({
src: function(src){
delete this.player.error;
// FIXME: Does this work or do we have to set the iFrame src again?
var videoId = this.getVideoId(src);
this.youtube.loadVideoById(videoId);
@ -227,7 +227,7 @@ _V_.youtube.onReady = function(e){
player.tech.triggerReady();
player.triggerReady();
player.triggerEvent("durationchange");
_V_.youtube.hideOverlay(player);
};
@ -247,7 +247,7 @@ _V_.youtube.onStateChange = function(e){
case YT.PlayerState.ENDED:
player.triggerEvent("ended");
_V_.youtube.hideOverlay(player);
// YouTube looping doesn't seem to play well with VideoJS, so we need to
// implement it manually here
if (player.apiArgs.playerVars.loop) {
@ -347,8 +347,8 @@ _V_.youtube.prototype.support = {
},
// Optional events that we can manually mimic with timers
progressEvent: false,
timeupdateEvent: false,
progressEvents: false,
timeupdateEvents: false,
//fullscreen: true,
// In iOS, if you move a video element in the DOM, it breaks video playback.