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

Updated closure compiler advanced mode branch

This commit is contained in:
Steve Heffernan 2013-01-10 13:06:12 -08:00
parent 428203c466
commit f267e27e36
43 changed files with 6375 additions and 2756 deletions

1
.gitignore vendored
View File

@ -6,4 +6,3 @@ projects
node_modules
npm-debug.log
closure-test

View File

@ -1,16 +1,23 @@
{
// Hopefully people are smart enough not to use eval
// But goog.base uses execScript so it throws an error.
// When compiled goog.base is stripped out completely.
"evil" : true,
"validthis": true,
"browser" : true,
"debug" : true,
"boss" : true,
"expr" : true,
"eqnull" : true,
"quotmark" : "double",
"quotmark" : "single",
"sub" : true,
"trailing" : true,
"undef" : true,
"laxbreak" : true,
"predef" : [ // Extra globals.
"_V_",
"VideoJS"
"videojs",
"vjs",
"goog"
]
}
}

View File

@ -1,8 +1,16 @@
[Video.js - HTML5 Video Player](http://videojs.com) [![Build Status](https://travis-ci.org/zencoder/video-js.png?branch=master)](https://travis-ci.org/zencoder/video-js)
[Video.js - HTML5 and Flash Video Player](http://videojs.com) [![Build Status](https://travis-ci.org/zencoder/video-js.png?branch=master)](https://travis-ci.org/zencoder/video-js)
==================================================
Visit the main site at [videojs.com](http://videojs.com) for download options and instructions.
Video.js was built to provide a fast and easy way to embed and work with video in a web page. It was built from the ground up with the assumption that HTML5 is the future of web video, however it supports Flash equally well for older browsers and for advanced features not yet supported in HTML5.
Some of the focuses of Video.js are:
- Universal browser and device support
- Easily skinned (themed/chromed) using just CSS
- A JavaScript API for controlling the video that works consistently across video platforms (HTML5, Flash, and others) as well as devices
- A common skin and API between HTML5, Flash, and potentially other players like YouTube
To build video-js from the latest version of the source, clone the source repository and run:
sh build.sh
in the video-js directory using the commnand-line/terminal of a unix-based system.

View File

@ -6,12 +6,12 @@ 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"']
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=test/video.compiled.js --create_source_map test/video.compiled.js.map --source_map_format=V3 --externs src/media.flash.externs.js --externs 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"']
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=test/unit/component.js --js=test/unit/lib.js --js=test/unit/events.js --js=test/unit/player.js --js=test/unit/setup.js --js=test/unit/core.js --formatting=pretty_print --js_output_file=test/video.test.compiled.js --create_source_map test/video.test.compiled.js.map --source_map_format=V3 --externs src/media.flash.externs.js --externs 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"

View File

@ -10,27 +10,25 @@
<script src="https://getfirebug.com/releases/lite/1.4/firebug-lite.js"></script>
<!--<![endif]-->
<script src="src/core.js"></script>
<script src="src/lib.js"></script>
<script src="src/json.js"></script>
<script src="src/component.js"></script>
<script src="src/player.js"></script>
<script src="src/tech.js"></script>
<script src="src/controls.js"></script>
<script src="src/events.js"></script>
<script src="src/tracks.js"></script>
<script src="tech/html5/html5.js"></script>
<script src="tech/flash/flash.js"></script>
<script src="src/setup.js"></script>
<script src='src/goog.base.js'></script>
<script src='src/core.js'></script>
<script src='src/lib.js'></script>
<script src='src/events.js'></script>
<script src='src/component.js'></script>
<script src='src/player.js'></script>
<script src='src/media.js'></script>
<script src='src/media.html5.js'></script>
<script src='src/media.flash.js'></script>
<script src='src/controls.js'></script>
<script src='src/tracks.js'></script>
<script src='src/setup.js'></script>
<script src='src/json.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";
videojs.options.techOrder = ["Flash"];
videojs.options.flash.swf = "tech/flash/video-js.swf";
}
</script>

View File

@ -76,16 +76,16 @@ myComponent.addChild('');
myPlayer.addChild('BigPlayButton');
myPlayer.removeChild('BigPlayButton');
myPlayer.getChild('BiPlayButton');
myPlayer.getChildren();
myPlayer.children();
myPlayer.getChildById('biPlayButton');
myPlayer.removeChildById('my-player-big-play-button');
getEl();
el();
getContentEl();
getChildren();
getParent();
#home_player_big-play-button
#home_player_big-play-button

View File

@ -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>
```

View File

@ -1,11 +1,8 @@
/**
* Player Component - Base class for all UI objects
* @fileoverview Player Component - Base class for all UI objects
*
*/
goog.provide('vjs.Component');
goog.require('vjs');
/**
* Base UI Component class
* @param {Object} player Main Player
@ -19,7 +16,7 @@ vjs.Component = function(player, options, ready){
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_" + vjs.guid++);
this.id_ = options.id || ((options.el && options.el.id) ? options.el.id : player.id + '_component_' + vjs.guid++ );
this.name_ = options.name || null;
@ -46,7 +43,7 @@ vjs.Component.prototype.dispose = function(){
if (this.children_) {
for (var i = this.children_.length - 1; i >= 0; i--) {
this.children_[i].dispose();
};
}
}
// Delete child references
@ -94,7 +91,7 @@ vjs.Component.prototype.createEl = function(tagName, attributes){
* Return the component's DOM element.
* @return {Element}
*/
vjs.Component.prototype.getEl = function(){
vjs.Component.prototype.el = function(){
return this.el_;
};
@ -109,7 +106,7 @@ vjs.Component.prototype.id_;
* Return the component's ID.
* @return {String}
*/
vjs.Component.prototype.getId = function(){
vjs.Component.prototype.id = function(){
return this.id_;
};
@ -124,7 +121,7 @@ vjs.Component.prototype.name_;
* Return the component's ID.
* @return {String}
*/
vjs.Component.prototype.getName = function(){
vjs.Component.prototype.name = function(){
return this.name_;
};
@ -139,9 +136,9 @@ vjs.Component.prototype.children_;
* Returns array of all child components.
* @return {Array}
*/
vjs.Component.prototype.getChildren = function(){
vjs.Component.prototype.children = function(){
return this.children_;
}
};
/**
* Object of child components by ID
@ -156,7 +153,7 @@ vjs.Component.prototype.childIndex_;
*/
vjs.Component.prototype.getChildById = function(id){
return this.childIndex_[id];
}
};
/**
* Object of child components by Name
@ -171,7 +168,7 @@ vjs.Component.prototype.childNameIndex_;
*/
vjs.Component.prototype.getChild = function(name){
return this.childNameIndex_[name];
}
};
/**
* Adds a child component inside this component.
@ -185,7 +182,7 @@ vjs.Component.prototype.addChild = function(child, options){
var component, componentClass, componentName, componentId;
// If string, create new component with options
if (typeof child === "string") {
if (typeof child === 'string') {
componentName = child;
@ -209,8 +206,8 @@ vjs.Component.prototype.addChild = function(child, options){
component = child;
}
componentName = component.getName();
componentId = component.getId();
componentName = component.name();
componentId = component.id();
this.children_.push(component);
@ -223,7 +220,7 @@ vjs.Component.prototype.addChild = function(child, options){
}
// Add the UI object's element to the container div (box)
this.el_.appendChild(component.getEl());
this.el_.appendChild(component.el());
// Return so it can stored on parent object if desired.
return component;
@ -243,16 +240,16 @@ vjs.Component.prototype.removeChild = function(component){
this.children_.splice(i,1);
break;
}
};
}
if (!childFound) return;
this.childIndex_[component.id] = null;
this.childNameIndex_[component.name] = null;
var compEl = component.getEl();
var compEl = component.el();
if (compEl && compEl.parentNode === this.el_) {
this.el_.removeChild(component.getEl());
this.el_.removeChild(component.el());
}
};
@ -289,8 +286,8 @@ vjs.Component.prototype.initChildren = function(){
vjs.Component.prototype.buildCSSClass = function(){
// Child classes can include a function that does:
// return "CLASS NAME" + this._super();
return "";
// return 'CLASS NAME' + this._super();
return '';
};
/* Events
@ -399,14 +396,14 @@ vjs.Component.prototype.triggerReady = function(){
if (readyQueue && readyQueue.length > 0) {
for (var i = 0, j = readyQueue.length; i < j; i++) {
readyQueue[i].call(this)
};
readyQueue[i].call(this);
}
// Reset Ready Queue
this.readyQueue_ = [];
// Allow for using event listeners also, in case you want to do something everytime a source is ready.
this.trigger("ready");
this.trigger('ready');
}
};
@ -438,7 +435,7 @@ vjs.Component.prototype.removeClass = function(classToRemove){
* @return {vjs.Component}
*/
vjs.Component.prototype.show = function(){
this.el_.style.display = "block";
this.el_.style.display = 'block';
return this;
};
@ -447,7 +444,7 @@ vjs.Component.prototype.show = function(){
* @return {vjs.Component}
*/
vjs.Component.prototype.hide = function(){
this.el_.style.display = "none";
this.el_.style.display = 'none';
return this;
};
@ -456,8 +453,8 @@ vjs.Component.prototype.hide = function(){
* @return {vjs.Component}
*/
vjs.Component.prototype.fadeIn = function(){
this.removeClass("vjs-fade-out");
this.addClass("vjs-fade-in");
this.removeClass('vjs-fade-out');
this.addClass('vjs-fade-in');
return this;
};
@ -466,8 +463,8 @@ vjs.Component.prototype.fadeIn = function(){
* @return {vjs.Component}
*/
vjs.Component.prototype.fadeOut = function(){
this.removeClass("vjs-fade-in");
this.addClass("vjs-fade-out");
this.removeClass('vjs-fade-in');
this.addClass('vjs-fade-out');
return this;
};
@ -477,9 +474,9 @@ vjs.Component.prototype.fadeOut = function(){
*/
vjs.Component.prototype.lockShowing = function(){
var style = this.el_.style;
style.display = "block";
style.display = 'block';
style.opacity = 1;
style.visiblity = "visible";
style.visiblity = 'visible';
return this;
};
@ -488,10 +485,10 @@ vjs.Component.prototype.lockShowing = function(){
* @return {vjs.Component}
*/
vjs.Component.prototype.unlockShowing = function(){
var style = this.el.style;
style.display = "";
style.opacity = "";
style.visiblity = "";
var style = this.el_.style;
style.display = '';
style.opacity = '';
style.visiblity = '';
return this;
};
@ -507,7 +504,7 @@ vjs.Component.prototype.unlockShowing = function(){
* Otherwise it returns the dimension.
*/
vjs.Component.prototype.width = function(num, skipListeners){
return this.dimension("width", num, skipListeners);
return this.dimension('width', num, skipListeners);
};
/**
@ -517,7 +514,7 @@ vjs.Component.prototype.width = function(num, skipListeners){
* @return {vjs.Component|Number|String} The player, or the dimension
*/
vjs.Component.prototype.height = function(num, skipListeners){
return this.dimension("height", num, skipListeners);
return this.dimension('height', num, skipListeners);
};
/**
@ -549,14 +546,14 @@ vjs.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
if (num !== undefined) {
// Check if using css width/height (% or px) and adjust
if ((""+num).indexOf("%") !== -1 || (""+num).indexOf("px") !== -1) {
if ((''+num).indexOf('%') !== -1 || (''+num).indexOf('px') !== -1) {
this.el_.style[widthOrHeight] = num;
} else {
this.el_.style[widthOrHeight] = num+"px";
this.el_.style[widthOrHeight] = num+'px';
}
// skipListeners allows us to avoid triggering the resize event when setting both width and height
if (!skipListeners) { this.trigger("resize"); }
if (!skipListeners) { this.trigger('resize'); }
// Return component
return this;
@ -568,7 +565,7 @@ vjs.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
// Get dimension value from style
var val = this.el_.style[widthOrHeight];
var pxIndex = val.indexOf("px");
var pxIndex = val.indexOf('px');
if (pxIndex !== -1) {
// Return the pixel value with no 'px'
return parseInt(val.slice(0,pxIndex), 10);
@ -585,7 +582,7 @@ vjs.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
// the percent value (e.g. '100%'')
// instead of zero like offsetWidth returns.
// var val = vjs.getComputedStyleValue(this.el_, widthOrHeight);
// var pxIndex = val.indexOf("px");
// var pxIndex = val.indexOf('px');
// if (pxIndex !== -1) {
// return val.slice(0, pxIndex);
@ -594,14 +591,3 @@ vjs.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
// }
}
};
// /* Utility
// ================================================================================ */
// vjs.Component.prototype.each = function(arr, fn){ vjs.each.call(this, arr, fn); };
// vjs.Component.prototype.eachProp = function(obj, fn){ vjs.eachProp.call(this, obj, fn); };
// vjs.Component.prototype.extend = function(obj){ vjs.merge(this, obj) };
// // More easily attach 'this' to functions
// vjs.Component.prototype.proxy = function(fn, uid){ return vjs.proxy(this, fn, uid); };

1233
src/controls.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,9 @@
// HTML5 Shiv. Must be in <head> to support older browsers.
document.createElement("video");document.createElement("audio");
/**
* @fileoverview Main function src. First file after goog.base.
*/
goog.provide('vjs');
// HTML5 Shiv. Must be in <head> to support older browsers.
document.createElement('video');document.createElement('audio');
/**
* Doubles as the main function for users to create a player instance and also
@ -17,10 +19,10 @@ vjs = function(id, options, ready){
// Allow for element or ID to be passed in
// String ID
if (typeof id == "string") {
if (typeof id === 'string') {
// Adjust for jQuery ID syntax
if (id.indexOf("#") === 0) {
if (id.indexOf('#') === 0) {
id = id.slice(1);
}
@ -30,7 +32,7 @@ vjs = function(id, options, ready){
// Otherwise get element for ID
} else {
tag = vjs.el(id)
tag = vjs.el(id);
}
// ID is a media element
@ -40,7 +42,7 @@ vjs = 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.
@ -48,12 +50,11 @@ vjs = function(id, options, ready){
return tag.player || new vjs.Player(tag, options, ready);
};
// Shortcut
// Extended name, also available externally, window.videojs
var videojs = vjs;
// videojs = vjs;
// CDN Version. Used to target right flash swf.
CDN_VERSION = "GENERATED_CDN_VSN";
var CDN_VERSION = 'GENERATED_CDN_VSN';
/**
* Global Player instance options
@ -63,11 +64,11 @@ CDN_VERSION = "GENERATED_CDN_VSN";
vjs.options = {
// Default order of fallback technology
'techOrder': ["html5","flash"],
// techOrder: ["flash","html5"],
'techOrder': ['html5','flash'],
// techOrder: ['flash','html5'],
'html5': {},
'flash': { swf: "http://vjs.zencdn.net/c/video-js.swf" },
'flash': { swf: 'http://vjs.zencdn.net/c/video-js.swf' },
// Default of web browser is 300x150. Should rely on source width/height.
'width': 300,
@ -77,14 +78,13 @@ vjs.options = {
'defaultVolume': 0.00, // The freakin seaguls are driving me crazy!
// Included control sets
// TODO: just use uppercase Class name
'children': {
"mediaLoader": {},
"posterImage": {},
// "textTrackDisplay": {},
"loadingSpinner": {},
"bigPlayButton": {},
"controlBar": {}
'mediaLoader': {},
'posterImage': {},
'textTrackDisplay': {},
'loadingSpinner': {},
'bigPlayButton': {},
'controlBar': {}
}
};
@ -96,6 +96,6 @@ vjs.players = {};
// Set CDN Version of swf
if (CDN_VERSION != "GENERATED_CDN_VSN") {
vjs.options.Flash.swf = "http://vjs.zencdn.net/"+CDN_VERSION+"/video-js.swf"
if (CDN_VERSION != 'GENERATED_CDN_VSN') {
videojs.options['flash']['swf'] = 'http://vjs.zencdn.net/'+CDN_VERSION+'/video-js.swf';
}

View File

@ -56,7 +56,7 @@ vjs.on = function(elem, type, fn){
if (document.addEventListener) {
elem.addEventListener(type, data.dispatcher, false);
} else if (document.attachEvent) {
elem.attachEvent("on" + type, data.dispatcher);
elem.attachEvent('on' + type, data.dispatcher);
}
}
};
@ -129,7 +129,7 @@ vjs.cleanUpEvents = function(elem, type) {
if (document.removeEventListener) {
elem.removeEventListener(type, data.dispatcher, false);
} else if (document.detachEvent) {
elem.detachEvent("on" + type, data.dispatcher);
elem.detachEvent('on' + type, data.dispatcher);
}
}
@ -250,7 +250,7 @@ vjs.trigger = function(elem, event) {
// handler;
// If an event name was passed as a string, creates an event out of it
if (typeof event === "string") {
if (typeof event === 'string') {
event = { type:event, target:elem };
}
// Normalizes the event properties.
@ -286,7 +286,7 @@ vjs.trigger = function(elem, event) {
* for now just in case.
*/
// // Added in attion to book. Book code was broke.
// event = typeof event === "object" ?
// event = typeof event === 'object' ?
// event[vjs.expando] ?
// event :
// new vjs.Event(type, event) :
@ -311,7 +311,7 @@ vjs.trigger = function(elem, event) {
*/
vjs.one = function(elem, type, fn) {
vjs.on(elem, type, function(){
vjs.off(elem, type, arguments.callee)
vjs.off(elem, type, arguments.callee);
fn.apply(this, arguments);
});
}
};

View File

@ -34,20 +34,20 @@ goog.exportSymbol('videojs.options', vjs.options);
goog.exportSymbol('videojs.cache', vjs.cache);
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.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('videojs.Player', vjs.Player);
@ -93,24 +93,27 @@ 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);
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(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.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']);
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']);
goog.exportSymbol('videojs.TextTrack', vjs.TextTrack);
goog.exportProperty(vjs.TextTrack.prototype, 'label', vjs.TextTrack.prototype.label);
goog.exportSymbol('videojs.CaptionsTrack', vjs.CaptionsTrack);
goog.exportSymbol('videojs.SubtitlesTrack', vjs.SubtitlesTrack);

View File

@ -426,9 +426,10 @@ goog.nullFunction = function() {};
* without type.
* @deprecated Use goog.functions.identity instead.
*/
goog.identityFunction = function(opt_returnValue, var_args) {
return opt_returnValue;
};
// Currently not used in Video.js and throwing jshint errors
// goog.identityFunction = function(opt_returnValue, var_args) {
// return opt_returnValue;
// };
/**
@ -458,18 +459,19 @@ goog.abstractMethod = function() {
* @param {!Function} ctor The constructor for the class to add the static
* method to.
*/
goog.addSingletonGetter = function(ctor) {
ctor.getInstance = function() {
if (ctor.instance_) {
return ctor.instance_;
}
if (goog.DEBUG) {
// NOTE: JSCompiler can't optimize away Array#push.
goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor;
}
return ctor.instance_ = new ctor;
};
};
// Currently not used in Video.js and throwing jshint errors
// goog.addSingletonGetter = function(ctor) {
// ctor.getInstance = function() {
// if (ctor.instance_) {
// return ctor.instance_;
// }
// if (goog.DEBUG) {
// // NOTE: JSCompiler can't optimize away Array#push.
// goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor;
// }
// return ctor.instance_ = new ctor;
// };
// };
/**
@ -1043,9 +1045,10 @@ goog.cloneObject = function(obj) {
* is deprecated because some people have declared a pure-JS version.
* Only the pure-JS version is truly deprecated.
*/
goog.bindNative_ = function(fn, selfObj, var_args) {
return /** @type {!Function} */ (fn.call.apply(fn.bind, arguments));
};
// Currently not used in Video.js and throwing errors
// goog.bindNative_ = function(fn, selfObj, var_args) {
// return /** @type {!Function} */ (fn.call.apply(fn.bind, arguments));
// };
/**
@ -1059,26 +1062,26 @@ goog.bindNative_ = function(fn, selfObj, var_args) {
* invoked as a method of.
* @private
*/
goog.bindJs_ = function(fn, selfObj, var_args) {
if (!fn) {
throw new Error();
}
// goog.bindJs_ = function(fn, selfObj, var_args) {
// if (!fn) {
// throw new Error();
// }
if (arguments.length > 2) {
var boundArgs = Array.prototype.slice.call(arguments, 2);
return function() {
// Prepend the bound arguments to the current arguments.
var newArgs = Array.prototype.slice.call(arguments);
Array.prototype.unshift.apply(newArgs, boundArgs);
return fn.apply(selfObj, newArgs);
};
// if (arguments.length > 2) {
// var boundArgs = Array.prototype.slice.call(arguments, 2);
// return function() {
// // Prepend the bound arguments to the current arguments.
// var newArgs = Array.prototype.slice.call(arguments);
// Array.prototype.unshift.apply(newArgs, boundArgs);
// return fn.apply(selfObj, newArgs);
// };
} else {
return function() {
return fn.apply(selfObj, arguments);
};
}
};
// } else {
// return function() {
// return fn.apply(selfObj, arguments);
// };
// }
// };
/**
@ -1104,23 +1107,23 @@ goog.bindJs_ = function(fn, selfObj, var_args) {
* invoked as a method of.
* @suppress {deprecated} See above.
*/
goog.bind = function(fn, selfObj, var_args) {
// TODO(nicksantos): narrow the type signature.
if (Function.prototype.bind &&
// NOTE(nicksantos): Somebody pulled base.js into the default
// Chrome extension environment. This means that for Chrome extensions,
// they get the implementation of Function.prototype.bind that
// calls goog.bind instead of the native one. Even worse, we don't want
// to introduce a circular dependency between goog.bind and
// Function.prototype.bind, so we have to hack this to make sure it
// works correctly.
Function.prototype.bind.toString().indexOf('native code') != -1) {
goog.bind = goog.bindNative_;
} else {
goog.bind = goog.bindJs_;
}
return goog.bind.apply(null, arguments);
};
// goog.bind = function(fn, selfObj, var_args) {
// // TODO(nicksantos): narrow the type signature.
// if (Function.prototype.bind &&
// // NOTE(nicksantos): Somebody pulled base.js into the default
// // Chrome extension environment. This means that for Chrome extensions,
// // they get the implementation of Function.prototype.bind that
// // calls goog.bind instead of the native one. Even worse, we don't want
// // to introduce a circular dependency between goog.bind and
// // Function.prototype.bind, so we have to hack this to make sure it
// // works correctly.
// Function.prototype.bind.toString().indexOf('native code') != -1) {
// goog.bind = goog.bindNative_;
// } else {
// goog.bind = goog.bindJs_;
// }
// return goog.bind.apply(null, arguments);
// };
/**
@ -1137,15 +1140,15 @@ goog.bind = function(fn, selfObj, var_args) {
* @return {!Function} A partially-applied form of the function bind() was
* invoked as a method of.
*/
goog.partial = function(fn, var_args) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
// Prepend the bound arguments to the current arguments.
var newArgs = Array.prototype.slice.call(arguments);
newArgs.unshift.apply(newArgs, args);
return fn.apply(this, newArgs);
};
};
// goog.partial = function(fn, var_args) {
// var args = Array.prototype.slice.call(arguments, 1);
// return function() {
// // Prepend the bound arguments to the current arguments.
// var newArgs = Array.prototype.slice.call(arguments);
// newArgs.unshift.apply(newArgs, args);
// return fn.apply(this, newArgs);
// };
// };
/**
@ -1186,38 +1189,39 @@ goog.now = Date.now || (function() {
* Throws an exception if neither execScript or eval is defined.
* @param {string} script JavaScript string.
*/
goog.globalEval = function(script) {
if (goog.global.execScript) {
goog.global.execScript(script, 'JavaScript');
} else if (goog.global.eval) {
// Test to see if eval works
if (goog.evalWorksForGlobals_ == null) {
goog.global.eval('var _et_ = 1;');
if (typeof goog.global['_et_'] != 'undefined') {
delete goog.global['_et_'];
goog.evalWorksForGlobals_ = true;
} else {
goog.evalWorksForGlobals_ = false;
}
}
// Currently not used in Video.js and throwing jshint errors
// goog.globalEval = function(script) {
// if (goog.global.execScript) {
// goog.global.execScript(script, 'JavaScript');
// } else if (goog.global.eval) {
// // Test to see if eval works
// if (goog.evalWorksForGlobals_ == null) {
// goog.global.eval('var _et_ = 1;');
// if (typeof goog.global['_et_'] != 'undefined') {
// delete goog.global['_et_'];
// goog.evalWorksForGlobals_ = true;
// } else {
// goog.evalWorksForGlobals_ = false;
// }
// }
if (goog.evalWorksForGlobals_) {
goog.global.eval(script);
} else {
var doc = goog.global.document;
var scriptElt = doc.createElement('script');
scriptElt.type = 'text/javascript';
scriptElt.defer = false;
// Note(user): can't use .innerHTML since "t('<test>')" will fail and
// .text doesn't work in Safari 2. Therefore we append a text node.
scriptElt.appendChild(doc.createTextNode(script));
doc.body.appendChild(scriptElt);
doc.body.removeChild(scriptElt);
}
} else {
throw Error('goog.globalEval not available');
}
};
// if (goog.evalWorksForGlobals_) {
// goog.global.eval(script);
// } else {
// var doc = goog.global.document;
// var scriptElt = doc.createElement('script');
// scriptElt.type = 'text/javascript';
// scriptElt.defer = false;
// // Note(user): can't use .innerHTML since "t('<test>')" will fail and
// // .text doesn't work in Safari 2. Therefore we append a text node.
// scriptElt.appendChild(doc.createTextNode(script));
// doc.body.appendChild(scriptElt);
// doc.body.removeChild(scriptElt);
// }
// } else {
// throw Error('goog.globalEval not available');
// }
// };
/**
@ -1407,9 +1411,9 @@ goog.getMsg = function(str, opt_values) {
* @param {string} b The fallback message.
* @return {string} The best translated message.
*/
goog.getMsgWithFallback = function(a, b) {
return a;
};
// goog.getMsgWithFallback = function(a, b) {
// return a;
// };
/**
@ -1486,7 +1490,7 @@ goog.exportProperty = function(object, publicName, symbol) {
*/
goog.inherits = function(childCtor, parentCtor) {
/** @constructor */
function tempCtor() {};
function tempCtor() {}
tempCtor.prototype = parentCtor.prototype;
childCtor.superClass_ = parentCtor.prototype;
childCtor.prototype = new tempCtor();
@ -1521,6 +1525,7 @@ goog.inherits = function(childCtor, parentCtor) {
* @return {*} The return value of the superclass method.
*/
goog.base = function(me, opt_methodName, var_args) {
var_args = var_args; // Hiding JSHint unused var warning without killing check
var caller = arguments.callee.caller;
if (caller.superClass_) {
// This is a constructor. Call the superclass constructor.

View File

@ -1,9 +1,9 @@
// Javascript JSON implementation
// (Parse Method Only)
// https://github.com/douglascrockford/JSON-js/blob/master/json2.js
/**
* JSON shim. Only using for parse method when parsing data-setup attribute JSON.
* Javascript JSON implementation
* (Parse Method Only)
* https://github.com/douglascrockford/JSON-js/blob/master/json2.js
* Only using for parse method when parsing data-setup attribute JSON.
* @type {Object}
*/
vjs.JSON;

View File

@ -12,7 +12,7 @@ vjs.createEl = function(tagName, properties){
el[propName] = properties[propName];
// Not remembering why we were checking for dash
// but using setAttribute means you have to use getAttribute
// if (propName.indexOf("-") !== -1) {
// if (propName.indexOf('-') !== -1) {
// el.setAttribute(propName, properties[propName]);
// } else {
// el[propName] = properties[propName];
@ -80,43 +80,19 @@ vjs.bind = function(context, fn, uid) {
// Create the new function that changes the context
var ret = function() {
return fn.apply(context, arguments);
}
};
// Allow for the ability to individualize this function
// Needed in the case where multiple objects might share the same prototype
// IF both items add an event listener with the same function, then you try to remove just one
// it will remove both because they both have the same guid.
// when using this, you need to use the bind method when you remove the listener as well.
ret.guid = (uid) ? uid + "_" + fn.guid : fn.guid;
// currently used in text tracks
ret.guid = (uid) ? uid + '_' + fn.guid : fn.guid;
return ret;
};
/**
* FROM CLOSURE LIB
* Like bind(), except that a 'this object' is not required. Useful when the
* target function is already bound.
*
* Usage:
* var g = partial(f, arg1, arg2);
* g(arg3, arg4);
*
* @param {Function} fn A function to partially apply.
* @param {...*} var_args Additional arguments that are partially
* applied to fn.
* @return {!Function} A partially-applied form of the function bind() was
* invoked as a method of.
*/
vjs.partial = function(fn, var_args) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
// Prepend the bound arguments to the current arguments.
var newArgs = Array.prototype.slice.call(arguments);
newArgs.unshift.apply(newArgs, args);
return fn.apply(this, newArgs);
};
};
/**
* Element Data Store. Allows for binding data to an element without putting it directly on the element.
* Ex. Event listneres are stored here.
@ -136,7 +112,7 @@ vjs.guid = 1;
* @type {String}
* @constant
*/
vjs.expando = "vdata" + (new Date).getTime();
vjs.expando = 'vdata' + (new Date()).getTime();
/**
* Returns the cache object where data for an element is stored
@ -204,8 +180,8 @@ vjs.isEmpty = function(obj) {
* @param {String} classToAdd Classname to add
*/
vjs.addClass = function(element, classToAdd){
if ((" "+element.className+" ").indexOf(" "+classToAdd+" ") == -1) {
element.className = element.className === "" ? classToAdd : element.className + " " + classToAdd;
if ((' '+element.className+' ').indexOf(' '+classToAdd+' ') == -1) {
element.className = element.className === '' ? classToAdd : element.className + ' ' + classToAdd;
}
};
@ -216,9 +192,9 @@ vjs.addClass = function(element, classToAdd){
*/
vjs.removeClass = function(element, classToRemove){
if (element.className.indexOf(classToRemove) == -1) { return; }
var classNames = element.className.split(" ");
var classNames = element.className.split(' ');
classNames.splice(classNames.indexOf(classToRemove),1);
element.className = classNames.join(" ");
element.className = classNames.join(' ');
};
/**
@ -226,7 +202,7 @@ vjs.removeClass = function(element, classToRemove){
* @type {Element}
* @constant
*/
vjs.TEST_VID = document.createElement("video");
vjs.TEST_VID = document.createElement('video');
/**
* Useragent for browser testing.
@ -259,11 +235,7 @@ vjs.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") };
vjs.IS_FIREFOX = function(){ return !!vjs.USER_AGENT.match('Firefox'); };
/**
@ -281,7 +253,7 @@ vjs.getAttributeValues = function(tag){
// We can check for matching boolean properties, but older browsers
// won't know about HTML5 boolean attributes that we still read from.
// Bookending with commas to allow for an easy string search.
var knownBooleans = ","+"autoplay,controls,loop,muted,default"+",";
var knownBooleans = ','+'autoplay,controls,loop,muted,default'+',';
if (tag && tag.attributes && tag.attributes.length > 0) {
var attrs = tag.attributes;
@ -293,15 +265,15 @@ vjs.getAttributeValues = function(tag){
// Check for known booleans
// The matching element property will return a value for typeof
if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(","+attrName+",") !== -1) {
// The value of an included boolean attribute is typically an empty string ("")
if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(','+attrName+',') !== -1) {
// The value of an included boolean attribute is typically an empty string ('')
// which would equal false if we just check for a false value.
// We also don't want support bad code like autoplay="false"
// We also don't want support bad code like autoplay='false'
attrVal = (attrVal !== null) ? true : false;
}
obj[attrName] = attrVal;
};
}
}
return obj;
@ -315,9 +287,9 @@ vjs.getAttributeValues = function(tag){
* @return {String} Style value
*/
vjs.getComputedStyleValue = function(el, strCssRule){
var strValue = "";
var strValue = '';
if(document.defaultView && document.defaultView.getComputedStyle){
strValue = document.defaultView.getComputedStyle(el, "").getPropertyValue(strCssRule);
strValue = document.defaultView.getComputedStyle(el, '').getPropertyValue(strCssRule);
} else if(el.currentStyle){
strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
@ -354,7 +326,7 @@ vjs.support = {};
* @return {Element} Element with supplied ID
*/
vjs.el = function(id){
if (id.indexOf("#") === 0) {
if (id.indexOf('#') === 0) {
id = id.slice(1);
}
@ -378,14 +350,14 @@ vjs.formatTime = function(seconds, guide) {
gh = Math.floor(guide / 3600);
// Check if we need to show hours
h = (h > 0 || gh > 0) ? h + ":" : "";
h = (h > 0 || gh > 0) ? h + ':' : '';
// If hours are showing, we may need to add a leading zero.
// Always show at least one digit of minutes.
m = (((h || gm >= 10) && m < 10) ? "0" + m : m) + ":";
m = (((h || gm >= 10) && m < 10) ? '0' + m : m) + ':';
// Check if leading zero is need for seconds
s = (s < 10) ? "0" + s : s;
s = (s < 10) ? '0' + s : s;
return h + m + s;
};
@ -404,7 +376,7 @@ vjs.unblockTextSelection = function(){ document.onselectstart = function () { re
* @return {String} Trimmed string
*/
vjs.trim = function(string){
return string.toString().replace(/^\s+/, "").replace(/\s+$/, "");
return string.toString().replace(/^\s+/, '').replace(/\s+$/, '');
};
/**
@ -435,67 +407,52 @@ vjs.createTimeRange = function(start, end){
};
};
// vjs.extend({
/**
* Simple http request for retrieving external files (e.g. text tracks)
* @param {String} url URL of resource
* @param {Function=} onSuccess Success callback
* @param {Function=} onError Error callback
*/
vjs.get = function(url, onSuccess, onError){
var local = (url.indexOf('file:') === 0 || (window.location.href.indexOf('file:') === 0 && url.indexOf('http') === -1));
// each: function(arr, fn){
// if (!arr || arr.length === 0) { return; }
// for (var i=0,j=arr.length; i<j; i++) {
// fn.call(this, arr[i], i);
// }
// },
if (typeof XMLHttpRequest === 'undefined') {
window.XMLHttpRequest = function () {
try { return new window.ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch (e) {}
try { return new window.ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch (f) {}
try { return new window.ActiveXObject('Msxml2.XMLHTTP'); } catch (g) {}
throw new Error('This browser does not support XMLHttpRequest.');
};
}
// // 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 - vjs.findPosX(relativeElement)) / relativeElement.offsetWidth));
// },
var request = new XMLHttpRequest();
// get: function(url, onSuccess, onError){
// // if (netscape.security.PrivilegeManager.enablePrivilege) {
// // netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
// // }
try {
request.open('GET', url);
} catch(e) {
onError(e);
}
// var local = (url.indexOf("file:") == 0 || (window.location.href.indexOf("file:") == 0 && url.indexOf("http:") == -1));
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200 || local && request.status === 0) {
onSuccess(request.responseText);
} else {
if (onError) {
onError();
}
}
}
};
// if (typeof XMLHttpRequest == "undefined") {
// XMLHttpRequest = function () {
// try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
// try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (f) {}
// try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (g) {}
// throw new Error("This browser does not support XMLHttpRequest.");
// };
// }
// var request = new XMLHttpRequest();
// try {
// request.open("GET", url);
// } catch(e) {
// vjs.log("VideoJS XMLHttpRequest (open)", e);
// // onError(e);
// return false;
// }
// request.onreadystatechange = vjs.proxy(this, function() {
// if (request.readyState == 4) {
// if (request.status == 200 || local && request.status == 0) {
// onSuccess(request.responseText);
// } else {
// if (onError) {
// onError();
// }
// }
// }
// });
// try {
// request.send();
// } catch(e) {
// vjs.log("VideoJS XMLHttpRequest (send)", e);
// if (onError) {
// onError(e);
// }
// }
// },
try {
request.send();
} catch(e) {
if (onError) {
onError(e);
}
}
};
/* Local Storage
================================================================================ */
@ -507,9 +464,9 @@ vjs.setLocalStorage = function(key, value){
localStorage[key] = value;
} catch(e) {
if (e.code == 22 || e.code == 1014) { // Webkit == 22 / Firefox == 1014
vjs.log("LocalStorage Full (VideoJS)", e);
vjs.log('LocalStorage Full (VideoJS)', e);
} else {
vjs.log("LocalStorage Error (VideoJS)", e);
vjs.log('LocalStorage Error (VideoJS)', e);
}
}
};
@ -533,25 +490,19 @@ vjs.getAbsoluteURL = function(url){
return url;
};
// usage: log('inside coolFunc', this, arguments);
// paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
// usage: log('inside coolFunc',this,arguments);
// http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
vjs.log = function(){
vjs.log.history = vjs.log.history || [];// store logs to an array for reference
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' ? vjs.log.apply.call(console.log, console, newarr) : console.log.apply(console, newarr));
if(window.console){
window.console.log(Array.prototype.slice.call(arguments));
}
};
// make it safe to use console.log always
(function(b){function c(){}for(var d="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,timeStamp,profile,profileEnd,time,timeEnd,trace,warn".split(","),a;a=d.pop();){b[a]=b[a]||c}})((function(){try
{console.log();return window.console;}catch(err){return window.console={};}})());
// Offset Left
// getBoundingClientRect technique from John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/
if ("getBoundingClientRect" in document.documentElement) {
if ('getBoundingClientRect' in document.documentElement) {
vjs.findPosX = function(el) {
var box;
@ -573,11 +524,11 @@ if ("getBoundingClientRect" in document.documentElement) {
vjs.findPosX = function(el) {
var curleft = el.offsetLeft;
// vjs.log(obj.className, obj.offsetLeft)
while(el = obj.offsetParent) {
if (el.className.indexOf("video-js") == -1) {
// 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"));
while(el = el.offsetParent) {
if (el.className.indexOf('video-js') == -1) {
// 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

@ -12,16 +12,16 @@ HTMLObjectElement.prototype.vjs_getProperty = function(name) {};
* @param {string} name
* @param {string|number} value
*/
HTMLObjectElement.prototype.vjs_setProperty = function(name, 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() {}
HTMLObjectElement.prototype.vjs_play = function() {};
HTMLObjectElement.prototype.vjs_pause = function() {};
HTMLObjectElement.prototype.vjs_load = function() {};
/**
* @param {string} src
*/
HTMLObjectElement.prototype.vjs_src = function(src) {}
HTMLObjectElement.prototype.vjs_src = function(src) {};

View File

@ -1,11 +1,9 @@
goog.provide('vjs.Flash');
goog.provide('vjs.media.flash');
/**
* @fileoverview 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
*/
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 {vjs.Player|Object} player
@ -22,10 +20,10 @@ vjs.Flash = function(player, options, ready){
parentEl = options.parentEl,
// Create a temporary element to be replaced by swf object
placeHolder = this.el_ = vjs.createEl("div", { id: player.getId() + "_temp_flash" }),
placeHolder = this.el_ = vjs.createEl('div', { id: player.id() + '_temp_flash' }),
// Generate ID for swf object
objId = player.getId()+"_flash_api",
objId = player.id()+'_flash_api',
// Store player options in local var for optimization
// TODO: switch to using player methods instead of options
@ -36,9 +34,9 @@ vjs.Flash = function(player, options, ready){
flashVars = vjs.merge({
// SWF Callback Functions
'readyFunction': "videojs.Flash.onReady",
'eventProxyFunction': "videojs.Flash.onEvent",
'errorEventProxyFunction': "videojs.Flash.onError",
'readyFunction': 'videojs.Flash.onReady',
'eventProxyFunction': 'videojs.Flash.onEvent',
'errorEventProxyFunction': 'videojs.Flash.onError',
// Player Settings
'autoplay': playerOptions.autoplay,
@ -50,8 +48,8 @@ vjs.Flash = function(player, options, ready){
// Merge default parames with ones passed in
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
'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
@ -103,20 +101,20 @@ vjs.Flash = function(player, options, ready){
if (options.iFrameMode === true && !vjs.IS_FIREFOX) {
// Create iFrame with vjs-tech class so it's 100% width/height
var iFrm = vjs.createEl("iframe", {
'id': objId + "_iframe",
'name': objId + "_iframe",
'className': "vjs-tech",
'scrolling': "no",
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
@ -124,32 +122,30 @@ vjs.Flash = function(player, options, ready){
// 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 = vjs.Flash.embed(options.swf, placeHolder, flashVars, params, attributes);
// (in onload)
// var temp = vjs.createEl("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('"+vjs.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.
vjs.on(iFrm, "load", vjs.bind(this, function(){
var iDoc, objTag, swfLoc,
iWin = iFrm.contentWindow,
varString = "";
vjs.on(iFrm, 'load', vjs.bind(this, function(){
var iDoc,
iWin = iFrm.contentWindow;
// The one working method I found was to use the iframe's document.write() to create the swf object
// This got around the security issue in all browsers except firefox.
// I did find a hack where if I call the iframe's window.location.href="", it would get around the security error
// 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 (vjs.USER_AGENT.match("Firefox")) {
// iWin.location.href = "";
// if (vjs.USER_AGENT.match('Firefox')) {
// iWin.location.href = '';
// }
// Get the iFrame's document depending on what the browser supports
@ -157,8 +153,8 @@ vjs.Flash = function(player, options, ready){
// Tried ensuring both document domains were the same, but they already were, so that wasn't the issue.
// Even tried adding /. that was mentioned in a browser security writeup
// document.domain = document.domain+"/.";
// iDoc.domain = document.domain+"/.";
// document.domain = document.domain+'/.';
// iDoc.domain = document.domain+'/.';
// Tried adding the object to the iframe doc's innerHTML. Security error in all browsers.
// iDoc.body.innerHTML = swfObjectHTML;
@ -185,23 +181,23 @@ vjs.Flash = function(player, options, ready){
tech.el = el;
// Now that the element is ready, make a click on the swf play the video
vjs.on(el, "click", tech.bind(tech.onClick));
vjs.on(el, 'click', tech.bind(tech.onClick));
// Make sure swf is actually ready. Sometimes the API isn't actually yet.
vjs.Flash.checkReady(tech);
});
// Create event listener for all swf events
iWin.events = vjs.bind(this.player, function(swfID, eventName, other){
iWin.events = vjs.bind(this.player, function(swfID, eventName){
var player = this;
if (player && player.techName == "flash") {
if (player && player.techName === 'flash') {
player.trigger(eventName);
}
});
// Create error listener for all swf errors
iWin.errors = vjs.bind(this.player, function(swfID, eventName){
vjs.log("Flash Error", eventName);
vjs.log('Flash Error', eventName);
});
}));
@ -223,11 +219,11 @@ vjs.Flash.prototype.dispose = function(){
vjs.Flash.prototype.play = function(){
this.el_.vjs_play();
}
};
vjs.Flash.prototype.pause = function(){
this.el_.vjs_pause();
}
};
vjs.Flash.prototype.src = function(src){
// Make sure source URL is abosolute.
@ -241,80 +237,78 @@ vjs.Flash.prototype.src = function(src){
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");
}
this.el_.vjs_getProperty('poster');
};
vjs.Flash.prototype.buffered = function(){
return vjs.createTimeRange(0, this.el_.vjs_getProperty("buffered"));
}
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
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(",");
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(',');
// 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); };
},
/**
* @this {*}
*/
var 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); };
}
;
/**
* @this {*}
*/
var 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 getters for read-only attributes
for (var i = 0; i < readOnly.length; i++) {
createGetter(readOnly[i]);
};
}
/* Flash Support Testing -------------------------------------------------------- */
vjs.Flash.isSupported = function(){
return vjs.Flash.version()[0] >= 10;
// return swfobject.hasFlashPlayerVersion("10");
// return swfobject.hasFlashPlayerVersion('10');
};
vjs.Flash.canPlaySource = function(srcObj){
if (srcObj.type in vjs.Flash.prototype.features.formats) { return "maybe"; }
if (srcObj.type in vjs.Flash.prototype.features.formats) { return 'maybe'; }
};
vjs.Flash.prototype.features = {
formats: {
"video/flv": "FLV",
"video/x-flv": "FLV",
"video/mp4": "MP4",
"video/m4v": "MP4"
'video/flv': 'FLV',
'video/x-flv': 'FLV',
'video/mp4': 'MP4',
'video/m4v': 'MP4'
},
// Optional events that we can manually mimic with timers
@ -326,7 +320,7 @@ vjs.Flash.prototype.features = {
fullscreenResize: false,
// Resizing plugins in Firefox always reloads the plugin (e.g. full window mode)
parentResize: !(vjs.USER_AGENT.match("Firefox"))
parentResize: !(vjs.USER_AGENT.match('Firefox'))
};
vjs.Flash['onReady'] = function(currSwf){
@ -344,7 +338,7 @@ vjs.Flash['onReady'] = function(currSwf){
tech.el_ = el;
// Now that the element is ready, make a click on the swf play the video
tech.on("click", tech.onClick);
tech.on('click', tech.onClick);
vjs.Flash.checkReady(tech);
};
@ -354,7 +348,7 @@ vjs.Flash['onReady'] = function(currSwf){
vjs.Flash.checkReady = function(tech){
// Check if API property exists
if (tech.getEl().vjs_getProperty) {
if (tech.el().vjs_getProperty) {
// If so, tell tech it's ready
tech.triggerReady();
@ -378,8 +372,8 @@ vjs.Flash['onEvent'] = function(swfID, eventName){
// Log errors from the swf
vjs.Flash['onError'] = function(swfID, err){
var player = vjs.el(swfID).player;
player.trigger("error");
vjs.log("Flash Error", err, swfID);
player.trigger('error');
vjs.log('Flash Error', err, swfID);
};
// Flash Version Check
@ -388,17 +382,17 @@ vjs.Flash.version = function(){
// IE
try {
version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
version = new window.ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
// other browsers
} catch(e) {
try {
if (navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){
version = (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1];
if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin){
version = (navigator.plugins['Shockwave Flash 2.0'] || navigator.plugins['Shockwave Flash']).description.replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
}
} catch(e) {}
} catch(err) {}
}
return version.split(",");
return version.split(',');
};
// Flash embedding method. Only used in non-iframe mode
@ -406,7 +400,7 @@ 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 = vjs.createEl("div", { innerHTML: code }).childNodes[0],
obj = vjs.createEl('div', { innerHTML: code }).childNodes[0],
par = placeHolder.parentNode
;
@ -414,13 +408,11 @@ vjs.Flash.embed = function(swf, placeHolder, flashVars, params, attributes){
placeHolder.parentNode.replaceChild(obj, placeHolder);
// IE6 seems to have an issue where it won't initialize the swf object after injecting it.
// This is a dumb temporary fix
if (vjs.IS_IE6to8()) {
var newObj = par.childNodes[0];
setTimeout(function(){
newObj.style.display = "block";
}, 1000);
}
// This is a dumb fix
var newObj = par.childNodes[0];
setTimeout(function(){
newObj.style.display = 'block';
}, 1000);
return obj;
@ -436,7 +428,7 @@ vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
// Convert flash vars to string
if (flashVars) {
vjs.eachProp(flashVars, function(key, val){
flashVarsString += (key + "=" + val + "&amp;");
flashVarsString += (key + '=' + val + '&amp;');
});
}
@ -444,8 +436,8 @@ vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
params = vjs.merge({
'movie': swf,
'flashvars': flashVarsString,
'allowScriptAccess': "always", // Required to talk to swf
'allowNetworking': "all" // All should be default, but having security issues.
'allowScriptAccess': 'always', // Required to talk to swf
'allowNetworking': 'all' // All should be default, but having security issues.
}, params);
// Create param tags string
@ -458,8 +450,8 @@ vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
'data': swf,
// Default to 100% width/height
'width': "100%",
'height': "100%"
'width': '100%',
'height': '100%'
}, attributes);

View File

@ -1,13 +1,7 @@
goog.provide('vjs.Html5');
goog.provide('vjs.media.html5');
goog.provide('vjs.Html5.Events');
goog.provide('vjs.Html5.isSupported');
goog.provide('vjs.Html5.canPlaySource');
/**
* @fileoverview HTML5 Media Controller - Wrapper for HTML5 Media API
*/
goog.require('vjs.MediaTechController');
/* HTML5 Media Controller - Wrapper for HTML5 Media API
============================================================================= */
/**
* HTML5 Media Controller - Wrapper for HTML5 Media API
* @param {vjs.Player|Object} player
@ -23,7 +17,7 @@ vjs.Html5 = function(player, options, ready){
// If the element source is already set, we may have missed the loadstart event, and want to trigger it.
// We don't want to set the source again and interrupt playback.
if (source && this.el_.currentSrc == source.src) {
player.trigger("loadstart");
player.trigger('loadstart');
// Otherwise set the source if one was provided.
} else if (source) {
@ -41,7 +35,7 @@ vjs.Html5 = function(player, options, ready){
}
});
this.on("click", this.onClick);
this.on('click', this.onClick);
this.setupTriggers();
@ -69,12 +63,12 @@ vjs.Html5.prototype.createEl = function(){
// If the original tag is still there, remove it.
if (el) {
player.getEl().removeChild(el);
player.el().removeChild(el);
}
newEl = vjs.createElement("video", {
id: el.id || player.id + "_html5_api",
className: el.className || "vjs-tech"
newEl = vjs.createElement('video', {
id: el.id || player.id + '_html5_api',
className: el.className || 'vjs-tech'
});
el = newEl;
@ -82,13 +76,13 @@ vjs.Html5.prototype.createEl = function(){
}
// Update specific tag settings, in case they were overridden
var attrs = ["autoplay","preload","loop","muted"];
var attrs = ['autoplay','preload','loop','muted'];
for (var i = attrs.length - 1; i >= 0; i--) {
var attr = attrs[i];
if (player.options[attr] !== null) {
el[attr] = player.options[attr];
}
};
}
return el;
// jenniisawesome = true;
@ -99,13 +93,13 @@ vjs.Html5.prototype.createEl = function(){
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));
};
}
};
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", vjs.getData(this.el_));
}
// console.log('removeTriggers', vjs.getData(this.el_));
};
vjs.Html5.prototype.eventHandler = function(e){
// console.log('eventHandler', e.type, e, this.el_)
@ -123,7 +117,7 @@ vjs.Html5.prototype.setCurrentTime = function(seconds){
try {
this.el_.currentTime = seconds;
} catch(e) {
vjs.log(e, "Video isn't ready. (Video.js)");
vjs.log(e, 'Video is not ready. (Video.js)');
// this.warning(VideoJS.warnings.videoNotReady);
}
};
@ -143,7 +137,7 @@ vjs.Html5.prototype.supportsFullScreen = function(){
if (typeof this.el_.webkitEnterFullScreen == 'function') {
// Seems to be broken in Chromium/Chrome && Safari in Leopard
if (!navigator.userAgent.match("Chrome") && !navigator.userAgent.match("Mac OS X 10.5")) {
if (!navigator.userAgent.match('Chrome') && !navigator.userAgent.match('Mac OS X 10.5')) {
return true;
}
}
@ -156,7 +150,7 @@ vjs.Html5.prototype.enterFullScreen = function(){
} catch (e) {
if (e.code == 11) {
// this.warning(VideoJS.warnings.videoNotReady);
vjs.log("Video.js: Video not ready.");
vjs.log('Video.js: Video not ready.');
}
}
};
@ -166,7 +160,7 @@ vjs.Html5.prototype.exitFullScreen = function(){
} catch (e) {
if (e.code == 11) {
// this.warning(VideoJS.warnings.videoNotReady);
vjs.log("Video.js: Video not ready.");
vjs.log('Video.js: Video not ready.');
}
}
};
@ -205,18 +199,18 @@ vjs.Html5.prototype.defaultMuted = function(){ return this.el_.defaultMuted; };
/* HTML5 Support Testing ---------------------------------------------------- */
vjs.Html5.isSupported = function(){
return !!document.createElement("video").canPlayType;
return !!document.createElement('video').canPlayType;
};
vjs.Html5.canPlaySource = function(srcObj){
return !!document.createElement("video").canPlayType(srcObj.type);
return !!document.createElement('video').canPlayType(srcObj.type);
// TODO: Check Type
// If no Type, check ext
// Check Media Type
};
// List of all HTML5 events (various uses).
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(",");
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 Feature detection and Device Fixes --------------------------------- //
@ -226,7 +220,7 @@ vjs.Html5.prototype.features = {
// http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html
// Seems to be broken in Chromium/Chrome && Safari in Leopard
fullscreen: (vjs.TEST_VID.webkitEnterFullScreen)
? ((!vjs.USER_AGENT.match("Chrome") && !vjs.USER_AGENT.match("Mac OS X 10.5")
? ((!vjs.USER_AGENT.match('Chrome') && !vjs.USER_AGENT.match('Mac OS X 10.5')
? true
: false))
: false,
@ -241,8 +235,8 @@ if (vjs.IS_ANDROID) {
// Override Android 2.2 and less canPlayType method which is broken
if (vjs.ANDROID_VERSION < 3) {
document.createElement("video").constructor.prototype.canPlayType = function(type){
return (type && type.toLowerCase().indexOf("video/mp4") != -1) ? "maybe" : "";
document.createElement('video').constructor.prototype.canPlayType = function(type){
return (type && type.toLowerCase().indexOf('video/mp4') != -1) ? 'maybe' : '';
};
}
}

View File

@ -1,10 +1,6 @@
goog.provide('vjs.media');
goog.provide('vjs.MediaTechController');
goog.require('vjs.Component');
/* Media Technology Controller - Base class for media playback technologies
================================================================================ */
/**
* @fileoverview Media Technology Controller - Base class for media playback technologies
*/
/**
* Base class for media (HTML5 Video, Flash) controllers
@ -16,9 +12,9 @@ vjs.MediaTechController = function(player, options, ready){
goog.base(this, player, options, ready);
// Make playback element clickable
// this.addEvent("click", this.proxy(this.onClick));
// this.addEvent('click', this.proxy(this.onClick));
// player.triggerEvent("techready");
// player.triggerEvent('techready');
};
goog.inherits(vjs.MediaTechController, vjs.Component);
@ -38,19 +34,22 @@ vjs.MediaTechController.prototype.onClick = function(){
}
};
vjs.media = {};
/**
* List of default API methods for any MediaTechController
* @type {String}
*/
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(",");
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
function createMethod(methodName){
return function(){
throw new Error('The "'+methodName+'" method is not available on the playback technology\'s API');
};
}
for (var i = vjs.media.ApiMethods.length - 1; i >= 0; i--) {
var methodName = vjs.media.ApiMethods[i];
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");
}
})(methodName);
};
vjs.MediaTechController.prototype[vjs.media.ApiMethods[i]] = createMethod(methodName);
}

View File

@ -1,9 +1,5 @@
goog.provide('vjs.Player');
goog.require('vjs.Component');
/**
* Main player class. Returned by vjs(id);
* Main player class. A player instance is returned by _V_(id);
* @param {Element} tag The original video tag used for configuring options
* @param {Object=} options Player options
* @param {Function=} ready Ready callback function
@ -25,28 +21,20 @@ vjs.Player = function(tag, options, ready){
// 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
vjs.Component.call(this, this, opts, ready);
this.on("ended", this.onEnded);
this.on("play", this.onPlay);
this.on("pause", this.onPause);
this.on("progress", this.onProgress);
this.on("durationchange", this.onDurationChange);
this.on("error", this.onError);
this.on('ended', this.onEnded);
this.on('play', this.onPlay);
this.on('pause', this.onPause);
this.on('progress', this.onProgress);
this.on('durationchange', this.onDurationChange);
this.on('error', this.onError);
// Make player easily findable by ID
vjs.players[this.id] = this;
vjs.players[this.id_] = this;
};
goog.inherits(vjs.Player, vjs.Component);
@ -54,7 +42,7 @@ vjs.Player.prototype.dispose = function(){
// this.isReady_ = false;
// Kill reference to this player
vjs.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; }
@ -70,8 +58,8 @@ vjs.Player.prototype.dispose = function(){
vjs.Player.prototype.getTagSettings = function(tag){
var options = {
sources: [],
tracks: []
'sources': [],
'tracks': []
};
vjs.merge(options, vjs.getAttributeValues(tag));
@ -88,15 +76,16 @@ vjs.Player.prototype.getTagSettings = function(tag){
// Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/
childName = child.nodeName.toLowerCase();
if (childName === "source") {
options.sources.push(vjs.getAttributeValues(child));
if (childName === 'source') {
options['sources'].push(vjs.getAttributeValues(child));
} else if (childName === "track") {
options.tracks.push(vjs.getAttributeValues(child));
} else if (childName === 'track') {
options['tracks'].push(vjs.getAttributeValues(child));
}
}
}
return options;
};
@ -106,12 +95,12 @@ vjs.Player.prototype.createEl = function(){
// Original tag settings stored in options
// now remove immediately so native controls don't flash.
tag.removeAttribute("controls");
tag.removeAttribute('controls');
// Poster will be handled by a manual <img>
tag.removeAttribute("poster");
tag.removeAttribute('poster');
// Remove width/height attrs from tag so CSS can make it 100% width/height
tag.removeAttribute("width");
tag.removeAttribute("height");
tag.removeAttribute('width');
tag.removeAttribute('height');
// Empty video tag sources and tracks so the built-in player doesn't use them also.
// This may not be fast enough to stop HTML5 browsers from reading the tags
// so we'll need to turn off any default tracks if we're manually doing
@ -119,14 +108,14 @@ vjs.Player.prototype.createEl = function(){
if (tag.hasChildNodes()) {
var nrOfChildNodes = tag.childNodes.length;
for (var i=0,j=tag.childNodes;i<nrOfChildNodes;i++) {
if (j[0].nodeName.toLowerCase() == "source" || j[0].nodeName.toLowerCase() == "track") {
if (j[0].nodeName.toLowerCase() == 'source' || j[0].nodeName.toLowerCase() == 'track') {
tag.removeChild(j[0]);
}
}
}
// Make sure tag ID exists
tag.id = tag.id || "vjs_video_" + vjs.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
@ -136,19 +125,19 @@ vjs.Player.prototype.createEl = function(){
// Update tag id/class for use as HTML5 playback tech
// Might think we should do this after embedding in container so .vjs-tech class
// doesn't flash 100% width/height, but class only applies with .video-js parent
tag.id += "_html5_api";
tag.className = "vjs-tech";
tag.id += '_html5_api';
tag.className = 'vjs-tech';
// Make player findable on elements
tag.player = el.player = this;
// Default state of video is paused
this.addClass("vjs-paused");
this.addClass('vjs-paused');
// Make box use width/height of tag, or default 300x150
// Enforce with CSS since width/height attrs don't work on divs
this.width(this.options.width, true); // (true) Skip resize listener on load
this.height(this.options.height, true);
this.width(this.options['width'], true); // (true) Skip resize listener on load
this.height(this.options['height'], true);
// Wrap video tag in div (el/box) container
if (tag.parentNode) {
@ -157,7 +146,7 @@ vjs.Player.prototype.createEl = function(){
vjs.insertFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup.
return el;
}
};
// /* Media Technology (tech)
// ================================================================================ */
@ -171,7 +160,7 @@ vjs.Player.prototype.loadTech = function(techName, source){
// If the first time loading, HTML5 tag will exist but won't be initialized
// So we need to remove it if we're not loading HTML5
} else if (techName !== "Html5" && this.tag) {
} else if (techName !== 'Html5' && this.tag) {
this.el_.removeChild(this.tag);
this.tag = null;
}
@ -193,14 +182,14 @@ vjs.Player.prototype.loadTech = function(techName, source){
if (!this.features.timeupdateEvents) {
this.player.manualTimeUpdatesOn();
}
}
};
// Grab tech-specific options from player options and add source and parent element to use.
var techOptions = vjs.merge({ source: source, parentEl: this.el_ }, this.options[techName.toLowerCase()])
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) {
techOptions.startTime = this.cache_.currentTime;
techOptions['startTime'] = this.cache_.currentTime;
}
this.cache_.src = source.src;
@ -212,29 +201,29 @@ vjs.Player.prototype.loadTech = function(techName, source){
this.tech.ready(techReady);
};
// vjs.Player.prototype.unloadTech = function(){
// this.tech.destroy();
vjs.Player.prototype.unloadTech = function(){
this.tech.dispose();
// // Turn off any manual progress or timeupdate tracking
// if (this.manualProgress) { this.manualProgressOff(); }
// Turn off any manual progress or timeupdate tracking
if (this.manualProgress) { this.manualProgressOff(); }
// if (this.manualTimeUpdates) { this.manualTimeUpdatesOff(); }
if (this.manualTimeUpdates) { this.manualTimeUpdatesOff(); }
// this.tech = false;
// };
this.tech = false;
};
// There's many issues around changing the size of a Flash (or other plugin) object.
// First is a plugin reload issue in Firefox that has been around for 11 years: https://bugzilla.mozilla.org/show_bug.cgi?id=90268
// 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){
// vjs.log("unloadingTech")
// vjs.log('unloadingTech')
// this.unloadTech();
// vjs.log("unloadedTech")
// vjs.log('unloadedTech')
// if (betweenFn) { betweenFn.call(); }
// vjs.log("LoadingTech")
// vjs.log('LoadingTech')
// this.loadTech(this.techName, { src: this.cache_.src })
// vjs.log("loadedTech")
// vjs.log('loadedTech')
// },
/* Fallbacks for unsupported event types
@ -247,13 +236,11 @@ vjs.Player.prototype.manualProgressOn = function(){
// Trigger progress watching when a source begins loading
this.trackProgress();
var techName = this.techName;
// Watch for a native progress event call on the tech element
// In HTML5, some older versions don't support the progress event
// So we're assuming they don't, and turning off manual progress if they do.
// As opposed to doing user agent detection
this.tech.one("progress", function(){
this.tech.one('progress', function(){
// Update known progress support for this playback technology
this.features.progressEvents = true;
@ -275,10 +262,10 @@ vjs.Player.prototype.trackProgress = function(){
// log(this.cache_.bufferEnd, this.buffered().end(0), this.duration())
/* TODO: update for multiple buffered regions */
if (this.cache_.bufferEnd < this.buffered().end(0)) {
this.trigger("progress");
this.trigger('progress');
} else if (this.bufferedPercent() == 1) {
this.stopTrackingProgress();
this.trigger("progress"); // Last update
this.trigger('progress'); // Last update
}
}), 500);
};
@ -288,12 +275,12 @@ vjs.Player.prototype.stopTrackingProgress = function(){ clearInterval(this.progr
vjs.Player.prototype.manualTimeUpdatesOn = function(){
this.manualTimeUpdates = true;
this.on("play", this.trackCurrentTime);
this.on("pause", this.stopTrackingCurrentTime);
this.on('play', this.trackCurrentTime);
this.on('pause', this.stopTrackingCurrentTime);
// timeupdate is also called by .currentTime whenever current time is set
// Watch for native timeupdate event
this.tech.one("timeupdate", function(){
this.tech.one('timeupdate', function(){
// Update known progress support for this playback technology
this.features.timeupdateEvents = true;
// Turn off manual progress tracking
@ -304,14 +291,14 @@ vjs.Player.prototype.manualTimeUpdatesOn = function(){
vjs.Player.prototype.manualTimeUpdatesOff = function(){
this.manualTimeUpdates = false;
this.stopTrackingCurrentTime();
this.off("play", this.trackCurrentTime);
this.off("pause", this.stopTrackingCurrentTime);
this.off('play', this.trackCurrentTime);
this.off('pause', this.stopTrackingCurrentTime);
};
vjs.Player.prototype.trackCurrentTime = function(){
if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); }
this.currentTimeInterval = setInterval(vjs.bind(this, function(){
this.trigger("timeupdate");
this.trigger('timeupdate');
}), 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
};
@ -321,37 +308,37 @@ vjs.Player.prototype.stopTrackingCurrentTime = function(){ clearInterval(this.cu
// /* Player event handlers (how the player reacts to certain events)
// ================================================================================ */
vjs.Player.prototype.onEnded = function(){
if (this.options.loop) {
if (this.options['loop']) {
this.currentTime(0);
this.play();
}
};
vjs.Player.prototype.onPlay = function(){
vjs.removeClass(this.el_, "vjs-paused");
vjs.addClass(this.el_, "vjs-playing");
vjs.removeClass(this.el_, 'vjs-paused');
vjs.addClass(this.el_, 'vjs-playing');
};
vjs.Player.prototype.onPause = function(){
vjs.removeClass(this.el_, "vjs-playing");
vjs.addClass(this.el_, "vjs-paused");
vjs.removeClass(this.el_, 'vjs-playing');
vjs.addClass(this.el_, 'vjs-paused');
};
vjs.Player.prototype.onProgress = function(){
// Add custom event for when source is finished downloading.
if (this.bufferedPercent() == 1) {
this.trigger("loadedalldata");
this.trigger('loadedalldata');
}
};
// Update duration with durationchange event
// Allows for cacheing value instead of asking player each time.
vjs.Player.prototype.onDurationChange = function(){
this.duration(this.techGet("duration"));
this.duration(this.techGet('duration'));
};
vjs.Player.prototype.onError = function(e) {
vjs.log("Video Error", e);
vjs.log('Video Error', e);
};
// /* Player API
@ -400,14 +387,13 @@ vjs.Player.prototype.techGet = function(method){
// When building additional tech libs, an expected method may not be defined yet
if (this.tech[method] === undefined) {
vjs.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
vjs.log("Video.js: " + method + " unavailable on "+this.techName+" playback technology element.", e);
if (e.name == 'TypeError') {
vjs.log('Video.js: ' + method + ' unavailable on '+this.techName+' playback technology element.', e);
this.tech.isReady_ = false;
throw e;
} else {
@ -422,20 +408,20 @@ vjs.Player.prototype.techGet = function(method){
// http://dev.w3.org/html5/spec/video.html#dom-media-play
vjs.Player.prototype.play = function(){
this.techCall("play");
this.techCall('play');
return this;
};
// http://dev.w3.org/html5/spec/video.html#dom-media-pause
vjs.Player.prototype.pause = function(){
this.techCall("pause");
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)
vjs.Player.prototype.paused = function(){
return (this.techGet("paused") === false) ? false : true;
return (this.techGet('paused') === false) ? false : true;
};
// http://dev.w3.org/html5/spec/video.html#dom-media-currenttime
@ -445,17 +431,17 @@ vjs.Player.prototype.currentTime = function(seconds){
// Cache the last set value for smoother scrubbing.
this.cache_.lastSetCurrentTime = seconds;
this.techCall("setCurrentTime", seconds);
this.techCall('setCurrentTime', seconds);
// Improve the accuracy of manual timeupdates
if (this.manualTimeUpdates) { this.trigger("timeupdate"); }
if (this.manualTimeUpdates) { this.trigger('timeupdate'); }
return this;
}
// Cache last currentTime and return
// Default to 0 seconds
return this.cache_.currentTime = (this.techGet("currentTime") || 0);
return this.cache_.currentTime = (this.techGet('currentTime') || 0);
};
// http://dev.w3.org/html5/spec/video.html#dom-media-duration
@ -478,13 +464,14 @@ vjs.Player.prototype.remainingTime = function(){
};
// 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.
// 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)
vjs.Player.prototype.buffered = function(){
var buffered = this.techGet("buffered"),
var buffered = this.techGet('buffered'),
start = 0,
end = this.cache_.bufferEnd = this.cache_.bufferEnd || 0, // Default end to 0 and store in values
timeRange;
// Default end to 0 and store in values
end = this.cache_.bufferEnd = this.cache_.bufferEnd || 0;
if (buffered && buffered.length > 0 && buffered.end(0) !== end) {
end = buffered.end(0);
@ -507,27 +494,27 @@ vjs.Player.prototype.volume = function(percentAsDecimal){
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);
vjs.setLocalStorage("volume", vol);
this.techCall('setVolume', vol);
vjs.setLocalStorage('volume', vol);
return this;
}
// Default to 1 when returning current volume.
vol = parseFloat(this.techGet("volume"));
vol = parseFloat(this.techGet('volume'));
return (isNaN(vol)) ? 1 : vol;
};
// http://dev.w3.org/html5/spec/video.html#attr-media-muted
vjs.Player.prototype.muted = function(muted){
if (muted !== undefined) {
this.techCall("setMuted", muted);
this.techCall('setMuted', muted);
return this;
}
return this.techGet("muted") || false; // Default to false
return this.techGet('muted') || false; // Default to false
};
// Check if current tech can support native fullscreen (e.g. with built in controls lik iOS, so not our flash swf)
vjs.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
vjs.Player.prototype.requestFullScreen = function(){
@ -543,16 +530,16 @@ vjs.Player.prototype.requestFullScreen = function(){
this.isFullScreen = document[requestFullScreen.isFullScreen];
// If cancelling fullscreen, remove event listener.
if (this.isFullScreen == false) {
if (this.isFullScreen === false) {
vjs.off(document, requestFullScreen.eventName, arguments.callee);
}
this.trigger("fullscreenchange");
this.trigger('fullscreenchange');
}));
// 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 (this.tech.features.fullscreenResize === false && this.options.Flash.iFrameMode != true) {
if (this.tech.features.fullscreenResize === false && this.options['flash']['iFrameMode'] !== true) {
this.pause();
this.unloadTech();
@ -569,11 +556,11 @@ vjs.Player.prototype.requestFullScreen = function(){
}
} else if (this.tech.supportsFullScreen()) {
this.trigger("fullscreenchange");
this.techCall("enterFullScreen");
this.trigger('fullscreenchange');
this.techCall('enterFullScreen');
} else {
this.trigger("fullscreenchange");
this.trigger('fullscreenchange');
this.enterFullWindow();
}
@ -590,14 +577,14 @@ vjs.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 (this.tech.features.fullscreenResize === false && this.options.Flash.iFrameMode != true) {
if (this.tech.features.fullscreenResize === false && this.options['flash']['iFrameMode'] !== true) {
this.pause();
this.unloadTech();
vjs.on(document, requestFullScreen.eventName, vjs.bind(this, function(){
vjs.off(document, requestFullScreen.eventName, arguments.callee);
this.loadTech(this.techName, { src: this.cache_.src })
this.loadTech(this.techName, { src: this.cache_.src });
}));
document[requestFullScreen.cancelFn]();
@ -607,12 +594,12 @@ vjs.Player.prototype.cancelFullScreen = function(){
}
} else if (this.tech.supportsFullScreen()) {
this.techCall("exitFullScreen");
this.trigger("fullscreenchange");
this.techCall('exitFullScreen');
this.trigger('fullscreenchange');
} else {
this.exitFullWindow();
this.trigger("fullscreenchange");
this.trigger('fullscreenchange');
}
return this;
@ -626,20 +613,20 @@ vjs.Player.prototype.enterFullWindow = function(){
this.docOrigOverflow = document.documentElement.style.overflow;
// Add listener for esc key to exit fullscreen
vjs.on(document, "keydown", vjs.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
vjs.addClass(document.body, "vjs-full-window");
vjs.addClass(this.el_, "vjs-fullscreen");
vjs.addClass(document.body, 'vjs-full-window');
vjs.addClass(this.el_, 'vjs-fullscreen');
this.trigger("enterFullWindow");
this.trigger('enterFullWindow');
};
vjs.Player.prototype.fullWindowOnEscKey = function(event){
if (event.keyCode == 27) {
if (this.isFullScreen == true) {
if (event.keyCode === 27) {
if (this.isFullScreen === true) {
this.cancelFullScreen();
} else {
this.exitFullWindow();
@ -649,18 +636,18 @@ vjs.Player.prototype.fullWindowOnEscKey = function(event){
vjs.Player.prototype.exitFullWindow = function(){
this.isFullWindow = false;
vjs.off(document, "keydown", this.fullWindowOnEscKey);
vjs.off(document, 'keydown', this.fullWindowOnEscKey);
// Unhide scroll bars.
document.documentElement.style.overflow = this.docOrigOverflow;
// Remove fullscreen styles
vjs.removeClass(document.body, "vjs-full-window");
vjs.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");
this.trigger('exitFullWindow');
};
vjs.Player.prototype.selectSource = function(sources){
@ -697,7 +684,6 @@ vjs.Player.prototype.src = function(source){
if (source instanceof Array) {
var sourceTech = this.selectSource(source),
source,
techName;
if (sourceTech) {
@ -712,10 +698,10 @@ vjs.Player.prototype.src = function(source){
this.loadTech(techName, source);
}
} else {
vjs.log("No compatible source and media technology were found.")
vjs.log('No compatible source and media technology were found.');
}
// Case: Source object { src: "", type: "" ... }
// Case: Source object { src: '', type: '' ... }
} else if (source instanceof Object) {
if (window['videojs'][this.techName]['canPlaySource'](source)) {
@ -735,11 +721,11 @@ vjs.Player.prototype.src = function(source){
this.src(source);
});
} else {
this.techCall("src", source);
if (this.options.preload == "auto") {
this.techCall('src', source);
if (this.options['preload'] == 'auto') {
this.load();
}
if (this.options.autoplay) {
if (this.options['autoplay']) {
this.play();
}
}
@ -750,63 +736,63 @@ vjs.Player.prototype.src = function(source){
// Begin loading the src data
// http://dev.w3.org/html5/spec/video.html#dom-media-load
vjs.Player.prototype.load = function(){
this.techCall("load");
this.techCall('load');
return this;
};
// http://dev.w3.org/html5/spec/video.html#dom-media-currentsrc
vjs.Player.prototype.currentSrc = function(){
return this.techGet("currentSrc") || this.cache_.src || "";
return this.techGet('currentSrc') || this.cache_.src || '';
};
// Attributes/Options
vjs.Player.prototype.preload = function(value){
if (value !== undefined) {
this.techCall("setPreload", value);
this.options.preload = value;
this.techCall('setPreload', value);
this.options['preload'] = value;
return this;
}
return this.techGet("preload");
return this.techGet('preload');
};
vjs.Player.prototype.autoplay = function(value){
if (value !== undefined) {
this.techCall("setAutoplay", value);
this.options.autoplay = value;
this.techCall('setAutoplay', value);
this.options['autoplay'] = value;
return this;
}
return this.techGet("autoplay", value);
return this.techGet('autoplay', value);
};
vjs.Player.prototype.loop = function(value){
if (value !== undefined) {
this.techCall("setLoop", value);
this.options.loop = value;
this.techCall('setLoop', value);
this.options['loop'] = value;
return this;
}
return this.techGet("loop");
return this.techGet('loop');
};
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"); };
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"); },
// readyState: function(){ return this.techCall("readyState"); },
// seeking: function(){ return this.techCall("seeking"); },
// initialTime: function(){ return this.techCall("initialTime"); },
// startOffsetTime: function(){ return this.techCall("startOffsetTime"); },
// played: function(){ return this.techCall("played"); },
// seekable: function(){ return this.techCall("seekable"); },
// videoTracks: function(){ return this.techCall("videoTracks"); },
// audioTracks: function(){ return this.techCall("audioTracks"); },
// videoWidth: function(){ return this.techCall("videoWidth"); },
// videoHeight: function(){ return this.techCall("videoHeight"); },
// defaultPlaybackRate: function(){ return this.techCall("defaultPlaybackRate"); },
// playbackRate: function(){ return this.techCall("playbackRate"); },
// mediaGroup: function(){ return this.techCall("mediaGroup"); },
// controller: function(){ return this.techCall("controller"); },
// defaultMuted: function(){ return this.techCall("defaultMuted"); }
// networkState: function(){ return this.techCall('networkState'); },
// readyState: function(){ return this.techCall('readyState'); },
// seeking: function(){ return this.techCall('seeking'); },
// initialTime: function(){ return this.techCall('initialTime'); },
// startOffsetTime: function(){ return this.techCall('startOffsetTime'); },
// played: function(){ return this.techCall('played'); },
// seekable: function(){ return this.techCall('seekable'); },
// videoTracks: function(){ return this.techCall('videoTracks'); },
// audioTracks: function(){ return this.techCall('audioTracks'); },
// videoWidth: function(){ return this.techCall('videoWidth'); },
// videoHeight: function(){ return this.techCall('videoHeight'); },
// defaultPlaybackRate: function(){ return this.techCall('defaultPlaybackRate'); },
// playbackRate: function(){ return this.techCall('playbackRate'); },
// mediaGroup: function(){ return this.techCall('mediaGroup'); },
// controller: function(){ return this.techCall('controller'); },
// defaultMuted: function(){ return this.techCall('defaultMuted'); }
// TODO
// currentSrcList: the array of sources including other formats and bitrates
@ -814,20 +800,16 @@ vjs.Player.prototype.ended = function(){ return this.techGet("ended"); };
// RequestFullscreen API
(function(){
var requestFn,
cancelFn,
eventName,
isFullScreen,
playerProto = vjs.Player.prototype;
var requestFn, cancelFn, eventName, isFullScreen;
// Current W3C Spec
// http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html#api
// Mozilla Draft: https://wiki.mozilla.org/Gecko:FullScreenAPI#fullscreenchange_event
if (document.cancelFullscreen !== undefined) {
requestFn = "requestFullscreen";
cancelFn = "exitFullscreen";
eventName = "fullscreenchange";
isFullScreen = "fullScreen";
requestFn = 'requestFullscreen';
cancelFn = 'exitFullscreen';
eventName = 'fullscreenchange';
isFullScreen = 'fullScreen';
// Webkit (Chrome/Safari) and Mozilla (Firefox) have working implementaitons
// that use prefixes and vary slightly from the new W3C spec. Specifically, using 'exit' instead of 'cancel',
@ -835,24 +817,24 @@ vjs.Player.prototype.ended = function(){ return this.techGet("ended"); };
// Other browsers don't have any hints of which version they might follow yet, so not going to try to predict by loopeing through all prefixes.
} else {
var prefixes = ["moz", "webkit"];
var prefixes = ['moz', 'webkit'];
for (var i = prefixes.length - 1; i >= 0; i--) {
var prefix = prefixes[i]
var prefix = prefixes[i];
// https://github.com/zencoder/video-js/pull/128
if ((prefix != "moz" || document.mozFullScreenEnabled) && document[prefix + "CancelFullScreen"] !== undefined) {
requestFn = prefix + "RequestFullScreen";
cancelFn = prefix + "CancelFullScreen";
eventName = prefix + "fullscreenchange";
if ((prefix != 'moz' || document.mozFullScreenEnabled) && document[prefix + 'CancelFullScreen'] !== undefined) {
requestFn = prefix + 'RequestFullScreen';
cancelFn = prefix + 'CancelFullScreen';
eventName = prefix + 'fullscreenchange';
if (prefix == "webkit") {
isFullScreen = prefix + "IsFullScreen";
if (prefix == 'webkit') {
isFullScreen = prefix + 'IsFullScreen';
} else {
isFullScreen = prefix + "FullScreen";
isFullScreen = prefix + 'FullScreen';
}
}
};
}
}
if (requestFn) {
@ -874,7 +856,7 @@ vjs.MediaLoader = function(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) {
if (!player.options['sources'] || player.options['sources'].length === 0) {
for (var i=0,j=player.options['techOrder']; i<j.length; i++) {
var techName = vjs.capitalize(j[i]),
tech = window['videojs'][techName];
@ -890,7 +872,7 @@ vjs.MediaLoader = function(player, options, ready){
// // Then load the best source.
// // A few assumptions here:
// // All playback technologies respect preload false.
player.src(player.options.sources);
player.src(player.options['sources']);
}
};
goog.inherits(vjs.MediaLoader, vjs.Component);

View File

@ -1,7 +1,12 @@
/**
* @fileoverview Functions for automatically setting up a player
* based on the data-setup attribute of the video tag
*/
// Automatically set up any tags that have a data-setup attribute
vjs.autoSetup = function(){
var options, vid, player,
vids = document.getElementsByTagName("video");
vids = document.getElementsByTagName('video');
// Check if any media elements exist
if (vids && vids.length > 0) {
@ -10,12 +15,12 @@ vjs.autoSetup = function(){
vid = vids[i];
// Check if element exists, has getAttribute func.
// IE seems to consider typeof el.getAttribute == "object" instead of "function" like expected, at least when loading the player immediately.
// IE seems to consider typeof el.getAttribute == 'object' instead of 'function' like expected, at least when loading the player immediately.
if (vid && vid.getAttribute) {
// Make sure this player hasn't already been set up.
if (vid.player === undefined) {
options = vid.getAttribute("data-setup");
options = vid.getAttribute('data-setup');
// Check if data-setup attr exists.
// We only auto-setup if they've added the data-setup attr.
@ -23,7 +28,7 @@ vjs.autoSetup = function(){
// Parse options JSON
// If empty string, make it a parsable json object.
options = vjs.JSON.parse(options || "{}");
options = vjs.JSON.parse(options || '{}');
// Create new video.js instance.
player = videojs(vid, options);
@ -48,7 +53,7 @@ vjs.autoSetupTimeout = function(wait){
setTimeout(vjs.autoSetup, wait);
};
vjs.one(window, "load", function(){
vjs.one(window, 'load', function(){
vjs.windowLoaded = true;
});

File diff suppressed because it is too large Load Diff

View File

@ -1,444 +0,0 @@
/* VideoJS-SWF - Custom Flash Player with HTML5-ish API - https://github.com/zencoder/video-js-swf
================================================================================ */
_V_.flash = _V_.PlaybackTech.extend({
init: function(player, options){
this.player = player;
var source = options.source,
// Which element to embed in
parentEl = options.parentEl,
// Create a temporary element to be replaced by swf object
placeHolder = this.el = _V_.createElement("div", { id: parentEl.id + "_temp_flash" }),
// Generate ID for swf object
objId = player.el.id+"_flash_api",
// Store player options in local var for optimization
playerOptions = player.options,
// Merge default flashvars with ones passed in to init
flashVars = _V_.merge({
// SWF Callback Functions
readyFunction: "_V_.flash.onReady",
eventProxyFunction: "_V_.flash.onEvent",
errorEventProxyFunction: "_V_.flash.onError",
// Player Settings
autoplay: playerOptions.autoplay,
preload: playerOptions.preload,
loop: playerOptions.loop,
muted: playerOptions.muted
}, 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),
// Merge default attributes with ones passed in
attributes = _V_.merge({
id: objId,
name: objId, // Both ID and Name needed or swf to identifty itself
'class': 'vjs-tech'
}, options.attributes)
;
// If source was supplied pass as a flash var.
if (source) {
flashVars.src = encodeURIComponent(_V_.getAbsoluteURL(source.src));
}
// Add placeholder to player div
_V_.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
if (options.startTime) {
this.ready(function(){
this.load();
this.play();
this.currentTime(options.startTime);
});
}
// Flash iFrame Mode
// In web browsers there are multiple instances where changing the parent element or visibility of a plugin causes the plugin to reload.
// - Firefox just about always. https://bugzilla.mozilla.org/show_bug.cgi?id=90268 (might be fixed by version 13)
// - Webkit when hiding the plugin
// - Webkit and Firefox when using requestFullScreen on a parent element
// Loading the flash plugin into a dynamically generated iFrame gets around most of these issues.
// Issues that remain include hiding the element and requestFullScreen in Firefox specifically
// There's on particularly annoying issue with this method which is that Firefox throws a security error on an offsite Flash object loaded into a dynamically created iFrame.
// Even though the iframe was inserted into a page on the web, Firefox + Flash considers it a local app trying to access an internet file.
// I tried mulitple ways of setting the iframe src attribute but couldn't find a src that worked well. Tried a real/fake source, in/out of domain.
// Also tried a method from stackoverflow that caused a security error in all browsers. http://stackoverflow.com/questions/2486901/how-to-set-document-domain-for-a-dynamically-generated-iframe
// In the end the solution I found to work was setting the iframe window.location.href right before doing a document.write of the Flash object.
// The only downside of this it seems to trigger another http request to the original page (no matter what's put in the href). Not sure why that is.
// NOTE (2012-01-29): Cannot get Firefox to load the remote hosted SWF into a dynamically created iFrame
// Firefox 9 throws a security error, unleess you call location.href right before doc.write.
// 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_.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
});
// Update ready function names in flash vars for iframe window
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);
// (in onload)
// var temp = _V_.createElement("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)+"');";
// 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(){
var iDoc, objTag, swfLoc,
iWin = iFrm.contentWindow,
varString = "";
// The one working method I found was to use the iframe's document.write() to create the swf object
// This got around the security issue in all browsers except firefox.
// 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")) {
// iWin.location.href = "";
// }
// Get the iFrame's document depending on what the browser supports
iDoc = iFrm.contentDocument ? iFrm.contentDocument : iFrm.contentWindow.document;
// Tried ensuring both document domains were the same, but they already were, so that wasn't the issue.
// Even tried adding /. that was mentioned in a browser security writeup
// document.domain = document.domain+"/.";
// iDoc.domain = document.domain+"/.";
// Tried adding the object to the iframe doc's innerHTML. Security error in all browsers.
// iDoc.body.innerHTML = swfObjectHTML;
// Tried appending the object to the iframe doc's body. Security error in all browsers.
// iDoc.body.appendChild(swfObject);
// 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));
// 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){
var el = iDoc.getElementById(currSwf),
player = this,
tech = player.tech;
// Update reference to playback technology element
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));
// Make sure swf is actually ready. Sometimes the API isn't actually yet.
_V_.flash.checkReady(tech);
});
// Create event listener for all swf events
iWin.events = _V_.proxy(this.player, function(swfID, eventName, other){
var player = this;
if (player && player.techName == "flash") {
player.triggerEvent(eventName);
}
});
// Create error listener for all swf errors
iWin.errors = _V_.proxy(this.player, function(swfID, eventName){
_V_.log("Flash Error", eventName);
});
}));
// Replace placeholder with iFrame (it will load now)
placeHolder.parentNode.replaceChild(iFrm, placeHolder);
// If not using iFrame mode, embed as normal object
} else {
_V_.flash.embed(options.swf, placeHolder, flashVars, params, attributes);
}
},
destroy: function(){
this.el.parentNode.removeChild(this.el);
},
// setupTriggers: function(){}, // Using global onEvent func to distribute events
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);
// 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;
}
});
// Create setters and getters for attributes
(function(){
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
createSetter = function(attr){
var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);
api["set"+attrUpper] = function(val){ return this.el.vjs_setProperty(attr, val); };
},
createGetter = function(attr){
api[attr] = function(){ return this.el.vjs_getProperty(attr); };
}
;
// 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);
});
})();
/* Flash Support Testing -------------------------------------------------------- */
_V_.flash.isSupported = function(){
return _V_.flash.version()[0] >= 10;
// return swfobject.hasFlashPlayerVersion("10");
};
_V_.flash.canPlaySource = function(srcObj){
if (srcObj.type in _V_.flash.prototype.support.formats) { return "maybe"; }
};
_V_.flash.prototype.support = {
formats: {
"video/flv": "FLV",
"video/x-flv": "FLV",
"video/mp4": "MP4",
"video/m4v": "MP4"
},
// Optional events that we can manually mimic with timers
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"))
};
_V_.flash.onReady = function(currSwf){
var el = _V_.el(currSwf);
// Get player from box
// On firefox reloads, el might already have a player
var player = el.player || el.parentNode.player,
tech = player.tech;
// Reference player on tech element
el.player = player;
// Update reference to playback technology element
tech.el = el;
// Now that the element is ready, make a click on the swf play the video
tech.addEvent("click", tech.onClick);
_V_.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){
// Check if API property exists
if (tech.el.vjs_getProperty) {
// If so, tell tech it's ready
tech.triggerReady();
// Otherwise wait longer.
} else {
setTimeout(function(){
_V_.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);
};
// 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);
};
// Flash Version Check
_V_.flash.version = function(){
var version = '0,0,0';
// IE
try {
version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
// other browsers
} catch(e) {
try {
if (navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){
version = (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1];
}
} catch(e) {}
}
return version.split(",");
};
// 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),
// Get element by embedding code and retrieving created element
obj = _V_.createElement("div", { innerHTML: code }).childNodes[0],
par = placeHolder.parentNode
;
placeHolder.parentNode.replaceChild(obj, placeHolder);
// 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_.IS_IE6to8()) {
var newObj = par.childNodes[0];
setTimeout(function(){
newObj.style.display = "block";
}, 1000);
}
return obj;
};
_V_.flash.getEmbedCode = function(swf, flashVars, params, attributes){
var objTag = '<object type="application/x-shockwave-flash"',
flashVarsString = '',
paramsString = '',
attrsString = '';
// Convert flash vars to string
if (flashVars) {
_V_.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);
// Create param tags string
_V_.eachProp(params, function(key, val){
paramsString += '<param name="'+key+'" value="'+val+'" />';
});
attributes = _V_.merge({
// Add swf to attributes (need both for IE and Others to work)
data: swf,
// Default to 100% width/height
width: "100%",
height: "100%"
}, attributes);
// Create Attributes string
_V_.eachProp(attributes, function(key, val){
attrsString += (key + '="' + val + '" ');
});
return objTag + attrsString + '>' + paramsString + '</object>';
};

View File

@ -1,228 +0,0 @@
/* HTML5 Playback Technology - Wrapper for HTML5 Media API
================================================================================ */
_V_.html5 = _V_.PlaybackTech.extend({
init: function(player, options, ready){
this.player = player;
this.el = this.createElement();
this.ready(ready);
this.addEvent("click", this.proxy(this.onClick));
var source = options.source;
// If the element source is already set, we may have missed the loadstart event, and want to trigger it.
// We don't want to set the source again and interrupt playback.
if (source && this.el.currentSrc == source.src) {
player.triggerEvent("loadstart");
// Otherwise set the source if one was provided.
} else if (source) {
this.el.src = source.src;
}
// Chrome and Safari both have issues with autoplay.
// In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work.
// In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays)
// This fixes both issues. Need to wait for API, so it updates displays correctly
player.ready(function(){
if (this.options.autoplay && this.paused()) {
this.tag.poster = null; // Chrome Fix. Fixed in Chrome v16.
this.play();
}
});
this.setupTriggers();
this.triggerReady();
},
destroy: function(){
this.player.tag = false;
this.removeTriggers();
this.el.parentNode.removeChild(this.el);
},
createElement: function(){
var html5 = _V_.html5,
player = this.player,
// If possible, reuse original tag for HTML5 playback technology element
el = player.tag,
newEl;
// 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 || this.support.movingElementInDOM === false) {
// If the original tag is still there, remove it.
if (el) {
player.el.removeChild(el);
}
newEl = _V_.createElement("video", {
id: el.id || player.el.id + "_html5_api",
className: el.className || "vjs-tech"
});
el = newEl;
_V_.insertFirst(el, player.el);
}
// Update tag settings, in case they were overridden
_V_.each(["autoplay","preload","loop","muted"], function(attr){ // ,"poster"
if (player.options[attr] !== null) {
el[attr] = player.options[attr];
}
}, this);
return el;
},
// Make video events trigger player events
// May seem verbose here, but makes other APIs possible.
setupTriggers: function(){
_V_.each.call(this, _V_.html5.events, function(type){
_V_.addEvent(this.el, type, _V_.proxy(this.player, this.eventHandler));
});
},
removeTriggers: function(){
_V_.each.call(this, _V_.html5.events, function(type){
_V_.removeEvent(this.el, type, _V_.proxy(this.player, this.eventHandler));
});
},
eventHandler: function(e){
e.stopPropagation();
this.triggerEvent(e);
},
play: function(){ this.el.play(); },
pause: function(){ this.el.pause(); },
paused: function(){ return this.el.paused; },
currentTime: function(){ return this.el.currentTime; },
setCurrentTime: function(seconds){
try {
this.el.currentTime = seconds;
} catch(e) {
_V_.log(e, "Video isn't ready. (VideoJS)");
// this.warning(VideoJS.warnings.videoNotReady);
}
},
duration: function(){ return this.el.duration || 0; },
buffered: function(){ return this.el.buffered; },
volume: function(){ return this.el.volume; },
setVolume: function(percentAsDecimal){ this.el.volume = percentAsDecimal; },
muted: function(){ return this.el.muted; },
setMuted: function(muted){ this.el.muted = muted; },
width: function(){ return this.el.offsetWidth; },
height: function(){ return this.el.offsetHeight; },
supportsFullScreen: function(){
if (typeof this.el.webkitEnterFullScreen == 'function') {
// Seems to be broken in Chromium/Chrome && Safari in Leopard
if (!navigator.userAgent.match("Chrome") && !navigator.userAgent.match("Mac OS X 10.5")) {
return true;
}
}
return false;
},
enterFullScreen: function(){
try {
this.el.webkitEnterFullScreen();
} catch (e) {
if (e.code == 11) {
// this.warning(VideoJS.warnings.videoNotReady);
_V_.log("VideoJS: Video not ready.");
}
}
},
exitFullScreen: function(){
try {
this.el.webkitExitFullScreen();
} catch (e) {
if (e.code == 11) {
// this.warning(VideoJS.warnings.videoNotReady);
_V_.log("VideoJS: Video not ready.");
}
}
},
src: function(src){ this.el.src = src; },
load: function(){ this.el.load(); },
currentSrc: function(){ return this.el.currentSrc; },
preload: function(){ return this.el.preload; },
setPreload: function(val){ this.el.preload = val; },
autoplay: function(){ return this.el.autoplay; },
setAutoplay: function(val){ this.el.autoplay = val; },
loop: function(){ return this.el.loop; },
setLoop: function(val){ this.el.loop = val; },
error: function(){ return this.el.error; },
// networkState: function(){ return this.el.networkState; },
// readyState: function(){ return this.el.readyState; },
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; },
ended: function(){ return this.el.ended; },
// videoTracks: function(){ return this.el.videoTracks; },
// audioTracks: function(){ return this.el.audioTracks; },
// videoWidth: function(){ return this.el.videoWidth; },
// videoHeight: function(){ return this.el.videoHeight; },
// textTracks: function(){ return this.el.textTracks; },
// defaultPlaybackRate: function(){ return this.el.defaultPlaybackRate; },
// playbackRate: function(){ return this.el.playbackRate; },
// mediaGroup: function(){ return this.el.mediaGroup; },
// controller: function(){ return this.el.controller; },
controls: function(){ return this.player.options.controls; },
defaultMuted: function(){ return this.el.defaultMuted; }
});
/* HTML5 Support Testing -------------------------------------------------------- */
_V_.html5.isSupported = function(){
return !!document.createElement("video").canPlayType;
};
_V_.html5.canPlaySource = function(srcObj){
return !!document.createElement("video").canPlayType(srcObj.type);
// TODO: Check Type
// If no Type, check ext
// Check Media Type
};
// 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(",");
/* HTML5 Device Fixes ---------------------------------------------------------- */
_V_.html5.prototype.support = {
// Support for tech specific full screen. (webkitEnterFullScreen, not requestFullscreen)
// http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html
// Seems to be broken in Chromium/Chrome && Safari in Leopard
fullscreen: (typeof _V_.testVid.webkitEnterFullScreen !== undefined) ? (!_V_.ua.match("Chrome") && !_V_.ua.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_.isIOS()
};
// Android
if (_V_.isAndroid()) {
// Override Android 2.2 and less canPlayType method which is broken
if (_V_.androidVersion() < 3) {
document.createElement("video").constructor.prototype.canPlayType = function(type){
return (type && type.toLowerCase().indexOf("video/mp4") != -1) ? "maybe" : "";
};
}
}

90
test/dev-compiled.html Normal file
View File

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>HTML5 Video Player</title>
<link rel="stylesheet" href="../design/video-js.css" type="text/css">
<link rel="stylesheet" href="../test/vendor/qunit/qunit/qunit.css" />
<script src="../test/vendor/qunit/qunit/qunit.js"></script>
<!--[if IE]>
<script src="https://getfirebug.com/releases/lite/1.3/firebug-lite.js"></script>
<!--<![endif]-->
<script src='video.compiled.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) {
videojs.options.techOrder = ["Flash"];
videojs.options.flash.swf = "../tech/flash/video-js.swf";
}
</script>
</head>
<body>
<video id="vid1" class="video-js vjs-default-skin" controls preload="none" width="640" height="264"
poster="http://video-js.zencoder.com/oceans-clip.png"
data-setup='{}'>
<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'>
<track kind=captions src="http://videojs.com/video-js/captions.vtt" srclang="en" label="English" />
<p>Video Playback Not Supported</p>
</video>
<script>
vid = document.getElementById("vid1");
var player = videojs('vid1');
function roughSizeOfObject( object ) {
var objectList = [];
var recurse = function( value )
{
var bytes = 0;
if ( typeof value === 'boolean' ) {
bytes = 4;
}
else if ( typeof value === 'string' ) {
bytes = value.length * 2;
}
else if ( typeof value === 'number' ) {
bytes = 8;
}
else if
(
typeof value === 'object'
&& objectList.indexOf( value ) === -1
)
{
objectList[ objectList.length ] = value;
for( i in value ) {
bytes+= 8; // an assumed existence overhead
bytes+= recurse( value[i] )
}
}
return bytes;
}
return recurse( object );
}
function cacheSize(){
for (i in videojs.cache[6].handlers) {
console.log(i, roughSizeOfObject(videojs.cache[6].handlers[i]))
}
}
</script>
</body>
</html>

84
test/qunit-externs.js Normal file
View File

@ -0,0 +1,84 @@
// https://github.com/lukeasrodgers/qunit-js-externs/blob/master/qunit-externs.js
/**
* @param {string} name
* @param {Object=} lifecycle
*/
function module(name, lifecycle) {}
/**
* @param {string} title
* @param {number|Function} expected
* @param {Function=} test_func
*/
function test(title, expected, test_func){}
/**
* @param {string} name
* @param {number|Function} expected
* @param {Function=} test_func
*/
function asyncTest(name, expected, test_func){}
/**
* @param {number} amount
*/
function expect(amount){}
/**
* @param {*} state
* @param {string=} message
*/
function ok(state, message){}
/**
* @param {*} actual
* @param {*} expected
* @param {string=} message
*/
function equal(actual, expected, message){}
/**
* @param {*} actual
* @param {*} expected
* @param {string=} message
*/
function notEqual(actual, expected, message){}
/**
* @param {*} actual
* @param {*} expected
* @param {string=} message
*/
function deepEqual(actual, expected, message){}
/**
* @param {*} actual
* @param {*} expected
* @param {string=} message
*/
function notDeepEqual(actual, expected, message){}
/**
* @param {*} actual
* @param {*} expected
* @param {string=} message
*/
function strictEqual(actual, expected, message){}
/**
* @param {*} actual
* @param {*} expected
* @param {string=} message
*/
function notStrictEqual(actual, expected, message){}
/**
* @param {number=} increment
*/
function start(increment){}
/**
* @param {number=} increment
*/
function stop(increment){}

1
test/src Symbolic link
View File

@ -0,0 +1 @@
../src

29
test/unit-compiled.html Normal file
View File

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Video.js Test Suite</title>
<!-- QUnit -->
<link rel="stylesheet" href="../test/vendor/qunit/qunit/qunit.css" />
<script src="../test/vendor/qunit/qunit/qunit.js"></script>
<!-- phantomjs logging script-->
<!--<script src="unit/phantom-logging.js"></script>-->
<!-- Video.js CSS -->
<link rel="stylesheet" href="../design/video-js.css" type="text/css">
<!-- Video.js JavaScript -->
<script src='video.test.compiled.js'></script>
</head>
<body>
<div>
<h1 id="qunit-header">Bootstrap Plugin Test Suite</h1>
<h2 id="qunit-banner"></h2>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture"></div>
</div>
</body>
</html>

View File

@ -4,8 +4,8 @@
<title>Video.js Test Suite</title>
<!-- QUnit -->
<link rel="stylesheet" href="vendor/qunit/qunit/qunit.css" />
<script src="vendor/qunit/qunit/qunit.js"></script>
<link rel="stylesheet" href="../test/vendor/qunit/qunit/qunit.css" />
<script src="../test/vendor/qunit/qunit/qunit.js"></script>
<!-- phantomjs logging script-->
<script src="unit/phantom-logging.js"></script>
@ -14,27 +14,28 @@
<link rel="stylesheet" href="../design/video-js.css" type="text/css">
<!-- Video.js JavaScript -->
<script src='../src/goog.base.js'></script>
<script src='../src/core.js'></script>
<script src='../src/lib.js'></script>
<script src='../src/component.js'></script>
<script src='../src/controls.js'></script>
<script src='../src/events.js'></script>
<script src='../src/json.js'></script>
<script src='../src/component.js'></script>
<script src='../src/player.js'></script>
<script src='../src/tech.js'></script>
<script src='../src/media.js'></script>
<script src='../src/media.html5.js'></script>
<script src='../src/media.flash.js'></script>
<script src='../src/controls.js'></script>
<script src='../src/tracks.js'></script>
<script src='../tech/html5/html5.js'></script>
<script src='../tech/flash/flash.js'></script>
<script src='../src/setup.js'></script>
<!-- Unit Tests -->
<script src="unit/component.js"></script>
<script src="unit/controls.js"></script>
<script src="unit/player.js"></script>
<script src="unit/lib.js"></script>
<script src="unit/events.js"></script>
<script src="unit/component.js"></script>
<script src="unit/player.js"></script>
<script src="unit/core.js"></script>
<script src="unit/media.html5.js"></script>
<!-- -->
</head>
<body>
<div>
@ -45,4 +46,4 @@
<div id="qunit-fixture"></div>
</div>
</body>
</html>
</html>

View File

@ -1,61 +1,67 @@
module("Component");
test('should create an element', function(){
var comp = new _V_.Component({}, {});
var comp = new vjs.Component({}, {});
ok(comp.getEl().nodeName);
ok(comp.el().nodeName);
});
test('should add a child component', function(){
var comp = new vjs.Component({});
var child = comp.addChild("component");
ok(comp.children().length === 1);
ok(comp.children()[0] === child);
ok(comp.el().childNodes[0] === child.el());
ok(comp.getChild('component') === child);
ok(comp.getChildById(child.id()) === child);
});
test('should init child coponents from options', function(){
var comp = new _V_.Component({}, {
components: {
var comp = new vjs.Component({}, {
children: {
'component': true
}
});
ok(comp.el.childNodes.length === 1);
ok(comp.children().length === 1);
ok(comp.el().childNodes.length === 1);
});
test('should add a child component', function(){
var comp = new _V_.Component({});
test('should dispose of component and children', function(){
var comp = new vjs.Component({});
comp.addChild("Component");
// Add a child
var child = comp.addChild("Component");
ok(comp.children().length === 1);
ok(comp.el.childNodes.length === 1);
});
// Add a listener
comp.on('click', function(){ return true; });
var data = vjs.getData(comp.el());
var id = comp.el()[vjs.expando];
comp.dispose();
test('should show and hide an element', function(){
var comp = new _V_.Component({}, {});
comp.hide();
ok(comp.el.style.display === 'none');
comp.show();
ok(comp.el.style.display === 'block');
});
test('should add and remove a CSS class', function(){
var comp = new _V_.Component({}, {});
comp.addClass('test-class');
ok(comp.el.className.indexOf('test-class') !== -1);
comp.removeClass('test-class');
ok(comp.el.className.indexOf('test-class') === -1);
ok(!comp.children(), 'component children were deleted');
ok(!comp.el(), 'component element was deleted');
ok(!child.children(), 'child children were deleted');
ok(!child.el(), 'child element was deleted');
ok(!vjs.cache[id], 'listener cache nulled')
ok(vjs.isEmpty(data), 'original listener cache object was emptied')
});
test('should add and remove event listeners to element', function(){
var comp = new _V_.Component({}, {});
var comp = new vjs.Component({}, {});
// No need to make this async because we're triggering events inline.
// We're going to trigger the event after removing the listener,
// So if we get extra asserts that's a problem.
expect(1);
expect(2);
var testListener = function(){
ok(true, 'fired event once');
ok(this === comp, 'listener has the component as context');
};
comp.on('test-event', testListener);
@ -65,7 +71,7 @@ test('should add and remove event listeners to element', function(){
});
test('should trigger a listener once using one()', function(){
var comp = new _V_.Component({}, {});
var comp = new vjs.Component({}, {});
expect(1);
@ -77,3 +83,64 @@ test('should trigger a listener once using one()', function(){
comp.trigger('test-event');
comp.trigger('test-event');
});
test('should trigger a listener when ready', function(){
expect(2);
var optionsReadyListener = function(){
ok(true, 'options listener fired')
};
var methodReadyListener = function(){
ok(true, 'ready method listener fired')
};
var comp = new vjs.Component({}, {}, optionsReadyListener);
comp.triggerReady();
comp.ready(methodReadyListener);
// First two listeners should only be fired once and then removed
comp.triggerReady();
});
test('should add and remove a CSS class', function(){
var comp = new vjs.Component({}, {});
comp.addClass('test-class');
ok(comp.el().className.indexOf('test-class') !== -1);
comp.removeClass('test-class');
ok(comp.el().className.indexOf('test-class') === -1);
});
test('should show and hide an element', function(){
var comp = new vjs.Component({}, {});
comp.hide();
ok(comp.el().style.display === 'none');
comp.show();
ok(comp.el().style.display === 'block');
});
test('should change the width and height of a component', function(){
var container = document.createElement('div');
var comp = new vjs.Component({}, {});
var el = comp.el();
var fixture = document.getElementById('qunit-fixture');
fixture.appendChild(container);
container.appendChild(el);
// Container of el needs dimensions or the component won't have dimensions
container.style.width = '1000px'
container.style.height = '1000px'
comp.width('50%');
comp.height('123px');
ok(comp.width() === 500, 'percent values working');
ok(vjs.getComputedStyleValue(el, 'width') === comp.width() + 'px', 'matches computed style');
ok(comp.height() === 123, 'px values working');
comp.width(321);
ok(comp.width() === 321, 'integer values working');
});

View File

@ -1 +0,0 @@
module("Controls");

View File

@ -1 +1,29 @@
module("Core");
module("Core");
test('should create a video tag and have access children in old IE', function(){
var fixture = document.getElementById('qunit-fixture');
fixture.innerHTML += "<video id='test_vid_id'><source type='video/mp4'></video>";
vid = document.getElementById('test_vid_id');
ok(vid.childNodes.length === 1);
ok(vid.childNodes[0].getAttribute('type') === 'video/mp4');
});
test('should return a video player instance', function(){
var fixture = document.getElementById('qunit-fixture');
fixture.innerHTML += "<video id='test_vid_id'></video><video id='test_vid_id2'></video>";
var player = videojs('test_vid_id');
ok(player, 'created player from tag');
ok(player.id() === 'test_vid_id');
ok(videojs.players['test_vid_id'] === player, 'added player to global reference')
var playerAgain = videojs('test_vid_id');
ok(player === playerAgain, 'did not create a second player from same tag');
var tag2 = document.getElementById('test_vid_id2');
var player2 = videojs(tag2);
ok(player2.id() === 'test_vid_id2', 'created player from element');
});

View File

@ -1 +1,74 @@
module("Events");
module("Events");
test('should add and remove an event listener to an element', function(){
expect(1);
var el = document.createElement('div');
var listener = function(){
ok(true, 'Click Triggered');
};
vjs.on(el, 'click', listener);
vjs.trigger(el, 'click'); // 1 click
vjs.off(el, 'click', listener)
vjs.trigger(el, 'click'); // No click should happen.
});
test('should remove all listeners of a type', function(){
var el = document.createElement('div');
var clicks = 0;
var listener = function(){
clicks++;
};
var listener2 = function(){
clicks++;
};
vjs.on(el, 'click', listener);
vjs.on(el, 'click', listener2);
vjs.trigger(el, 'click'); // 2 clicks
ok(clicks === 2, 'both click listeners fired')
vjs.off(el, 'click')
vjs.trigger(el, 'click'); // No click should happen.
ok(clicks === 2, 'no click listeners fired')
});
test('should remove all listeners from an element', function(){
expect(2);
var el = document.createElement('div');
var listener = function(){
ok(true, 'Fake1 Triggered');
};
var listener2 = function(){
ok(true, 'Fake2 Triggered');
};
vjs.on(el, 'fake1', listener);
vjs.on(el, 'fake2', listener2);
vjs.trigger(el, 'fake1');
vjs.trigger(el, 'fake2');
vjs.off(el);
// No listener should happen.
vjs.trigger(el, 'fake1');
vjs.trigger(el, 'fake2');
});
test('should listen only once', function(){
expect(1);
var el = document.createElement('div');
var listener = function(){
ok(true, 'Click Triggered');
};
vjs.one(el, 'click', listener);
vjs.trigger(el, 'click'); // 1 click
vjs.trigger(el, 'click'); // No click should happen.
});

View File

@ -1,69 +1,184 @@
module("Lib");
test('should merge two objects', function(){
var obj1 = { a:1, b:2 };
var obj2 = { b:3, c:4 };
_V_.merge(obj1, obj2);
deepEqual(obj1, {a:1,b:3,c:4} );
test('should create an element', function(){
var div = vjs.createEl();
var span = vjs.createEl('span', { "data-test": "asdf", innerHTML:'fdsa' })
ok(div.nodeName === 'DIV');
ok(span.nodeName === 'SPAN');
ok(span['data-test'] === 'asdf');
ok(span.innerHTML === "fdsa");
});
test('should create an element with attributes', function(){
var el = _V_.createElement('div', { className: 'test-class', 'data-test': 'asdf' })
ok(el.className === 'test-class');
ok(el.getAttribute('data-test') === 'asdf' );
test('should make a string start with an uppercase letter', function(){
var foo = vjs.capitalize('bar')
ok(foo === 'Bar');
});
test('should insert an element first', function(){
test('should loop through each property on an object', function(){
var asdf = {
a: 1,
b: 2,
'c': 3
}
// Add 3 to each value
vjs.eachProp(asdf, function(key, value){
asdf[key] = value + 3;
});
deepEqual(asdf,{a:4,b:5,'c':6})
});
test('should add context to a function', function(){
var newContext = { test: 'obj'};
var asdf = function(){
ok(this === newContext);
}
var fdsa = vjs.bind(newContext, asdf);
fdsa();
});
test('should add and remove a class name on an element', function(){
var el = document.createElement('div');
vjs.addClass(el, 'test-class')
ok(el.className === 'test-class', 'class added');
vjs.addClass(el, 'test-class')
ok(el.className === 'test-class', 'same class not duplicated');
vjs.addClass(el, 'test-class2')
ok(el.className === 'test-class test-class2', 'added second class');
vjs.removeClass(el, 'test-class')
ok(el.className === 'test-class2', 'removed first class');
});
test('should get and remove data from an element', function(){
var el = document.createElement('div');
var data = vjs.getData(el);
var id = el[vjs.expando];
ok(typeof data === 'object', 'data object created');
// Add data
var testData = { asdf: 'fdsa' };
data.test = testData;
ok(vjs.getData(el).test === testData, 'data added');
// Remove all data
vjs.removeData(el);
ok(!vjs.cache[id], 'cached item nulled')
ok(el[vjs.expando] === null || el[vjs.expando] === undefined, 'element data id removed')
});
test('should read tag attributes from elements, including HTML5 in all browsers', function(){
var container = document.createElement('div');
var tags = '<video id="vid1" controls autoplay loop muted preload="none" src="http://google.com" poster="http://www2.videojs.com/img/video-js-html5-video-player.png" data-test="asdf" data-empty-string=""></video>';
tags += '<video id="vid2">';
// Not putting source and track inside video element because
// oldIE needs the HTML5 shim to read tags inside HTML5 tags.
// Still may not work in oldIE.
tags += '<source id="source" src="http://google.com" type="video/mp4" media="fdsa" title="test" >';
tags += '<track id="track" default src="http://google.com" kind="captions" srclang="en" label="testlabel" title="test" >';
container.innerHTML += tags;
document.getElementById('qunit-fixture').appendChild(container);
var vid1Vals = vjs.getAttributeValues(document.getElementById('vid1'));
var vid2Vals = vjs.getAttributeValues(document.getElementById('vid2'));
var sourceVals = vjs.getAttributeValues(document.getElementById('source'));
var trackVals = vjs.getAttributeValues(document.getElementById('track'));
deepEqual(vid1Vals, { 'autoplay': true, 'controls': true, 'data-test': "asdf", 'data-empty-string': "", 'id': "vid1", 'loop': true, 'muted': true, 'poster': "http://www2.videojs.com/img/video-js-html5-video-player.png", 'preload': "none", 'src': "http://google.com" });
deepEqual(vid2Vals, { 'id': "vid2" });
deepEqual(sourceVals, {'title': "test", 'media': "fdsa", 'type': "video/mp4", 'src': "http://google.com", 'id': "source" });
deepEqual(trackVals, { "default": true, /* IE no likey default key */ 'id': "track", 'kind': "captions", 'label': "testlabel", 'src': "http://google.com", 'srclang': "en", 'title': "test" });
});
test('should get the right style values for an element', function(){
var el = document.createElement('div');
var container = document.createElement('div');
var fixture = document.getElementById('qunit-fixture')
container.appendChild(el);
fixture.appendChild(container);
container.style.width = "1000px";
container.style.height = "1000px";
el.style.height = "100%";
el.style.width = "123px";
ok(vjs.getComputedStyleValue(el, 'height') === '1000px');
ok(vjs.getComputedStyleValue(el, 'width') === '123px');
});
test('should insert an element first in another', function(){
var el1 = document.createElement('div');
var el2 = document.createElement('div');
var el3 = document.createElement('div');
var parent = document.createElement('div');
_V_.insertFirst(el2, el1);
ok(el1.childNodes[0] === el2);
_V_.insertFirst(el3, el1);
ok(el1.childNodes[0] === el3);
vjs.insertFirst(el1, parent)
ok(parent.firstChild === el1, 'inserts first into empty parent');
vjs.insertFirst(el2, parent)
ok(parent.firstChild === el2, 'inserts first into parent with child');
});
test('should add and remove a CSS class', function(){
var el = document.createElement('div');
test('should return the element with the ID', function(){
var el1 = document.createElement('div');
var el2 = document.createElement('div');
var fixture = document.getElementById('qunit-fixture');
_V_.addClass(el, 'test-class')
ok(el.className.indexOf('test-class') !== -1);
_V_.removeClass(el, 'test-class')
ok(el.className.indexOf('test-class') === -1);
fixture.appendChild(el1);
fixture.appendChild(el2);
el1.id = 'test_id1';
el2.id = 'test_id2';
ok(vjs.el("test_id1") === el1, 'found element for ID');
ok(vjs.el("#test_id2") === el2, 'found element for CSS ID');
});
test('should format the time', function(){
ok(_V_.formatTime(120) === "2:00");
ok(_V_.formatTime(18121) === "5:02:01");
});
test('should uppercase a word', function(){
ok(_V_.capitalize('asdf') === "Asdf");
});
test('should trim a string', function(){
ok(_V_.trim(' asdf ') === "asdf");
test('should trim whitespace from a string', function(){
ok(vjs.trim(' asdf asdf asdf \t\n\r') === 'asdf asdf asdf');
});
test('should round a number', function(){
ok(_V_.round(1.01) === 1);
ok(_V_.round(1.01, 1) === 1.0);
ok(_V_.round(1.01, 2) === 1.01);
ok(_V_.round(1.05, 1) === 1.1);
ok(vjs.round(1.01) === 1);
ok(vjs.round(1.5) === 2);
ok(vjs.round(1.55, 2) === 1.55);
ok(vjs.round(10.551, 2) === 10.55);
});
test('should test that an object is empty', function(){
ok(_V_.isEmpty({}) === true);
ok(_V_.isEmpty({ asdf: 'asdf' }) === false);
test('should format time as a string', function(){
ok(vjs.formatTime(1) === "0:01");
ok(vjs.formatTime(10) === "0:10");
ok(vjs.formatTime(60) === "1:00");
ok(vjs.formatTime(600) === "10:00");
ok(vjs.formatTime(3600) === "1:00:00");
ok(vjs.formatTime(36000) === "10:00:00");
ok(vjs.formatTime(360000) === "100:00:00");
// Using guide should provide extra leading zeros
ok(vjs.formatTime(1,1) === "0:01");
ok(vjs.formatTime(1,10) === "0:01");
ok(vjs.formatTime(1,60) === "0:01");
ok(vjs.formatTime(1,600) === "00:01");
ok(vjs.formatTime(1,3600) === "0:00:01");
// Don't do extra leading zeros for hours
ok(vjs.formatTime(1,36000) === "0:00:01");
ok(vjs.formatTime(1,360000) === "0:00:01");
});
test('should create a fake timerange', function(){
var tr = _V_.createTimeRange(0, 100);
var tr = vjs.createTimeRange(0, 10);
ok(tr.start() === 0);
ok(tr.end() === 100);
ok(tr.length === 1);
ok(tr.end() === 10);
});
test('should get an absolute URL', function(){
// Errors on compiled tests that don't use unit.html. Need a better solution.
// ok(vjs.getAbsoluteURL('unit.html') === window.location.href);
ok(vjs.getAbsoluteURL('http://asdf.com') === "http://asdf.com");
ok(vjs.getAbsoluteURL('https://asdf.com/index.html') === "https://asdf.com/index.html");
});

1
test/unit/media.html5.js Normal file
View File

@ -0,0 +1 @@
module("HTML5");

View File

@ -1,22 +1,183 @@
module("Player", {
setup: function(){
module("Player");
var PlayerTest = {
makeTag: function(){
var videoTag = document.createElement('video');
videoTag.id = 'example_1';
videoTag.className = 'video-js vjs-default-skin';
return videoTag;
},
makePlayer: function(playerOptions){
var videoTag = PlayerTest.makeTag();
var fixture = document.getElementById('qunit-fixture');
fixture.appendChild(videoTag);
this.player = new _V_.Player(videoTag, {});
},
teardown: function(){
return player = new vjs.Player(videoTag, playerOptions);
}
};
// Compiler doesn't like using 'this' in setup/teardown.
// module("Player", {
// /**
// * @this {*}
// */
// setup: function(){
// window.player1 = true; // using window works
// },
// /**
// * @this {*}
// */
// teardown: function(){
// // if (this.player && this.player.el() !== null) {
// // this.player.dispose();
// // this.player = null;
// // }
// }
// });
// Object.size = function(obj) {
// var size = 0, key;
// for (key in obj) {
// console.log('key', key)
// if (obj.hasOwnProperty(key)) size++;
// }
// return size;
// };
test('should create player instance that inherits from component and dispose it', function(){
var player = PlayerTest.makePlayer();
ok(player.el().nodeName === 'DIV');
ok(player.on, 'component function exists');
player.dispose();
ok(player.el() === null, 'element disposed');
});
test('should create and embed a new player element', function(){
ok(this.player.el.nodeName === 'DIV');
ok(this.player.el.parentNode.id === 'qunit-fixture');
ok(this.player.el.className.indexOf('video-js vjs-default-skin') !== -1);
ok(this.player.el.id === 'example_1');
});
test('should accept options from multiple sources and override in correct order', function(){
// For closure compiler to work, all reference to the prop have to be the same type
// As in options['attr'] or options.attr. Compiler will minimize each separately.
// Since we're using setAttribute which requires a string, we have to use the string
// version of the key for all version.
// Set a global option
vjs.options['attr'] = 1;
var tag0 = PlayerTest.makeTag();
var player0 = new vjs.Player(tag0);
ok(player0.options['attr'] === 1, 'global option was set')
player0.dispose();
// Set a tag level option
var tag1 = PlayerTest.makeTag();
tag1.setAttribute('attr', 'asdf'); // Attributes must be set as strings
var player1 = new vjs.Player(tag1);
ok(player1.options['attr'] === 'asdf', 'Tag options overrode global options');
player1.dispose();
// Set a tag level option
var tag2 = PlayerTest.makeTag();
tag2.setAttribute('attr', 'asdf');
var player2 = new vjs.Player(tag2, { 'attr': 'fdsa' });
ok(player2.options['attr'] === 'fdsa', 'Init options overrode tag and global options');
player2.dispose();
});
test('should get tag, source, and track settings', function(){
// Partially tested in lib->getAttributeValues
var fixture = document.getElementById('qunit-fixture');
var html = '<video id="example_1" class="video-js" autoplay preload="metadata">'
html += '<source src="http://google.com" type="video/mp4">';
html += '<source src="http://google.com" type="video/webm">';
html += '<track src="http://google.com" kind="captions" default>';
html += '</video>';
fixture.innerHTML += html;
var tag = document.getElementById('example_1');
var player = new vjs.Player(tag);
ok(player.options['autoplay'] === true);
ok(player.options['preload'] === 'metadata'); // No extern. Use string.
ok(player.options['id'] === 'example_1');
ok(player.options['sources'].length === 2);
ok(player.options['sources'][0].src === 'http://google.com');
ok(player.options['sources'][0].type === 'video/mp4');
ok(player.options['sources'][1].type === 'video/webm');
ok(player.options['tracks'].length === 1);
ok(player.options['tracks'][0]['kind'] === 'captions'); // No extern
ok(player.options['tracks'][0]['default'] === true);
ok(player.el().className.indexOf('video-js') !== -1, 'transferred class from tag to player div');
ok(player.el().id === 'example_1', 'transferred id from tag to player div');
ok(tag.player === player, 'player referenceable on original tag');
ok(vjs.players[player.id()] === player, 'player referenceable from global list');
ok(tag.id !== player.id, 'tag ID no longer is the same as player ID');
ok(tag.className !== player.el().className, 'tag classname updated');
player.dispose();
ok(tag.player === null, 'tag player ref killed')
ok(!vjs.players['example_1'], 'global player ref killed')
ok(player.el() === null, 'player el killed')
});
test('should set the width and height of the player', function(){
var player = PlayerTest.makePlayer({ width: 123, height: '100%' });
ok(player.width() === 123)
ok(player.el().style.width === '123px')
var fixture = document.getElementById('qunit-fixture');
var container = document.createElement('div');
fixture.appendChild(container);
// Player container needs to have height in order to have height
// Don't want to mess with the fixture itself
container.appendChild(player.el());
container.style.height = "1000px";
ok(player.height() === 1000);
player.dispose();
});
test('should accept options from multiple sources and override in correct order', function(){
var tag = PlayerTest.makeTag();
var container = document.createElement('div');
var fixture = document.getElementById('qunit-fixture');
container.appendChild(tag);
fixture.appendChild(container);
var player = new vjs.Player(tag);
var el = player.el();
ok(el.parentNode === container, 'player placed at same level as tag')
// Tag may be placed inside the player element or it may be removed from the DOM
ok(tag.parentNode !== container, 'tag removed from original place')
player.dispose();
});
test('should load a media controller', function(){
var player = PlayerTest.makePlayer({
preload: 'none',
sources: [
{ src: "http://google.com", type: 'video/mp4' },
{ src: "http://google.com", type: 'video/webm' }
]
});
ok(player.el().children[0].className.indexOf('vjs-tech') !== -1, 'media controller loaded')
player.dispose();
});

View File

@ -1 +1 @@
module("Setup");
module("Setup");

View File

@ -1 +0,0 @@
module("Tech");

View File

@ -1 +0,0 @@
module("Tracks");

2014
test/video.compiled.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

2385
test/video.test.compiled.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long