mirror of
				https://github.com/videojs/video.js.git
				synced 2025-10-31 00:08:01 +02:00 
			
		
		
		
	Optimized slider controls.
Fixed issue with fullscreen progress bar tracking (offset left wasn't working in new fullscreen)
This commit is contained in:
		| @@ -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 */ | ||||
|   | ||||
| @@ -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(){ | ||||
|   | ||||
							
								
								
									
										374
									
								
								src/controls.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										374
									
								
								src/controls.js
									
									
									
									
										vendored
									
									
								
							| @@ -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)); | ||||
|   stepForward: function(){ | ||||
|     this.player.currentTime(this.player.currentTime() + 1); | ||||
|   }, | ||||
|   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); | ||||
|     } | ||||
|   }, | ||||
|   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,25 +568,11 @@ _V_.VolumeControl = _V_.Component.extend({ | ||||
|  | ||||
| }); | ||||
|  | ||||
| _V_.VolumeBar = _V_.Component.extend({ | ||||
| _V_.VolumeBar = _V_.Slider.extend({ | ||||
|  | ||||
|   init: function(player, options){ | ||||
|     this._super(player, options); | ||||
|  | ||||
|     _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", { | ||||
| @@ -544,70 +580,21 @@ _V_.VolumeBar = _V_.Component.extend({ | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   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" | ||||
|   | ||||
							
								
								
									
										46
									
								
								src/lib.js
									
									
									
									
									
								
							
							
						
						
									
										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; | ||||
|   }; | ||||
| } | ||||
|   | ||||
| @@ -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"); | ||||
|   | ||||
| @@ -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; } | ||||
|     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"); } | ||||
| }); | ||||
|  | ||||
| @@ -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); | ||||
|     } | ||||
|   }, | ||||
|   | ||||
							
								
								
									
										431
									
								
								src/tech.js.orig
									
									
									
									
									
								
							
							
						
						
									
										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); | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user