mirror of
https://github.com/videojs/video.js.git
synced 2024-12-25 02:42:10 +02:00
Updated closure compiler build. Starting Flash support.
This commit is contained in:
parent
688b5053ee
commit
e125ee878e
@ -38,9 +38,6 @@ _V_.Component = function(player, options, ready){
|
||||
* Dispose of the component and all child components.
|
||||
*/
|
||||
_V_.Component.prototype.dispose = function(){
|
||||
// Remove all event listeners.
|
||||
this.off();
|
||||
|
||||
// Dispose all children.
|
||||
if (this.children_) {
|
||||
for (var i = this.children_.length - 1; i >= 0; i--) {
|
||||
@ -48,16 +45,20 @@ _V_.Component.prototype.dispose = function(){
|
||||
};
|
||||
}
|
||||
|
||||
// Remove element from DOM
|
||||
if (this.el_.parentNode) {
|
||||
this.el_.parentNode.removeChild(this.el_);
|
||||
}
|
||||
|
||||
// Delete child references
|
||||
this.children_ = null;
|
||||
this.childIndex_ = null;
|
||||
this.childNameIndex_ = null;
|
||||
|
||||
// Remove all event listeners.
|
||||
this.off();
|
||||
|
||||
// Remove element from DOM
|
||||
if (this.el_.parentNode) {
|
||||
this.el_.parentNode.removeChild(this.el_);
|
||||
}
|
||||
|
||||
_V_.removeData(this.el_);
|
||||
this.el_ = null;
|
||||
};
|
||||
|
||||
@ -188,7 +189,7 @@ _V_.Component.prototype.addChild = function(child, options){
|
||||
options = options || {};
|
||||
|
||||
// Assume name of set is a lowercased name of the UI Class (PlayButton, etc.)
|
||||
componentClass = options.componentClass || _V_.uc(componentName);
|
||||
componentClass = options.componentClass || _V_.capitalize(componentName);
|
||||
|
||||
// Set name through options
|
||||
options.name = componentName;
|
||||
@ -577,7 +578,7 @@ _V_.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
|
||||
// TODO: handle display:none and no dimension style using px
|
||||
} else {
|
||||
|
||||
return parseInt(this.el_['offset'+_V_.uc(widthOrHeight)], 10);
|
||||
return parseInt(this.el_['offset'+_V_.capitalize(widthOrHeight)], 10);
|
||||
|
||||
// ComputedStyle version.
|
||||
// Only difference is if the element is hidden it will return
|
||||
|
@ -2,8 +2,9 @@
|
||||
document.createElement("video");document.createElement("audio");
|
||||
|
||||
goog.provide('_V_');
|
||||
goog.provide('VideoJS');
|
||||
|
||||
var _V_ = function(id, options, ready){
|
||||
var VideoJS = function(id, options, ready){
|
||||
var tag; // Element of ID
|
||||
|
||||
// Allow for element or ID to be passed in
|
||||
@ -40,7 +41,7 @@ var _V_ = function(id, options, ready){
|
||||
};
|
||||
|
||||
// Shortcut
|
||||
VideoJS = _V_;
|
||||
// VideoJS = _V_;
|
||||
|
||||
// CDN Version. Used to target right flash swf.
|
||||
CDN_VERSION = "GENERATED_CDN_VSN";
|
||||
@ -69,7 +70,7 @@ _V_.options = {
|
||||
children: {
|
||||
"mediaLoader": {},
|
||||
"posterImage": {},
|
||||
// "textTrackDisplay": {},
|
||||
// // "textTrackDisplay": {},
|
||||
"loadingSpinner": {},
|
||||
"bigPlayButton": {},
|
||||
"controlBar": {}
|
||||
|
@ -68,6 +68,9 @@ _V_.on = function(elem, type, fn){
|
||||
* @param {Function} fn Specific listener to remove. Don't incldue to remove listeners for an event type.
|
||||
*/
|
||||
_V_.off = function(elem, type, fn) {
|
||||
// Don't want to add a cache object through getData if not needed
|
||||
if (!_V_.hasData(elem)) return;
|
||||
|
||||
var data = _V_.getData(elem);
|
||||
|
||||
// If no events exist, nothing to unbind
|
||||
@ -132,9 +135,13 @@ _V_.cleanUpEvents = function(elem, type) {
|
||||
|
||||
// Remove the events object if there are no types left
|
||||
if (_V_.isEmpty(data.handlers)) {
|
||||
data.handlers = null;
|
||||
data.dispatcher = null;
|
||||
data.disabled = null;
|
||||
delete data.handlers;
|
||||
delete data.dispatcher;
|
||||
delete data.disabled;
|
||||
|
||||
// data.handlers = null;
|
||||
// data.dispatcher = null;
|
||||
// data.disabled = null;
|
||||
}
|
||||
|
||||
// Finally remove the expando if there is no data left
|
||||
@ -235,7 +242,9 @@ _V_.fixEvent = function(event) {
|
||||
*/
|
||||
_V_.trigger = function(elem, event) {
|
||||
// Fetches element data and a reference to the parent (for bubbling).
|
||||
var elemData = _V_.getData(elem);
|
||||
// Don't want to add a data object to cache for every parent,
|
||||
// so checking hasData first.
|
||||
var elemData = (_V_.hasData(elem)) ? _V_.getData(elem) : {};
|
||||
var parent = elem.parentNode || elem.ownerDocument;
|
||||
// type = event.type || event,
|
||||
// handler;
|
||||
|
@ -2,6 +2,8 @@ goog.require('_V_');
|
||||
goog.require('_V_.Component');
|
||||
goog.require('_V_.Player');
|
||||
|
||||
goog.exportSymbol('VideoJS', VideoJS);
|
||||
|
||||
goog.exportSymbol('_V_.Component', _V_.Component);
|
||||
goog.exportProperty(_V_.Component.prototype, "dispose", _V_.Component.prototype.dispose);
|
||||
goog.exportProperty(_V_.Component.prototype, "createEl", _V_.Component.prototype.createEl);
|
||||
@ -57,16 +59,21 @@ goog.exportSymbol('_V_.MenuItem', _V_.MenuItem);
|
||||
|
||||
goog.exportSymbol('_V_.MediaTechController', _V_.MediaTechController);
|
||||
|
||||
// Can't figure out why export symbol doesn't work with media controllers
|
||||
goog.exportSymbol('_V_.Html5', _V_.Html5);
|
||||
// goog.exportProperty(_V_, "Html5", _V_.Html5);
|
||||
goog.exportProperty(_V_.Html5, "Supports", _V_.Html5.Supports);
|
||||
goog.exportProperty(_V_.Html5, "Events", _V_.Html5.Events);
|
||||
goog.exportProperty(_V_.Html5, "isSupported", _V_.Html5.isSupported);
|
||||
goog.exportProperty(_V_.Html5, "canPlaySource", _V_.Html5.canPlaySource);
|
||||
|
||||
// goog.exportProperty(_V_.Html5, "isSupported", _V_.Html5.isSupported);
|
||||
// goog.exportProperty(_V_.Html5, "canPlaySource", _V_.Html5.canPlaySource);
|
||||
// Export non-standard HTML5 video API methods.
|
||||
// Standard method names already protected by default externs.
|
||||
goog.exportProperty(_V_.Html5.prototype, "setCurrentTime", _V_.Html5.prototype.setCurrentTime);
|
||||
goog.exportProperty(_V_.Html5.prototype, "setVolume", _V_.Html5.prototype.setVolume);
|
||||
goog.exportProperty(_V_.Html5.prototype, "setMuted", _V_.Html5.prototype.setMuted);
|
||||
goog.exportProperty(_V_.Html5.prototype, "setPreload", _V_.Html5.prototype.setPreload);
|
||||
goog.exportProperty(_V_.Html5.prototype, "setAutoplay", _V_.Html5.prototype.setAutoplay);
|
||||
goog.exportProperty(_V_.Html5.prototype, "setLoop", _V_.Html5.prototype.setLoop);
|
||||
|
||||
goog.exportSymbol('_V_.media', _V_.media);
|
||||
goog.exportSymbol('_V_.media.html5', _V_.media.html5);
|
||||
goog.exportProperty(_V_.media.html5, "isSupported", _V_.media.html5.isSupported);
|
||||
goog.exportProperty(_V_.media.html5, "canPlaySource", _V_.media.html5.canPlaySource);
|
||||
// goog.exportSymbol('_V_.media.html5.canPlaySource', _V_.media.html5.canPlaySource);
|
||||
// goog.exportSymbol('_V_.media.html5.isSupported', _V_.media.html5.isSupported);
|
||||
|
||||
// Allow external components to use global cache
|
||||
goog.exportSymbol('_V_.cache', _V_.cache);
|
||||
|
41
src/lib.js
41
src/lib.js
@ -27,7 +27,7 @@ _V_.createEl = function(tagName, properties){
|
||||
* @param {String} string String to be uppercased
|
||||
* @return {String}
|
||||
*/
|
||||
_V_.uc = function(string){
|
||||
_V_.capitalize = function(string){
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
};
|
||||
|
||||
@ -92,6 +92,31 @@ _V_.bind = function(context, fn, uid) {
|
||||
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.
|
||||
*/
|
||||
_V_.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.
|
||||
@ -127,6 +152,16 @@ _V_.getData = function(el){
|
||||
return _V_.cache[id];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the cache object where data for an element is stored
|
||||
* @param {Element} el Element to store data for.
|
||||
* @return {Object}
|
||||
*/
|
||||
_V_.hasData = function(el){
|
||||
var id = el[_V_.expando];
|
||||
return !(!id || _V_.isEmpty(_V_.cache[id]));
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete data for the element from the cache and the guid attr from getElementById
|
||||
* @param {Element} el Remove data for an element
|
||||
@ -137,7 +172,9 @@ _V_.removeData = function(el){
|
||||
// Remove all stored data
|
||||
// Changed to = null
|
||||
// http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
|
||||
_V_.cache[id] = null;
|
||||
// _V_.cache[id] = null;
|
||||
delete _V_.cache[id];
|
||||
|
||||
// Remove the expando property from the DOM node
|
||||
try {
|
||||
delete el[_V_.expando];
|
||||
|
462
src/media.flash.js
Normal file
462
src/media.flash.js
Normal file
@ -0,0 +1,462 @@
|
||||
goog.provide('_V_.Flash');
|
||||
goog.provide('_V_.media.flash');
|
||||
|
||||
goog.require('_V_.MediaTechController');
|
||||
|
||||
/* VideoJS-SWF - Custom Flash Player with HTML5-ish API - https://github.com/zencoder/video-js-swf
|
||||
================================================================================ */
|
||||
/**
|
||||
* HTML5 Media Controller - Wrapper for HTML5 Media API
|
||||
* @param {_V_.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @param {Function=} ready
|
||||
* @constructor
|
||||
*/
|
||||
_V_.Flash = function(player, options, ready){
|
||||
goog.base(this, player, options, ready);
|
||||
|
||||
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_.isFF) {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
};
|
||||
goog.inherits(_V_.Flash, _V_.MediaTechController);
|
||||
|
||||
_V_.Flash = _V_.PlaybackTech.extend({
|
||||
|
||||
init: function(player, options){
|
||||
|
||||
},
|
||||
|
||||
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
|
||||
progressEvent: false,
|
||||
timeupdateEvent: 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_.isIE()) {
|
||||
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 + "&");
|
||||
});
|
||||
}
|
||||
|
||||
// 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>';
|
||||
};
|
@ -1,5 +1,9 @@
|
||||
goog.provide('_V_.Html5');
|
||||
goog.provide('_V_.media.html5');
|
||||
goog.provide('_V_.Html5.Supports');
|
||||
goog.provide('_V_.Html5.Events');
|
||||
goog.provide('_V_.Html5.isSupported');
|
||||
goog.provide('_V_.Html5.canPlaySource');
|
||||
|
||||
goog.require('_V_.MediaTechController');
|
||||
|
||||
@ -62,7 +66,7 @@ _V_.Html5.prototype.createEl = function(){
|
||||
// Check if this browser supports moving the element into the box.
|
||||
// On the iPhone video will break if you move the element,
|
||||
// So we have to create a brand new element.
|
||||
if (!el || _V_.media.html5.support.movingElementInDOM === false) {
|
||||
if (!el || _V_.Html5.Supports.movingElementInDOM === false) {
|
||||
|
||||
// If the original tag is still there, remove it.
|
||||
if (el) {
|
||||
@ -94,13 +98,13 @@ _V_.Html5.prototype.createEl = function(){
|
||||
// Make video events trigger player events
|
||||
// May seem verbose here, but makes other APIs possible.
|
||||
_V_.Html5.prototype.setupTriggers = function(){
|
||||
for (var i = _V_.media.html5.events.length - 1; i >= 0; i--) {
|
||||
_V_.on(this.el_, _V_.media.html5.events[i], _V_.bind(this.player, this.eventHandler));
|
||||
for (var i = _V_.Html5.Events.length - 1; i >= 0; i--) {
|
||||
_V_.on(this.el_, _V_.Html5.Events[i], _V_.bind(this.player, this.eventHandler));
|
||||
};
|
||||
};
|
||||
_V_.Html5.prototype.removeTriggers = function(){
|
||||
for (var i = _V_.media.html5.events.length - 1; i >= 0; i--) {
|
||||
_V_.off(this.el_, _V_.media.html5.events[i], _V_.bind(this.player, this.eventHandler));
|
||||
for (var i = _V_.Html5.Events.length - 1; i >= 0; i--) {
|
||||
_V_.off(this.el_, _V_.Html5.Events[i], _V_.bind(this.player, this.eventHandler));
|
||||
};
|
||||
// console.log("removeTriggers", _V_.getData(this.el_));
|
||||
};
|
||||
@ -201,11 +205,11 @@ _V_.Html5.prototype.defaultMuted = function(){ return this.el_.defaultMuted; };
|
||||
|
||||
/* HTML5 Support Testing -------------------------------------------------------- */
|
||||
|
||||
_V_.media.html5.isSupported = function(){
|
||||
_V_.Html5.isSupported = function(){
|
||||
return !!document.createElement("video").canPlayType;
|
||||
};
|
||||
|
||||
_V_.media.html5.canPlaySource = function(srcObj){
|
||||
_V_.Html5.canPlaySource = function(srcObj){
|
||||
return !!document.createElement("video").canPlayType(srcObj.type);
|
||||
// TODO: Check Type
|
||||
// If no Type, check ext
|
||||
@ -213,20 +217,20 @@ _V_.media.html5.canPlaySource = function(srcObj){
|
||||
};
|
||||
|
||||
// List of all HTML5 events (various uses).
|
||||
_V_.media.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(",");
|
||||
_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_.media.html5.support = {
|
||||
_V_.Html5.Supports = {
|
||||
|
||||
// Support for video element specific full screen. (webkitEnterFullScreen, not requestFullscreen which we use on the player div)
|
||||
// http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html
|
||||
// Seems to be broken in Chromium/Chrome && Safari in Leopard
|
||||
fullscreen: (_V_.TEST_VID.webkitEnterFullScreen) ? (!_V_.UA.match("Chrome") && !_V_.UA.match("Mac OS X 10.5") ? true : false) : false,
|
||||
'fullscreen': (_V_.TEST_VID.webkitEnterFullScreen) ? (!_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_.IS_IOS
|
||||
'movingElementInDOM': !_V_.IS_IOS
|
||||
|
||||
};
|
||||
|
||||
|
10
src/media.js
10
src/media.js
@ -46,7 +46,11 @@ _V_.apiMethods = "play,pause,paused,currentTime,setCurrentTime,duration,buffered
|
||||
|
||||
// Create placeholder methods for each that warn when a method isn't supported by the current playback technology
|
||||
for (var i = _V_.apiMethods.length - 1; i >= 0; i--) {
|
||||
_V_.MediaTechController.prototype[_V_.apiMethods[i]] = function(){
|
||||
throw new Error("The '"+_V_.apiMethods[i]+"' method is not available on the playback technology's API");
|
||||
};
|
||||
var methodName = _V_.apiMethods[i];
|
||||
|
||||
_V_.MediaTechController.prototype[_V_.apiMethods[i]] = (function(methodName){
|
||||
return function(){
|
||||
throw new Error("The '"+methodName+"' method is not available on the playback technology's API");
|
||||
}
|
||||
})(methodName);
|
||||
};
|
||||
|
182
src/player.js
182
src/player.js
@ -38,10 +38,10 @@ _V_.Player = function(tag, options, ready){
|
||||
this.on("error", this.onError);
|
||||
|
||||
// Tracks defined in tracks.js
|
||||
this.textTracks = [];
|
||||
if (opts.tracks && opts.tracks.length > 0) {
|
||||
this.addTextTracks(opts.tracks);
|
||||
}
|
||||
// this.textTracks = [];
|
||||
// if (opts.tracks && opts.tracks.length > 0) {
|
||||
// this.addTextTracks(opts.tracks);
|
||||
// }
|
||||
|
||||
// Make player easily findable by ID
|
||||
_V_.players[this.id] = this;
|
||||
@ -57,13 +57,13 @@ _V_.Player.prototype.dispose = function(){
|
||||
if (this.el_ && this.el_.player) { this.el_.player = null; }
|
||||
|
||||
// Ensure that tracking progress and time progress will stop and plater deleted
|
||||
// this.stopTrackingProgress();
|
||||
this.stopTrackingProgress();
|
||||
// this.stopTrackingCurrentTime();
|
||||
|
||||
if (this.tech) { this.tech.dispose(); }
|
||||
|
||||
// Component dispose
|
||||
goog.base(this, 'dispose')
|
||||
goog.base(this, 'dispose');
|
||||
};
|
||||
|
||||
_V_.Player.prototype.getTagSettings = function(tag){
|
||||
@ -182,15 +182,15 @@ _V_.Player.prototype.loadTech = function(techName, source){
|
||||
var techReady = function(){
|
||||
this.player.triggerReady();
|
||||
|
||||
// // Manually track progress in cases where the browser/flash player doesn't report it.
|
||||
// if (!this.support.progressEvent) {
|
||||
// this.player.manualProgressOn();
|
||||
// }
|
||||
// Manually track progress in cases where the browser/flash player doesn't report it.
|
||||
if (!window['_V_'][techName]['Supports']['progressEvent']) {
|
||||
this.player.manualProgressOn();
|
||||
}
|
||||
|
||||
// // Manually track timeudpates in cases where the browser/flash player doesn't report it.
|
||||
// if (!this.support.timeupdateEvent) {
|
||||
// this.player.manualTimeUpdatesOn();
|
||||
// }
|
||||
// Manually track timeudpates in cases where the browser/flash player doesn't report it.
|
||||
if (!window['_V_'][techName]['Supports']['timeupdateEvent']) {
|
||||
this.player.manualTimeUpdatesOn();
|
||||
}
|
||||
}
|
||||
|
||||
// Grab tech-specific options from player options and add source and parent element to use.
|
||||
@ -238,86 +238,89 @@ _V_.Player.prototype.loadTech = function(techName, source){
|
||||
================================================================================ */
|
||||
// Manually trigger progress events based on changes to the buffered amount
|
||||
// Many flash players and older HTML5 browsers don't send progress or progress-like events
|
||||
// _V_.Player.prototype.manualProgressOn = function(){
|
||||
// this.manualProgress = true;
|
||||
_V_.Player.prototype.manualProgressOn = function(){
|
||||
this.manualProgress = true;
|
||||
|
||||
// // Trigger progress watching when a source begins loading
|
||||
// this.trackProgress();
|
||||
// Trigger progress watching when a source begins loading
|
||||
this.trackProgress();
|
||||
|
||||
// // Watch for a native progress event call on the tech element
|
||||
// // In HTML5, some older versions don't support the progress event
|
||||
// // So we're assuming they don't, and turning off manual progress if they do.
|
||||
// this.tech.on("progress", function(){
|
||||
var techName = this.techName;
|
||||
|
||||
// // Remove this listener from the element
|
||||
// this.off("progress", arguments.callee);
|
||||
// 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(){
|
||||
|
||||
// // Update known progress support for this playback technology
|
||||
// this.support.progressEvent = true;
|
||||
// Update known progress support for this playback technology
|
||||
window['_V_'][techName]['Supports']['progressEvent'] = true;
|
||||
|
||||
// // Turn off manual progress tracking
|
||||
// this.player.manualProgressOff();
|
||||
// });
|
||||
// };
|
||||
// Turn off manual progress tracking
|
||||
this.player.manualProgressOff();
|
||||
});
|
||||
};
|
||||
|
||||
// _V_.Player.prototype.manualProgressOff = function(){
|
||||
// this.manualProgress = false;
|
||||
// this.stopTrackingProgress();
|
||||
// };
|
||||
_V_.Player.prototype.manualProgressOff = function(){
|
||||
this.manualProgress = false;
|
||||
this.stopTrackingProgress();
|
||||
};
|
||||
|
||||
// _V_.Player.prototype.trackProgress = function(){
|
||||
// this.progressInterval = setInterval(_V_.bind(this, function(){
|
||||
// // Don't trigger unless buffered amount is greater than last time
|
||||
// // log(this.cache_.bufferEnd, this.buffered().end(0), this.duration())
|
||||
// /* TODO: update for multiple buffered regions */
|
||||
// if (this.cache_.bufferEnd < this.buffered().end(0)) {
|
||||
// this.trigger("progress");
|
||||
// } else if (this.bufferedPercent() == 1) {
|
||||
// this.stopTrackingProgress();
|
||||
// this.trigger("progress"); // Last update
|
||||
// }
|
||||
// }), 500);
|
||||
// };
|
||||
// _V_.Player.prototype.stopTrackingProgress = function(){ clearInterval(this.progressInterval); };
|
||||
_V_.Player.prototype.trackProgress = function(){
|
||||
|
||||
// /* Time Tracking -------------------------------------------------------------- */
|
||||
// _V_.Player.prototype.manualTimeUpdatesOn = function(){
|
||||
// this.manualTimeUpdates = true;
|
||||
this.progressInterval = setInterval(_V_.bind(this, function(){
|
||||
// Don't trigger unless buffered amount is greater than last time
|
||||
// log(this.cache_.bufferEnd, this.buffered().end(0), this.duration())
|
||||
/* TODO: update for multiple buffered regions */
|
||||
if (this.cache_.bufferEnd < this.buffered().end(0)) {
|
||||
this.trigger("progress");
|
||||
} else if (this.bufferedPercent() == 1) {
|
||||
this.stopTrackingProgress();
|
||||
this.trigger("progress"); // Last update
|
||||
}
|
||||
}), 500);
|
||||
};
|
||||
_V_.Player.prototype.stopTrackingProgress = function(){ clearInterval(this.progressInterval); };
|
||||
|
||||
// this.on("play", this.trackCurrentTime);
|
||||
// this.on("pause", this.stopTrackingCurrentTime);
|
||||
// // timeupdate is also called by .currentTime whenever current time is set
|
||||
/* Time Tracking -------------------------------------------------------------- */
|
||||
_V_.Player.prototype.manualTimeUpdatesOn = function(){
|
||||
this.manualTimeUpdates = true;
|
||||
|
||||
// // Watch for native timeupdate event
|
||||
// this.tech.on("timeupdate", function(){
|
||||
this.on("play", this.trackCurrentTime);
|
||||
this.on("pause", this.stopTrackingCurrentTime);
|
||||
// timeupdate is also called by .currentTime whenever current time is set
|
||||
|
||||
// // Remove this listener from the element
|
||||
// this.off("timeupdate", arguments.callee);
|
||||
var techName = this.techName;
|
||||
|
||||
// // Update known progress support for this playback technology
|
||||
// this.support.timeupdateEvent = true;
|
||||
// Watch for native timeupdate event
|
||||
this.tech.on("timeupdate", function(){
|
||||
|
||||
// // Turn off manual progress tracking
|
||||
// this.player.manualTimeUpdatesOff();
|
||||
// });
|
||||
// };
|
||||
// Remove this listener from the element
|
||||
this.off("timeupdate", arguments.callee);
|
||||
|
||||
// _V_.Player.prototype.manualTimeUpdatesOff = function(){
|
||||
// this.manualTimeUpdates = false;
|
||||
// this.stopTrackingCurrentTime();
|
||||
// this.off("play", this.trackCurrentTime);
|
||||
// this.off("pause", this.stopTrackingCurrentTime);
|
||||
// };
|
||||
// Update known progress support for this playback technology
|
||||
window['_V_'][techName]['Supports']['timeupdateEvent'] = true;
|
||||
|
||||
// _V_.Player.prototype.trackCurrentTime = function(){
|
||||
// if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); }
|
||||
// this.currentTimeInterval = setInterval(_V_.bind(this, function(){
|
||||
// this.trigger("timeupdate");
|
||||
// }), 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
|
||||
// };
|
||||
// Turn off manual progress tracking
|
||||
this.player.manualTimeUpdatesOff();
|
||||
});
|
||||
};
|
||||
|
||||
// // Turn off play progress tracking (when paused or dragging)
|
||||
// _V_.Player.prototype.stopTrackingCurrentTime = function(){ clearInterval(this.currentTimeInterval); };
|
||||
_V_.Player.prototype.manualTimeUpdatesOff = function(){
|
||||
this.manualTimeUpdates = false;
|
||||
this.stopTrackingCurrentTime();
|
||||
this.off("play", this.trackCurrentTime);
|
||||
this.off("pause", this.stopTrackingCurrentTime);
|
||||
};
|
||||
|
||||
_V_.Player.prototype.trackCurrentTime = function(){
|
||||
if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); }
|
||||
this.currentTimeInterval = setInterval(_V_.bind(this, function(){
|
||||
this.trigger("timeupdate");
|
||||
}), 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
|
||||
};
|
||||
|
||||
// Turn off play progress tracking (when paused or dragging)
|
||||
_V_.Player.prototype.stopTrackingCurrentTime = function(){ clearInterval(this.currentTimeInterval); };
|
||||
|
||||
// /* Player event handlers (how the player reacts to certain events)
|
||||
// ================================================================================ */
|
||||
@ -408,9 +411,10 @@ _V_.Player.prototype.techGet = function(method){
|
||||
|
||||
// When a method isn't available on the object it throws a TypeError
|
||||
if (e.name == "TypeError") {
|
||||
window['e'] = e
|
||||
_V_.log("Video.js: " + method + " unavailable on "+this.techName+" playback technology element.", e);
|
||||
this.tech.isReady_ = false;
|
||||
|
||||
throw e;
|
||||
} else {
|
||||
_V_.log(e);
|
||||
}
|
||||
@ -553,7 +557,7 @@ _V_.Player.prototype.requestFullScreen = function(){
|
||||
|
||||
// Flash and other plugins get reloaded when you take their parent to fullscreen.
|
||||
// To fix that we'll remove the tech, and reload it after the resize has finished.
|
||||
if (window['_V_'][this.techName].support.fullscreenResize === false && this.options.flash.iFrameMode != true) {
|
||||
if (window['_V_'][this.techName]['Supports']['fullscreenResize'] === false && this.options.flash.iFrameMode != true) {
|
||||
|
||||
this.pause();
|
||||
this.unloadTech();
|
||||
@ -591,7 +595,7 @@ _V_.Player.prototype.cancelFullScreen = function(){
|
||||
|
||||
// Flash and other plugins get reloaded when you take their parent to fullscreen.
|
||||
// To fix that we'll remove the tech, and reload it after the resize has finished.
|
||||
if (window['_V_']['media'][this.techName.toLowerCase()].support.fullscreenResize === false && this.options.flash.iFrameMode != true) {
|
||||
if (window['_V_'][this.techName]['Supports']['fullscreenResize'] === false && this.options.flash.iFrameMode != true) {
|
||||
|
||||
this.pause();
|
||||
this.unloadTech();
|
||||
@ -668,19 +672,19 @@ _V_.Player.prototype.selectSource = function(sources){
|
||||
|
||||
// Loop through each playback technology in the options order
|
||||
for (var i=0,j=this.options.techOrder;i<j.length;i++) {
|
||||
var techName = _V_.uc(j[i]),
|
||||
var techName = _V_.capitalize(j[i]),
|
||||
tech = window['_V_'][techName];
|
||||
|
||||
var techInfo = window['_V_']['media'][j[i]];
|
||||
var techInfo = window['_V_'][j[i]];
|
||||
|
||||
// Check if the browser supports this technology
|
||||
if (techInfo.isSupported()) {
|
||||
if (tech.isSupported()) {
|
||||
// Loop through each source object
|
||||
for (var a=0,b=sources;a<b.length;a++) {
|
||||
var source = b[a];
|
||||
|
||||
// Check if source can be played with this technology
|
||||
if (techInfo.canPlaySource(source)) {
|
||||
if (tech['canPlaySource'](source)) {
|
||||
return { source: source, tech: techName };
|
||||
}
|
||||
}
|
||||
@ -721,7 +725,7 @@ _V_.Player.prototype.src = function(source){
|
||||
// Case: Source object { src: "", type: "" ... }
|
||||
} else if (source instanceof Object) {
|
||||
|
||||
if (window['_V_']['media'][this.techName.toLowerCase()].canPlaySource(source)) {
|
||||
if (window['_V_'][this.techName]['canPlaySource'](source)) {
|
||||
this.src(source.src);
|
||||
} else {
|
||||
// Send through tech loop to check for a compatible technology.
|
||||
@ -879,13 +883,13 @@ _V_.MediaLoader = function(player, options, ready){
|
||||
// load the first supported playback technology.
|
||||
if (!player.options.sources || player.options.sources.length == 0) {
|
||||
for (var i=0,j=player.options.techOrder; i<j.length; i++) {
|
||||
var techName = _V_.uc(j[i]),
|
||||
var techName = _V_.capitalize(j[i]),
|
||||
tech = window['_V_'][techName];
|
||||
|
||||
var techInfo = window['_V_']['media'][j[i]];
|
||||
var techInfo = window['_V_'][j[i]];
|
||||
|
||||
// Check if the browser supports this technology
|
||||
if (tech && techInfo.isSupported()) {
|
||||
if (tech && tech.isSupported()) {
|
||||
player.loadTech(techName);
|
||||
break;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ _V_.Player.prototype.addTextTracks = function(trackObjects){
|
||||
for (;i<j;i++) {
|
||||
// HTML5 Spec says default to subtitles.
|
||||
// Uppercase (uc) first letter to match class names
|
||||
Kind = _V_.uc(trackObjects[i].kind || "subtitles");
|
||||
Kind = _V_.capitalize(trackObjects[i].kind || "subtitles");
|
||||
|
||||
// Create correct texttrack class. CaptionsTrack, etc.
|
||||
track = new _V_[Kind + "Track"](this, trackObjects[i]);
|
||||
@ -592,7 +592,7 @@ _V_.TextTrackButton.prototype.createMenu = function(){
|
||||
// Add a title list item to the top
|
||||
menu.el.appendChild(_V_.createElement("li", {
|
||||
className: "vjs-menu-title",
|
||||
innerHTML: _V_.uc(this.kind)
|
||||
innerHTML: _V_.capitalize(this.kind)
|
||||
}));
|
||||
|
||||
// Add an OFF menu item to turn all tracks off
|
||||
@ -721,7 +721,7 @@ _V_.ChaptersButton.prototype.createMenu = function(){
|
||||
|
||||
menu.el.appendChild(_V_.createElement("li", {
|
||||
className: "vjs-menu-title",
|
||||
innerHTML: _V_.uc(this.kind)
|
||||
innerHTML: _V_.capitalize(this.kind)
|
||||
}));
|
||||
|
||||
if (chaptersTrack) {
|
||||
|
@ -41,7 +41,7 @@ test('should format the time', function(){
|
||||
});
|
||||
|
||||
test('should uppercase a word', function(){
|
||||
ok(_V_.uc('asdf') === "Asdf");
|
||||
ok(_V_.capitalize('asdf') === "Asdf");
|
||||
});
|
||||
|
||||
test('should trim a string', function(){
|
||||
@ -66,4 +66,4 @@ test('should create a fake timerange', function(){
|
||||
ok(tr.start() === 0);
|
||||
ok(tr.end() === 100);
|
||||
ok(tr.length === 1);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user