Permalink
Browse files

Optimized slider controls.

Fixed issue with fullscreen progress bar tracking (offset left wasn't working in new fullscreen)
  • Loading branch information...
1 parent afc9369 commit e4f6bbb0b2a6c3f61748ec0e4902fde9e5a335ed Steve Heffernan committed Dec 5, 2011
Showing with 235 additions and 1,313 deletions.
  1. 0 LICENSE.txt → LGPLv3-LICENSE.txt
  2. +1 −1 design/video-js.css
  3. +2 −5 src/component.js
  4. +182 −192 src/controls.js
  5. +38 −8 src/lib.js
  6. +8 −2 src/player.js
  7. +0 −671 src/player.js.orig
  8. +4 −3 src/tech.js
  9. +0 −431 src/tech.js.orig
View
0 LICENSE.txt → LGPLv3-LICENSE.txt
File renamed without changes.
View
2 design/video-js.css
@@ -79,7 +79,7 @@ so you can upgrade to newer versions easier. You can remove all these styles by
}
.vjs-default-skin .vjs-control:focus {
- outline: 0;
+/* outline: 0;*/
}
/* Hide control text visually, but have it available for screenreaders: h5bp.com/v */
View
7 src/component.js
@@ -61,11 +61,8 @@ _V_.Component = _V_.Class.extend({
destroy: function(){},
- createElement: function(type, options){
- options = _V_.merge({
- /* Standar Options */
- }, options || {});
- return _V_.createElement(type || "div", options);
+ createElement: function(type, attrs){
+ return _V_.createElement(type || "div", attrs);
},
buildCSSClass: function(){
View
374 src/controls.js
@@ -1,9 +1,6 @@
/* Control - Base class for all control elements
================================================================================ */
_V_.Control = _V_.Component.extend({
- init: function(player, options){
- this._super(player, options);
- },
buildCSSClass: function(){
return "vjs-control " + this._super();
@@ -18,27 +15,21 @@ _V_.Button = _V_.Control.extend({
init: function(player, options){
this._super(player, options);
- _V_.addEvent(this.el, "click", _V_.proxy(this, this.onClick));
- _V_.addEvent(this.el, "focus", _V_.proxy(this, this.onFocus));
- _V_.addEvent(this.el, "blur", _V_.proxy(this, this.onBlur));
-
- return "fdsa";
+ this.addEvent("click", this.onClick);
+ this.addEvent("focus", this.onFocus);
+ this.addEvent("blur", this.onBlur);
},
createElement: function(type, attrs){
- // Default to Div element
- type = type || "div";
-
// Add standard Aria and Tabindex info
attrs = _V_.merge({
+ className: this.buildCSSClass(),
+ innerHTML: '<div><span class="vjs-control-text">' + (this.buttonText || "Need Text") + '</span></div>',
role: "button",
tabIndex: 0
- }, attrs || {});
+ }, attrs);
- return this._super(type, {
- className: attrs.className || this.buildCSSClass(),
- innerHTML: attrs.innerHTML || '<div><span class="vjs-control-text">' + (this.buttonText || "Need Text") + '</span></div>'
- });
+ return this._super(type, attrs);
},
// Click - Override with specific functionality for button
@@ -186,8 +177,8 @@ _V_.ControlBar = _V_.Component.extend({
init: function(player, options){
this._super(player, options);
- // player.addEvent("mouseover", _V_.proxy(this, this.show));
- // player.addEvent("mouseout", _V_.proxy(this, this.hide));
+ player.addEvent("mouseover", _V_.proxy(this, this.show));
+ player.addEvent("mouseout", _V_.proxy(this, this.hide));
},
createElement: function(){
@@ -312,6 +303,138 @@ _V_.RemainingTimeDisplay = _V_.Component.extend({
});
+/* Slider - Parent for seek bar and volume slider
+================================================================================ */
+_V_.Slider = _V_.Component.extend({
+
+ init: function(player, options){
+ this._super(player, options);
+
+ _V_.each.call(this, this.components, function(comp){
+ if (comp instanceof _V_[this.barClass]) {
+ this.bar = comp;
+ } else if (comp instanceof _V_[this.handleClass]) {
+ this.handle = comp;
+ }
+ });
+
+ player.addEvent(this.playerEvent, _V_.proxy(this, this.update));
+
+ this.addEvent("mousedown", this.onMouseDown);
+ this.addEvent("focus", this.onFocus);
+ this.addEvent("blur", this.onBlur);
+ },
+
+ createElement: function(type, attrs) {
+ attrs = _V_.merge({
+ role: "slider",
+ "aria-valuenow": 0,
+ "aria-valuemin": 0,
+ "aria-valuemax": 100,
+ tabIndex: 0
+ }, attrs);
+
+ return this._super(type, attrs);
+ },
+
+ onMouseDown: function(event){
+ event.preventDefault();
+ _V_.blockTextSelection();
+
+ _V_.addEvent(document, "mousemove", _V_.proxy(this, this.onMouseMove));
+ _V_.addEvent(document, "mouseup", _V_.proxy(this, this.onMouseUp));
+
+ this.onMouseMove(event);
+ },
+
+ onMouseUp: function(event) {
+ _V_.unblockTextSelection();
+ _V_.removeEvent(document, "mousemove", this.onMouseMove, false);
+ _V_.removeEvent(document, "mouseup", this.onMouseUp, false);
+ },
+
+ update: function(){
+ // If scrubbing, we could use a cached value to make the handle keep up with the user's mouse.
+ // On HTML5 browsers scrubbing is really smooth, but some flash players are slow, so we might want to utilize this later.
+ // var progress = (this.player.scrubbing) ? this.player.values.currentTime / this.player.duration() : this.player.currentTime() / this.player.duration();
+
+ var progress = this.getPercent();
+ handle = this.handle,
+ bar = this.bar,
+ barProgress = progress;
+
+ // Protect against no duration and other division issues
+ if (isNaN(progress)) { progress = 0; }
+
+ // If there is a handle, we need to account for the handle in our calculation for progress bar
+ // so that it doesn't fall short of or extend past the handle.
+ if (handle) {
+ var box = this.el,
+ boxWidth = box.offsetWidth,
+
+ // The width of the handle in percent of the containing box
+ handlePercent = handle.el.offsetWidth / boxWidth,
+
+ // Get the adjusted size of the box, considering that the handle's center never touches the left or right side.
+ // There is a margin of half the handle's width on both sides.
+ boxAdjustedPercent = 1 - handlePercent;
+
+ // Adjust the progress that we'll use to set widths to the new adjusted box width
+ adjustedProgress = progress * boxAdjustedPercent,
+
+ // The bar does reach the left side, so we need to account for this in the bar's width
+ barProgress = adjustedProgress + (handlePercent / 2);
+
+ // Move the handle from the left based on the adjected progress
+ handle.el.style.left = _V_.round(adjustedProgress * 100, 2) + "%";
+ }
+
+ // Set the new bar width
+ bar.el.style.width = _V_.round(barProgress * 100, 2) + "%";
+ },
+
+ calculateDistance: function(event){
+ var box = this.el,
+ boxX = _V_.findPosX(box),
+ boxW = box.offsetWidth,
+ handle = this.handle;
+
+ // _V_.log(box.offsetLeft, box.offsetLeft)
+
+ if (handle) {
+ var handleW = handle.el.offsetWidth;
+
+ // Adjusted X and Width, so handle doesn't go outside the bar
+ boxX = boxX + (handleW / 2);
+ boxW = boxW - handleW;
+ }
+
+ // _V_.log(event.pageX, boxX, boxW);
+
+ // Percent that the click is through the adjusted area
+ return Math.max(0, Math.min(1, (event.pageX - boxX) / boxW));
+ },
+
+ onFocus: function(event){
+ _V_.addEvent(document, "keyup", _V_.proxy(this, this.onKeyPress));
+ },
+
+ onKeyPress: function(event){
+ if (event.which == 37) { // Left Arrow
+ event.preventDefault();
+ this.stepBack();
+ } else if (event.which == 39) { // Right Arrow
+ event.preventDefault();
+ this.stepForward();
+ }
+ },
+
+ onBlur: function(event){
+ _V_.removeEvent(document, "keyup", _V_.proxy(this, this.onKeyPress));
+ }
+});
+
+
/* Progress
================================================================================ */
@@ -327,28 +450,14 @@ _V_.ProgressControl = _V_.Component.extend({
});
// Seek Bar and holder for the progress bars
-_V_.SeekBar = _V_.Component.extend({
+_V_.SeekBar = _V_.Slider.extend({
+
+ barClass: "PlayProgressBar",
+ handleClass: "SeekHandle",
+ playerEvent: "timeupdate",
init: function(player, options){
this._super(player, options);
-
- _V_.each.call(this, this.components, function(comp){
- if (comp instanceof _V_.PlayProgressBar) {
- this.playProgressBar = comp;
- } else if (comp instanceof _V_.SeekHandle) {
- this.seekHandle = comp;
- }
- });
-
- player.addEvent("timeupdate", _V_.proxy(this, this.update));
-
- _V_.addEvent(this.el, "mousedown", _V_.proxy(this, this.onMouseDown));
- _V_.addEvent(this.el, "focus", _V_.proxy(this, this.onFocus));
- _V_.addEvent(this.el, "blur", _V_.proxy(this, this.onBlur));
-
- // _V_.addEvent(element, "mousedown", _V_.proxy(element, function(event){
- // player.onSeekBarMouseDown(event, this);
- // }));
},
createElement: function(){
@@ -357,66 +466,21 @@ _V_.SeekBar = _V_.Component.extend({
});
},
- update: function(){
- // If scrubbing, use the cached currentTime value for speed
- var progress = /* (this.player.scrubbing) ? this.player.values.currentTime / this.player.duration() : */ this.player.currentTime() / this.player.duration();
- // Protect against no duration and other division issues
- if (isNaN(progress)) { progress = 0; }
-
- var // barData = _V_.getData(bar),
- barX = _V_.findPosX(this.el),
- barW = this.el.offsetWidth,
- handle = this.seekHandle,
- progBar = this.playProgressBar,
- handleW = (handle) ? handle.el.offsetWidth : 0;
-
- // Adjusted X and Width, so handle doesn't go outside the bar
- barAX = barX + (handleW / 2),
- barAW = barW - handleW,
- progBarProgress = _V_.round(progress * barAW + handleW / 2) + "px";
-
- if (progBar && progBar.el.style) {
- progBar.el.style.width = progBarProgress;
- }
-
- if (handle) {
- handle.el.style.left = _V_.round(progress * barAW)+"px";
- }
+ getPercent: function(){
+ return this.player.currentTime() / this.player.duration();
},
onMouseDown: function(event){
- event.preventDefault();
- _V_.blockTextSelection();
-
- this.player.currSeekBar = this;
- this.player.currHandle = this.seekHandle || false;
+ this._super(event);
this.player.scrubbing = true;
- this.player.videoWasPlaying = !this.player.paused();
+ this.videoWasPlaying = !this.player.paused();
this.player.pause();
-
- this.setCurrentTimeWithScrubber(event);
- _V_.addEvent(document, "mousemove", _V_.proxy(this, this.onMouseMove));
- _V_.addEvent(document, "mouseup", _V_.proxy(this, this.onMouseUp));
},
- setCurrentTimeWithScrubber: function(event){
- var bar = this.el,
- barX = _V_.findPosX(bar),
- barW = bar.offsetWidth,
- handle = this.player.currHandle.el,
- handleW = (handle) ? handle.offsetWidth : 0;
-
- // Adjusted X and Width, so handle doesn't go outside the bar
- barAX = barX + (handleW / 2),
- barAW = barW - handleW,
- // Percent that the click is through the adjusted area
- percent = Math.max(0, Math.min(1, (event.pageX - barAX) / barAW)),
- // Percent translated to pixels
- percentPix = percent * barAW,
- // Percent translated to seconds
- newTime = percent * this.player.duration();
+ onMouseMove: function(event){
+ var newTime = this.calculateDistance(event) * this.player.duration();
// Don't let video end while scrubbing.
if (newTime == this.player.duration()) { newTime = newTime - 0.1; }
@@ -425,33 +489,21 @@ _V_.SeekBar = _V_.Component.extend({
this.player.currentTime(newTime);
},
- onMouseMove: function(event){ // Removeable
- this.setCurrentTimeWithScrubber(event);
- },
- onMouseUp: function(event){ // Removeable
- _V_.unblockTextSelection();
- _V_.removeEvent(document, "mousemove", this.onMouseMove, false);
- _V_.removeEvent(document, "mouseup", this.onMouseUp, false);
+ onMouseUp: function(event){
+ this._super(event);
+
this.player.scrubbing = false;
- if (this.player.videoWasPlaying) {
+ if (this.videoWasPlaying) {
this.player.play();
}
},
- onFocus: function(event){
- _V_.addEvent(document, "keyup", _V_.proxy(this, this.onKeyPress));
- },
- onKeyPress: function(event){
- if (event.which == 37) {
- event.preventDefault();
- this.player.currentTime(this.player.currentTime() - 1);
- } else if (event.which == 39) {
- event.preventDefault();
- this.player.currentTime(this.player.currentTime() + 1);
- }
+ stepForward: function(){
+ this.player.currentTime(this.player.currentTime() + 1);
},
- onBlur: function(event){
- _V_.removeEvent(document, "keyup", _V_.proxy(this, this.onKeyPress));
+
+ stepBack: function(){
+ this.player.currentTime(this.player.currentTime() - 1);
}
});
@@ -497,9 +549,7 @@ _V_.SeekHandle = _V_.Component.extend({
createElement: function(){
return this._super("div", {
className: "vjs-seek-handle",
- innerHTML: '<span class="vjs-control-text">00:00</span>',
- tabIndex: 0,
- role: "slider", "aria-valuenow": 0, "aria-valuemin": 0, "aria-valuemax": 100
+ innerHTML: '<span class="vjs-control-text">00:00</span>'
});
}
@@ -518,96 +568,33 @@ _V_.VolumeControl = _V_.Component.extend({
});
-_V_.VolumeBar = _V_.Component.extend({
-
- init: function(player, options){
- this._super(player, options);
+_V_.VolumeBar = _V_.Slider.extend({
- _V_.each.call(this, this.components, function(comp){
- if (comp instanceof _V_.VolumeLevel) {
- this.volumeLevel = comp;
- } else if (comp instanceof _V_.VolumeHandle) {
- this.volumeHandle = comp;
- }
- });
-
- player.addEvent("volumechange", _V_.proxy(this, this.update));
-
- _V_.addEvent(this.el, "mousedown", _V_.proxy(this, this.onMouseDown));
- // _V_.addEvent(this.el, "focus", _V_.proxy(this, this.onFocus));
- // _V_.addEvent(this.el, "blur", _V_.proxy(this, this.onBlur));
- },
+ barClass: "VolumeLevel",
+ handleClass: "VolumeHandle",
+ playerEvent: "volumechange",
createElement: function(){
return this._super("div", {
className: "vjs-volume-bar"
});
},
- onMouseDown: function(event){
- event.preventDefault();
- _V_.blockTextSelection();
-
- this.player.currVolumeBar = this;
- this.player.currHandle = this.volumeHandle || false;
-
- this.setVolumeWithSlider(event);
- _V_.addEvent(document, "mousemove", _V_.proxy(this, this.onMouseMove));
- _V_.addEvent(document, "mouseup", _V_.proxy(this, this.onMouseUp));
- },
- onMouseMove: function(event){ // Removeable
- this.setVolumeWithSlider(event);
- },
- onMouseUp: function(event){ // Removeable
- _V_.unblockTextSelection();
- _V_.removeEvent(document, "mousemove", this.onMouseMove, false);
- _V_.removeEvent(document, "mouseup", this.onMouseUp, false);
+ onMouseMove: function(event) {
+ this.player.volume(this.calculateDistance(event));
},
- setVolumeWithSlider: function(event){
- var bar = this.el,
- barX = _V_.findPosX(bar),
- barW = bar.offsetWidth,
- handle = (this.player.currHandle) ? this.player.currHandle.el : false,
- handleW = (handle) ? handle.offsetWidth : 0;
-
- // Adjusted X and Width, so handle doesn't go outside the bar
- barAX = barX + (handleW / 2),
- barAW = barW - handleW,
- // Percent that the click is through the adjusted area
- percent = Math.max(0, Math.min(1, (event.pageX - barAX) / barAW)),
- // Percent translated to pixels
- percentPix = percent * barAW,
- // Percent translated to seconds
- newTime = percent * this.player.duration();
-
- this.player.volume(percent);
+ getPercent: function(){
+ return this.player.volume();
},
- update: function(){
- var vol = this.player.volume();
-
- var bar = this.el;
- barX = _V_.findPosX(bar),
- barW = bar.offsetWidth,
- handle = (this.volumeHandle) ? this.volumeHandle.el : false,
- level = (this.volumeLevel) ? this.volumeLevel.el : false,
- handleW = (handle) ? handle.offsetWidth : 0;
-
- // Adjusted X and Width, so handle doesn't go outside the bar
- barAX = barX + (handleW / 2),
- barAW = barW - handleW,
- progBarProgress = _V_.round(vol * barAW + handleW / 2) + "px";
-
- if (level) {
- level.style.width = progBarProgress;
- }
-
- if (handle) {
- handle.style.left = _V_.round(vol * barAW)+"px";
- }
- }
+ stepForward: function(){
+ this.player.volume(this.player.volume() + 0.1);
+ },
+ stepBack: function(){
+ this.player.volume(this.player.volume() - 0.1);
+ }
});
_V_.VolumeLevel = _V_.Component.extend({
@@ -626,9 +613,9 @@ _V_.VolumeHandle = _V_.Component.extend({
createElement: function(){
return this._super("div", {
className: "vjs-volume-handle",
- innerHTML: '<span class="vjs-control-text"></span>',
- tabindex: 0,
- role: "slider", "aria-valuenow": 0, "aria-valuemin": 0, "aria-valuemax": 100
+ innerHTML: '<span class="vjs-control-text"></span>'
+ // tabindex: 0,
+ // role: "slider", "aria-valuenow": 0, "aria-valuemin": 0, "aria-valuemax": 100
});
}
@@ -708,16 +695,19 @@ _V_.SubtitlesDisplay = _V_.TextTrackDisplay.extend({
trackType: "subtitles"
});
+
_V_.CaptionsDisplay = _V_.TextTrackDisplay.extend({
trackType: "captions"
});
+
_V_.ChaptersDisplay = _V_.TextTrackDisplay.extend({
trackType: "chapters"
});
+
_V_.DescriptionsDisplay = _V_.TextTrackDisplay.extend({
trackType: "descriptions"
View
46 src/lib.js
@@ -1,4 +1,7 @@
_V_.merge = function(obj1, obj2, safe){
+ // Make sure second object exists
+ if (!obj2) { obj2 = {}; };
+
for (var attrname in obj2){
if (obj2.hasOwnProperty(attrname) && (!safe || !obj1.hasOwnProperty(attrname))) { obj1[attrname]=obj2[attrname]; }
}
@@ -128,14 +131,7 @@ _V_.extend({
getRelativePosition: function(x, relativeElement){
return Math.max(0, Math.min(1, (x - _V_.findPosX(relativeElement)) / relativeElement.offsetWidth));
},
- // Get an objects position on the page
- findPosX: function(obj) {
- var curleft = obj.offsetLeft;
- while(obj = obj.offsetParent) {
- curleft += obj.offsetLeft;
- }
- return curleft;
- },
+
getComputedStyleValue: function(element, style){
return window.getComputedStyle(element, null).getPropertyValue(style);
},
@@ -300,4 +296,38 @@ _V_.log = function(){
(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
+if ("getBoundingClientRect" in document.documentElement) {
+ _V_.findPosX = function(el) {
+ var box;
+ try {
+ box = el.getBoundingClientRect();
+ } catch(e) {}
+
+ if (!box) { return 0; }
+
+ var docEl = document.documentElement,
+ body = document.body,
+ clientLeft = docEl.clientLeft || body.clientLeft || 0,
+ scrollLeft = window.pageXOffset || body.scrollLeft,
+ left = box.left + scrollLeft - clientLeft;
+
+ return left;
+ };
+} else {
+ _V_.findPosX = function(el) {
+ var curleft = el.offsetLeft;
+ // _V_.log(obj.className, obj.offsetLeft)
+ while(el = obj.offsetParent) {
+ if (el.className.indexOf("video-js") == -1) {
+ // _V_.log(el.offsetParent, "OFFSETLEFT", el.offsetLeft)
+ // _V_.log("-webkit-full-screen", el.webkitMatchesSelector("-webkit-full-screen"));
+ // _V_.log("-webkit-full-screen", el.querySelectorAll(".video-js:-webkit-full-screen"));
+ } else {
+ }
+ curleft += el.offsetLeft;
+ }
+ return curleft;
+ };
+}
View
10 src/player.js
@@ -362,9 +362,15 @@ _V_.Player.prototype.extend({
currentTime: function(seconds){
if (seconds !== undefined) {
- this.values.currentTime = seconds; // Cache the last set value for smoother scrubbing.
+
+ // Cache the last set value for smoother scrubbing.
+ this.values.currentTime = seconds;
+
this.apiCall("setCurrentTime", seconds);
- if (this.manualTimeUpdates) { this.triggerEvent("timeupdate"); }
+
+ if (this.manualTimeUpdates) {
+ this.triggerEvent("timeupdate");
+ }
return this;
}
return this.apiCall("currentTime");
View
671 src/player.js.orig
@@ -1,671 +0,0 @@
-/* UI Component- Base class for all UI objects
-================================================================================ */
-_V_.Player = _V_.Component.extend({
-
- init: function(tag, addOptions, ready){
-
- this.tag = tag; // Store the original tag used to set options
-
- var el = this.el = _V_.createElement("div"), // Div to contain video and controls
- options = this.options = {},
- width = options.width = tag.width,
- height = options.height = tag.height,
-
- // Browsers default to 300x150 if there's no width/height or video size data.
- initWidth = width || 300,
- initHeight = height || 150;
-
- // Make player findable on elements
- tag.player = el.player = this;
-
- // Add callback to ready queue
- this.ready(ready);
-
- // Wrap video tag in div (el/box) container
- tag.parentNode.insertBefore(el, tag);
- el.appendChild(tag); // Breaks iPhone, fixed in HTML5 setup.
-
- // Give video tag properties to box
- el.id = this.id = tag.id; // ID will now reference box, not the video tag
- el.className = tag.className;
- // Update tag id/class for use as HTML5 playback tech
- tag.id += "_html5_api";
- tag.className = "vjs-tech";
-
- // Make player easily findable by ID
- _V_.players[el.id] = this;
-
- // Make box use width/height of tag, or default 300x150
- el.setAttribute("width", initWidth);
- el.setAttribute("height", initHeight);
- // Enforce with CSS since width/height attrs don't work on divs
- el.style.width = initWidth+"px";
- el.style.height = initHeight+"px";
- // Remove width/height attrs from tag so CSS can make it 100% width/height
- tag.removeAttribute("width");
- tag.removeAttribute("height");
-
- // Set Options
- _V_.merge(options, _V_.options); // Copy Global Defaults
- _V_.merge(options, this.getVideoTagSettings()); // Override with Video Tag Options
- _V_.merge(options, addOptions); // Override/extend with options from setup call
-
- // Store controls setting, and then remove immediately so native controls don't flash.
- tag.removeAttribute("controls");
-
- // Empty video tag sources and tracks so the built in player doesn't use them also.
- if (tag.hasChildNodes()) {
- for (var i=0,j=tag.childNodes;i<j.length;i++) {
- if (j[i].nodeName == "SOURCE" || j[i].nodeName == "TRACK") {
- tag.removeChild(j[i]);
- }
- }
- }
-
- // Holder for playback tech components
- this.techs = {};
-
- // Cache for video property values.
- this.values = {};
-
- this.addClass("vjs-paused");
-
- this.addEvent("ended", this.onEnded);
- this.addEvent("play", this.onPlay);
- this.addEvent("pause", this.onPause);
- this.addEvent("error", this.onError);
-
- // When the API is ready, loop through the components and add to the player.
- if (this.options.controls) {
- this.ready(function(){
- this.each(this.options.components, function(set){
- this.addComponent(set);
- });
- });
- }
-
- // If there are no sources when the player is initialized,
- // load the first supported playback technology.
- if (!this.options.sources || this.options.sources.length == 0) {
- for (var i=0,j=this.options.techOrder;i<j.length;i++) {
- var techName = j[i],
- tech = _V_[techName];
-
- // Check if the browser supports this technology
- if (tech.isSupported()) {
- this.loadTech(techName);
- break;
- }
- }
- } else {
- // Loop through playback technologies (HTML5, Flash) and check for support
- // Then load the best source.
- this.src(this.options.sources);
- }
- },
-
- // Cache for video property values.
- values: {},
-
- destroy: function(){},
-
- createElement: function(type, options){
-
- },
-
- getVideoTagSettings: function(){
- var options = {
- sources: [],
- tracks: []
- };
-
- options.src = this.tag.src;
- options.controls = this.tag.getAttribute("controls") !== null;
- options.poster = this.tag.poster;
- options.preload = this.tag.preload;
- options.autoplay = this.tag.getAttribute("autoplay") !== null; // hasAttribute not IE <8 compatible
- options.loop = this.tag.getAttribute("loop") !== null;
- options.muted = this.tag.getAttribute("muted") !== null;
-
- for (var c,i=0,j=this.tag.children;i<j.length;i++) {
- c = j[i];
- if (c.nodeName == "SOURCE") {
- options.sources.push({
- src: c.src,
- type: c.type,
- media: c.media,
- title: c.title
- });
- }
- if (c.nodeName == "TRACK") {
- options.tracks.push(new _V_.Track({
- src: c.getAttribute("src"),
- kind: c.getAttribute("kind"),
- srclang: c.getAttribute("srclang"),
- label: c.getAttribute("label"),
- 'default': c.getAttribute("default") !== null,
- title: c.getAttribute("title")
- }, this));
-
- }
- }
- return options;
- },
-
- /* PLayback Technology (tech)
- ================================================================================ */
- // Load/Create an instance of playback technlogy including element and API methods
- // And append playback element in player div.
- loadTech: function(techName, source){
-
- this.triggerEvent("loadingtech");
-
- // Pause and remove current playback technology
- if (this.tech) {
- this.removeTech(this.tech);
-
- // Turn off any manual progress or timeupdate tracking
- if (this.manualProgress) {
- this.manualProgressOff()
- }
-
- if (this.manualTimeUpdates) {
- this.manualTimeUpdatesOff()
- }
-
- // If the first time loading, HTML5 tag will exist but won't be initialized
- // So we need to remove it if we're not loading HTML5
- } else if (!this.tech && techName != "HTML5") {
- this.removeTechElement(this.tag);
- }
-
- this.techName = techName;
-
- // Turn off API access because we're loading a new tech that might load asynchronously
- this.isReady = false;
-
- var techReady = function(){
- // Set up playback technology's event triggers
- this.setupTriggers();
- this.player.triggerReady();
-
- // Manually track progress in cases where the browser/flash player doesn't report it.
- if (!_V_.techSupports(this.name, "event", "progress")) {
- this.player.manualProgressOn();
- }
-
- // Manually track timeudpates in cases where the browser/flash player doesn't report it.
- if (!_V_.techSupports(this.name, "event", "timeupdate")) {
- this.player.manualTimeUpdatesOn();
- }
- }
-
- // Initialize new tech if it hasn't been yet and load source
- // Add tech element to player div
- if (this.techs[techName] === undefined) {
- this.techs[techName] = this.tech = new _V_[techName](this, { source: source });
- this.tech.ready(techReady)
- } else {
- this.tech = this.techs[techName];
- _V_.log("here3")
- _V_.insertFirst(this.techs[techName].el, this.el);
- this.src(source);
- }
- },
-
- removeTech: function(tech){
- this.removeTechElement(tech.el);
- // TODO: Remove API listeners as well
- },
-
- removeTechElement: function(el){
- this.el.removeChild(el);
- },
-
- /* Fallbacks for unsupported event types
- ================================================================================ */
- // Manually trigger progress events based on changes to the buffered amount
- // Many flash players and older HTML5 browsers don't send progress or progress-like events
- manualProgressOn: function(){
- this.manualProgress = true;
-
- // Trigger progress watching when a source begins loading
- this.trackProgress();
-
- // Watch for a native progress event call on the tech element
- // In HTML5, some older versions don't support the progress event
- // So we're assuming they don't, and turning off manual progress if they do.
- this.tech.addEvent("progress", function(){
-
- // Remove this listener from the element
- this.removeEvent("progress", arguments.callee);
-
- // Update known progress support for this playback technology
- _V_.updateTechSupport(this.name, "event", "progress", true);
-
- // Turn off manual progress tracking
- this.player.manualProgressOff();
- });
- },
-
- manualProgressOff: function(){
- this.manualProgress = false;
- this.stopTrackingProgress();
- },
-
- trackProgress: function(){
- this.progressInterval = setInterval(_V_.proxy(this, function(){
- // Don't trigger unless buffered amount is greater than last time
- // log(this.values.bufferEnd, this.buffered().end(0), this.duration())
- /* TODO: update for multiple buffered regions */
- if (this.values.bufferEnd < this.buffered().end(0)) {
- this.triggerEvent("progress");
- } else if (this.bufferedPercent() == 1) {
- this.stopTrackingProgress();
- this.triggerEvent("progress"); // Last update
- }
- }), 500);
- },
- stopTrackingProgress: function(){ clearInterval(this.progressInterval); },
-
- /* Time Tracking -------------------------------------------------------------- */
- manualTimeUpdatesOn: function(){
- this.manualTimeUpdates = true;
-
- this.addEvent("play", this.trackCurrentTime);
- this.addEvent("pause", this.stopTrackingCurrentTime);
- // timeupdate is also called by .currentTime whenever current time is set
-
- // Watch for native timeupdate event
- this.tech.addEvent("timeupdate", function(){
-
- // Remove this listener from the element
- this.removeEvent("timeupdate", arguments.callee);
-
- // Update known progress support for this playback technology
- _V_.updateTechSupport(this.name, "event", "timeupdate", true);
-
- // Turn off manual progress tracking
- this.player.manualTimeUpdatesOff();
- });
- },
-
- manualTimeUpdatesOff: function(){
- this.manualTimeUpdates = false;
- this.stopTrackingCurrentTime();
- this.removeEvent("play", this.trackCurrentTime);
- this.removeEvent("pause", this.stopTrackingCurrentTime);
- },
-
- trackCurrentTime: function(){
- if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); }
- this.currentTimeInterval = setInterval(_V_.proxy(this, function(){
- this.triggerEvent("timeupdate");
- }), 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
- },
-
- // Turn off play progress tracking (when paused or dragging)
- stopTrackingCurrentTime: function(){ clearInterval(this.currentTimeInterval); },
-
- /* Player event handlers (how the player reacts to certain events)
- ================================================================================ */
- onEnded: function(){
- if (this.options.loop) {
- this.currentTime(0);
- this.play();
- } else {
- // this.pause();
- // this.currentTime(0);
- // this.pause();
- }
- },
-
- onPlay: function(){
- _V_.removeClass(this.el, "vjs-paused");
- _V_.addClass(this.el, "vjs-playing");
- },
-
- onPause: function(){
- _V_.removeClass(this.el, "vjs-playing");
- _V_.addClass(this.el, "vjs-paused");
- },
-
- onError: function(e) {
- _V_.log("Video Error", e);
- }
-
-});
-
-/* Player API
-================================================================================ */
-_V_.Player.prototype.extend({
-
- apiCall: function(method, arg){
- if (this.isReady) {
- return this.tech[method](arg);
- } else {
- _V_.log("The playback technology API is not ready yet. Use player.ready(myFunction)."+" ["+method+"]")
- return false;
- // throw new Error("The playback technology API is not ready yet. Use player.ready(myFunction)."+" ["+method+"]");
- }
- },
-
- play: function(){
- this.apiCall("play"); return this;
- },
- pause: function(){
- this.apiCall("pause"); return this;
- },
- paused: function(){
- return this.apiCall("paused");
- },
-
- currentTime: function(seconds){
- if (seconds !== undefined) {
- this.values.currentTime = seconds; // Cache the last set value for smoother scrubbing.
- this.apiCall("setCurrentTime", seconds);
- if (this.manualTimeUpdates) { this.triggerEvent("timeupdate"); }
- return this;
- }
- return this.apiCall("currentTime");
- },
- duration: function(){
- return this.apiCall("duration");
- },
- remainingTime: function(){
- return this.duration() - this.currentTime();
- },
-
- buffered: function(){
- var buffered = this.apiCall("buffered"),
- start = 0, end = this.values.bufferEnd = this.values.bufferEnd || 0,
- timeRange;
-
- if (buffered && buffered.length > 0 && buffered.end(0) > end) {
- end = buffered.end(0);
- // Storing values allows them be overridden by setBufferedFromProgress
- this.values.bufferEnd = end;
- }
-
- return _V_.createTimeRange(start, end);
- },
-
- // Calculates amount of buffer is full
- bufferedPercent: function(){
- return (this.duration()) ? this.buffered().end(0) / this.duration() : 0;
- },
-
- volume: function(percentAsDecimal){
- if (percentAsDecimal !== undefined) {
- var vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1
- this.values.volume = vol;
- this.apiCall("setVolume", vol);
- _V_.setLocalStorage("volume", vol);
- return this;
- }
- // if (this.values.volume) { return this.values.volume; }
@hhsh
hhsh Oct 9, 2014

take a test

- return this.apiCall("volume");
- },
- muted: function(muted){
- if (muted !== undefined) {
- this.apiCall("setMuted", muted);
- return this;
- }
- return this.apiCall("muted");
- },
-
- width: function(width, skipListeners){
- if (width !== undefined) {
- this.el.width = width;
- this.el.style.width = width+"px";
- if (!skipListeners) { this.triggerEvent("resize"); }
- return this;
- }
- return parseInt(this.el.getAttribute("width"));
- },
- height: function(height){
- if (height !== undefined) {
- this.el.height = height;
- this.el.style.height = height+"px";
- this.triggerEvent("resize");
- return this;
- }
- return parseInt(this.el.getAttribute("height"));
- },
- size: function(width, height){
- // Skip resize listeners on width for optimization
- return this.width(width, true).height(height);
- },
-
- supportsFullScreen: function(){ return this.apiCall("supportsFullScreen"); },
-
- // Turn on fullscreen (or window) mode
- enterFullScreen: function(){
-<<<<<<< HEAD
- if (this.supportsFullScreen()) {
- this.apiCall("enterFullScreen");
- } else {
- this.enterFullWindow();
- }
- this.triggerEvent("enterFullScreen");
- return this;
- },
-
- exitFullScreen: function(){
- if (true || !this.supportsFullScreen()) {
- this.exitFullWindow();
- }
- this.triggerEvent("exitFullScreen");
-
- // Otherwise Shouldn't be called since native fullscreen uses own controls.
- return this;
- },
-=======
- this.videoIsFullScreen = true;
- if (typeof this.el.webkitRequestFullScreen == 'function') {
- this.el.webkitRequestFullScreen();
- } else if (this.supportsFullScreen()) {
- this.apiCall("enterFullScreen");
- } else {
- this.enterFullWindow();
- }
- this.triggerEvent("enterFullScreen");
- return this;
- },
-
- exitFullScreen: function(){
- this.videoIsFullScreen = false;
- if (typeof this.el.webkitRequestFullScreen == 'function') {
- document.webkitCancelFullScreen();
- } else if (this.supportsFullScreen()) {
- document.webkitExitFullScreen();
- } else {
- this.exitFullWindow();
- }
- this.triggerEvent("exitFullScreen");
-
- // Otherwise Shouldn't be called since native fullscreen uses own controls.
- return this;
- },
->>>>>>> 2f99215f8dae0cac216f8c494f9058b087b39725
-
- enterFullWindow: function(){
- this.videoIsFullScreen = true;
-
- // Storing original doc overflow value to return to when fullscreen is off
- this.docOrigOverflow = document.documentElement.style.overflow;
-
- // Add listener for esc key to exit fullscreen
- _V_.addEvent(document, "keydown", _V_.proxy(this, this.fullWindowOnEscKey));
-
- // Hide any scroll bars
- document.documentElement.style.overflow = 'hidden';
-
- // Apply fullscreen styles
- _V_.addClass(document.body, "vjs-full-window");
- _V_.addClass(this.el, "vjs-fullscreen");
-
- this.triggerEvent("enterFullWindow");
- },
-
- fullWindowOnEscKey: function(event){
- if (event.keyCode == 27) {
- this.exitFullScreen();
- }
- },
-
- exitFullWindow: function(){
- this.videoIsFullScreen = false;
- _V_.removeEvent(document, "keydown", this.fullWindowOnEscKey);
-
- // Unhide scroll bars.
- document.documentElement.style.overflow = this.docOrigOverflow;
-
- // Remove fullscreen styles
- _V_.removeClass(document.body, "vjs-full-window");
- _V_.removeClass(this.el, "vjs-fullscreen");
-
- // Resize the box, controller, and poster to original sizes
- // this.positionAll();
- this.triggerEvent("exitFullWindow");
- },
-
- // src is a pretty powerful function
- // If you pass it an array of source objects, it will find the best source to play and use that object.src
- // If the new source requires a new playback technology, it will switch to that.
- // If you pass it an object, it will set the source to object.src
- // If you pass it anything else (url string) it will set the video source to that
- src: function(source){
- // Case: Array of source objects to choose from and pick the best to play
- if (source instanceof Array) {
-
- var sources = source;
-
- techLoop: // Named loop for breaking both loops
- // Loop through each playback technology in the options order
- for (var i=0,j=this.options.techOrder;i<j.length;i++) {
- var techName = j[i],
- tech = _V_[techName];
- // tech = _V_.tech[techName];
-
- // Check if the browser supports this technology
- if (tech.isSupported()) {
-
- // Loop through each source object
- for (var a=0,b=sources;a<b.length;a++) {
- var source = b[a];
-
- // Check if source can be played with this technology
- if (tech.canPlaySource.call(this, source)) {
-
- // If this technology is already loaded, set source
- if (techName == this.currentTechName) {
- this.src(source); // Passing the source object
-
- // Otherwise load this technology with chosen source
- } else {
- this.loadTech(techName, source);
- }
-
- break techLoop; // Break both loops
- }
- }
- }
- }
-
- // Case: Source object { src: "", type: "" ... }
- } else if (source instanceof Object) {
- if (this.tech.canPlaySource(source)) {
- this.src(source.src);
- } else {
- // Send through tech loop to check for a compatible technology.
- this.src([source]);
- }
- // Case: URL String (http://myvideo...)
- } else {
- if (!this.isReady) {
- this.ready(function(){
- this.src(source);
- });
- } else {
- this.apiCall("src", source);
- if (this.options.preload == "auto") {
- this.load();
- }
- if (this.options.autoplay) {
- this.play();
- }
- }
- }
- return this;
- },
-
- // Begin loading the src data
- load: function(){
- this.apiCall("load");
- return this;
- },
- currentSrc: function(){
- return this.apiCall("currentSrc");
- },
-
- textTrackValue: function(kind, value){
- if (value !== undefined) {
- this.values[kind] = value;
- this.triggerEvent(kind+"update");
- return this;
- }
- return this.values[kind];
- },
-
- // Attributes/Options
- preload: function(value){
- if (value !== undefined) {
- this.apiCall("setPreload", value);
- this.options.preload = value;
- return this;
- }
- return this.apiCall("preload", value);
- },
- autoplay: function(value){
- if (value !== undefined) {
- this.apiCall("setAutoplay", value);
- this.options.autoplay = value;
- return this;
- }
- return this.apiCall("autoplay", value);
- },
- loop: function(value){
- if (value !== undefined) {
- this.apiCall("setLoop", value);
- this.options.loop = value;
- return this;
- }
- return this.apiCall("loop", value);
- },
-
- controls: function(){ return this.options.controls; },
- textTracks: function(){ return this.options.tracks; },
- poster: function(){ return this.apiCall("poster"); },
-
- error: function(){ return this.apiCall("error"); },
- networkState: function(){ return this.apiCall("networkState"); },
- readyState: function(){ return this.apiCall("readyState"); },
- seeking: function(){ return this.apiCall("seeking"); },
- initialTime: function(){ return this.apiCall("initialTime"); },
- startOffsetTime: function(){ return this.apiCall("startOffsetTime"); },
- played: function(){ return this.apiCall("played"); },
- seekable: function(){ return this.apiCall("seekable"); },
- ended: function(){ return this.apiCall("ended"); },
- videoTracks: function(){ return this.apiCall("videoTracks"); },
- audioTracks: function(){ return this.apiCall("audioTracks"); },
- videoWidth: function(){ return this.apiCall("videoWidth"); },
- videoHeight: function(){ return this.apiCall("videoHeight"); },
- defaultPlaybackRate: function(){ return this.apiCall("defaultPlaybackRate"); },
- playbackRate: function(){ return this.apiCall("playbackRate"); },
- // mediaGroup: function(){ return this.apiCall("mediaGroup"); },
- // controller: function(){ return this.apiCall("controller"); },
- controls: function(){ return this.apiCall("controls"); },
- defaultMuted: function(){ return this.apiCall("defaultMuted"); }
-});
-
View
7 src/tech.js
@@ -116,9 +116,10 @@ _V_.HTML5 = _V_.PlaybackTech.extend({
currentTime: function(){ return this.el.currentTime; },
setCurrentTime: function(seconds){
- try { this.el.currentTime = seconds; }
- catch(e) {
- _V_.log(e);
+ try {
+ this.el.currentTime = seconds;
+ } catch(e) {
+ _V_.log(e, "Video isn't ready. (VideoJS)");
// this.warning(VideoJS.warnings.videoNotReady);
}
},
View
431 src/tech.js.orig
@@ -1,431 +0,0 @@
-/* Playback Technology - Base class for playback technologies
-================================================================================ */
-_V_.PlaybackTech = _V_.Component.extend({
- init: function(player, options){
- // this._super(player, options);
-
- // Make playback element clickable
- // _V_.addEvent(this.el, "click", _V_.proxy(this, _V_.PlayToggle.prototype.onClick));
-
- // player.triggerEvent("techready");
- },
- createElement: function(){},
- setupTriggers: function(){},
- removeTriggers: function(){},
-
- canPlaySource: function(source){
- return _V_[this.name].canPlaySource(source);
- }
-});
-
-// Create placeholder methods for each that warn when a method
-// isn't supported by the current playback technology
-_V_.apiMethods = "play,pause,paused,currentTime,setCurrentTime,duration,buffered,volume,setVolume,muted,setMuted,width,height,supportsFullScreen,enterFullScreen,src,load,currentSrc,preload,setPreload,autoplay,setAutoplay,loop,setLoop,error,networkState,readyState,seeking,initialTime,startOffsetTime,played,seekable,ended,videoTracks,audioTracks,videoWidth,videoHeight,textTracks,defaultPlaybackRate,playbackRate,mediaGroup,controller,controls,defaultMuted".split(",");
-_V_.each(_V_.apiMethods, function(methodName){
- _V_.PlaybackTech.prototype[methodName] = function(){
- throw new Error("The '"+method+"' method is not available on the playback technology's API");
- }
-});
-
-/* HTML5 Playback Technology - Wrapper for HTML5 Media API
-================================================================================ */
-_V_.HTML5 = _V_.PlaybackTech.extend({
- name: "HTML5",
-
- init: function(player, options, ready){
- this.player = player;
- this.el = this.createElement();
- this.ready(ready);
-
- 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.triggerReady();
- },
-
- createElement: function(){
- var html5 = _V_.HTML5,
- player = this.player,
-
- // 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 (html5.supports.movingElementInDOM === false) {
- newEl = _V_.createElement("video", {
- id: el.id,
- className: el.className
- });
-
- player.el.removeChild(el);
- el = newEl;
- _V_.log("here")
- _V_.insertFirst(el, player.el);
- }
-
- // Update tag settings, in case they were overridden
- _V_.each(["autoplay","preload","loop","muted","poster"], function(attr){
- el[attr] = player.options[attr];
- }, this);
-
- return el;
- },
-
- setupTriggers: function(){
- // Make video events trigger player events
- // May seem verbose here, but makes other APIs possible.
-
- // ["play", "playing", "pause", "ended", "volumechange", "error", "progress", "seeking", "timeupdate"]
- var types = _V_.HTML5.events,
- i;
- for (i = 0;i<types.length; i++) {
- _V_.addEvent(this.el, types[i], _V_.proxy(this.player, function(e){
- e.stopPropagation();
- this.triggerEvent(e);
- }));
- }
- },
- removeTriggers: function(){},
-
- 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);
- // 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(){
-<<<<<<< HEAD
- if(typeof this.el.webkitEnterFullScreen == 'function') {
-=======
- if (typeof this.el.webkitEnterFullScreen == 'function') {
-
->>>>>>> 2f99215f8dae0cac216f8c494f9058b087b39725
- // 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;
- }
-<<<<<<< HEAD
- }
- 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.")
- }
- }
-=======
- }
- 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.")
- }
- }
->>>>>>> 2f99215f8dae0cac216f8c494f9058b087b39725
- },
- 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
-};
-
-_V_.HTML5.supports = {};
-
-// 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 ---------------------------------------------------------- */
-
-// iOS
-if (_V_.isIOS()) {
- // If you move a video element in the DOM, it breaks video playback.
- _V_.HTML5.supports.movingElementInDOM = false;
-}
-
-// 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" : "";
- };
- }
-}
-
-
-/* H5SWF - Custom Flash Player with HTML5-ish API
-================================================================================ */
-_V_.H5swf = _V_.PlaybackTech.extend({
- name: "H5swf",
-
- swf: "flash/video-js.swf",
- // swf: "https://s3.amazonaws.com/video-js/3.0b/video-js.swf",
- // swf: "http://video-js.zencoder.com/3.0b/video-js.swf",
- // swf: "http://video-js.com/test/video-js.swf",
- // swf: "http://video-js.com/source/flash/video-js.swf",
- // swf: "http://video-js.com/source/flash/video-js.swf",
- // swf: "video-js.swf",
-
- init: function(player, options){
- this.player = player;
- var placeHolder = this.el = _V_.createElement("div", { id: player.el.id + "_temp_h5swf" });
-
- var source = options.source,
- objId = player.el.id+"_h5swf_api",
- playerOptions = player.options;
-
- flashvars = {
- readyFunction: "_V_.H5swf.onSWFReady",
- eventProxyFunction: "_V_.H5swf.onSWFEvent",
- errorEventProxyFunction: "_V_.H5swf.onSWFErrorEvent",
- autoplay: playerOptions.autoplay,
- preload: playerOptions.preload,
- loop: playerOptions.loop,
- muted: playerOptions.muted
- },
-
- params = {
- allowScriptAccess: "always",
- wmode: "opaque",
- bgcolor: "#000000"
- },
-
- attributes = {
- id: objId,
- name: objId,
- 'class': 'vjs-tech'
- };
-
- if (playerOptions.poster) {
- flashvars.poster = playerOptions.poster;
- }
-
- // If source was supplied pass as a flash var.
- if (source) {
- flashvars.src = source.src;
- }
-
- _V_.insertFirst(placeHolder, player.el);
-
- swfobject.embedSWF(options.swf || this.swf, placeHolder.id, "480", "270", "9.0.124", "", flashvars, params, attributes);
- },
-
- setupTriggers: function(){
- // Using global onSWFEvent func to distribute events
- },
-
- play: function(){ this.el.vjs_play(); },
- pause: function(){ this.el.vjs_pause(); },
- src: function(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_.H5swf.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_.H5swf.isSupported = function(){
- return swfobject.hasFlashPlayerVersion("9");
-};
-
-_V_.H5swf.canPlaySource = function(srcObj){
- if (srcObj.type in _V_.H5swf.supports.format) { return "maybe"; }
-};
-
-_V_.H5swf.supports = {
- format: {
- "video/flv": "FLV",
- "video/x-flv": "FLV",
- "video/mp4": "MP4",
- "video/m4v": "MP4"
- },
-
- // Optional events that we can manually mimic with timers
- event: {
- progress: false,
- timeupdate: false
- }
-};
-
-_V_.H5swf.onSWFReady = function(currSwf){
-
- _V_.log(currSwf, "currSwf")
-
- // Flash seems to be catching errors, so raising them manally
- try {
- // Delay for real swf ready.
- setTimeout(function(){
- var el = _V_.el(currSwf);
-
- // Get player from box
- var player = el.parentNode.player,
- tech = player.techs["H5swf"];
-
- // Reference player on tech element
- el.player = player;
-
- // Update reference to playback technology element
- tech.el = el;
-
- tech.triggerReady();
-
- },0);
-
- } catch(err) {
- _V_.log(err);
- }
-};
-
-_V_.H5swf.onSWFEvent = function(swfID, eventName, other){
- try {
- var player = _V_.el(swfID).player;
- if (player) {
- player.triggerEvent(eventName);
- }
- } catch(err) {
- _V_.log(err);
- }
-};
-
-_V_.H5swf.onSWFErrorEvent = function(swfID, eventName){
- _V_.log("Flash (H5SWF) Error", eventName);
-};

0 comments on commit e4f6bbb

Please sign in to comment.