Video JS is a javascript-based video player that uses the HTML5 video functionality built into advanced browsers. In general, the benefit of using an HTML5 player is a consistent look between browsers.
diff --git a/stylesheets/site.css b/stylesheets/site.css
index 6b1188e1c..5ada21018 100644
--- a/stylesheets/site.css
+++ b/stylesheets/site.css
@@ -14,7 +14,7 @@ ul#nav { list-style: none; margin: 0; padding: 0; height: 20px; text-align: righ
ul#nav li { display: inline; list-style: none; margin: 0; padding: 0; padding-left: 20px; font-size: 120%; line-height: 20px; }
ul#nav li a { color: #fff; text-decoration: none; }
-.video-box { margin-bottom: 0; background-color: #000; }
+.video-js-box { margin-bottom: 0; background-color: #000; }
p#video_note { margin-bottom: 20px; font-size: 100%; line-height: 20px; color: #999; text-align: center; }
#features_and_support { }
diff --git a/video-js/LICENSE.txt b/video-js/LICENSE.txt
new file mode 100644
index 000000000..cc7626505
--- /dev/null
+++ b/video-js/LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2010 Zencoder, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/video-js/README.markdown b/video-js/README.markdown
new file mode 100644
index 000000000..b0d908291
--- /dev/null
+++ b/video-js/README.markdown
@@ -0,0 +1,3 @@
+video.js
+--------
+Based on the tutorial at http://blog.steveheffernan.com/2010/04/how-to-build-an-html5-video-player/
\ No newline at end of file
diff --git a/video-js/demo.html b/video-js/demo.html
new file mode 100644
index 000000000..1e57fead7
--- /dev/null
+++ b/video-js/demo.html
@@ -0,0 +1,38 @@
+
+
+
+
+ HTML5 Video Player
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/video-js/video-js.css b/video-js/video-js.css
index 6af69e616..c07a0228d 100644
--- a/video-js/video-js.css
+++ b/video-js/video-js.css
@@ -1,4 +1,4 @@
-.video-box { text-align: left; position: relative; }
+.video-js-box { text-align: left; position: relative; }
.video-js { background-color: #000; }
/* General controls styles */
diff --git a/video-js/video.js b/video-js/video.js
index 61326790d..9073b32a9 100644
--- a/video-js/video.js
+++ b/video-js/video.js
@@ -13,30 +13,48 @@ var VideoJS = Class.extend({
init: function(element, num){
this.video = element;
- // Default the player number to 0
- this.num = (num) ? num : 0;
-
this.buildController();
this.showController(); // has to come before positioning
this.positionController();
+ // Listen for when the video is played
+ this.video.addEventListener("play", this.onPlay.context(this), false);
+ // Listen for when the video is paused
+ this.video.addEventListener("pause", this.onPause.context(this), false);
+ // Listen for when the video ends
+ this.video.addEventListener("ended", this.onEnded.context(this), false);
+ // Listen for a volume change
+ this.video.addEventListener('volumechange',this.onVolumeChange.context(this),false);
+ // Listen for video errors
+ this.video.addEventListener('error',this.onError.context(this),false);
+
// Listen for clicks on the play/pause button
- this.playControl.addEventListener("click", this.onPlayControlClick, true);
+ this.playControl.addEventListener("click", this.onPlayControlClick.context(this), false);
+ // Make a click on the video act like a click on the play button.
+ this.video.addEventListener("click", this.onPlayControlClick.context(this), false);
// Listen for drags on the progress bar
- this.progressHolder.addEventListener("mousedown", this.onProgressHolderMouseDown, true);
+ this.progressHolder.addEventListener("mousedown", this.onProgressHolderMouseDown.context(this), false);
// Listen for a release on the progress bar
- this.progressHolder.addEventListener("mouseup", this.onProgressHolderMouseUp, true);
+ this.progressHolder.addEventListener("mouseup", this.onProgressHolderMouseUp.context(this), false);
// Listen for a drag on the volume control
- this.volumeControl.addEventListener("mousedown", this.onVolumeControlMouseDown, true);
+ this.volumeControl.addEventListener("mousedown", this.onVolumeControlMouseDown.context(this), false);
// Listen for a release on the volume control
- this.volumeControl.addEventListener("mouseup", this.onVolumeControlMouseUp, true);
+ this.volumeControl.addEventListener("mouseup", this.onVolumeControlMouseUp.context(this), false);
// Set the display to the initial volume
this.updateVolumeDisplay();
- // Listen for clicks on the fullscreen button
- this.fullscreenControl.addEventListener("click", this.onFullscreenControlClick, true);
+ // Listen for clicks on the button
+ this.fullscreenControl.addEventListener("click", this.onFullscreenControlClick.context(this), false);
+
+ // Listen for the mouse over the video. Used to reveal the controller.
+ this.video.addEventListener("mouseover", this.onVideoMouseOver.context(this), false);
+ // Listen for the mouse moving out of the video. Used to hide the controller.
+ this.video.addEventListener("mouseout", this.onVideoMouseOut.context(this), false);
+ // Have to add the mouseout to the controller too or it may not hide.
+ // For some reason the same isn't needed for mouseover
+ this.controls.addEventListener("mouseout", this.onVideoMouseOut.context(this), false);
},
buildController: function(){
@@ -52,7 +70,7 @@ var VideoJS = Class.extend({
- 00:00 / 00:00
+ 00:00 / 00:00
@@ -69,6 +87,8 @@ var VideoJS = Class.extend({
*/
+
+
// Create a list element to hold the different controls
this.controls = document.createElement("ul");
@@ -121,8 +141,10 @@ var VideoJS = Class.extend({
this.currentTimeDisplay.className = "vjs-current-time-display";
this.currentTimeDisplay.innerHTML = '00:00';
- // Adding a slash for visual separation
- this.progressTime.innerHTML += " / ";
+ // Add time separator
+ this.timeSeparator = document.createElement("span");
+ this.timeSeparator.innerHTML = " / ";
+ this.progressTime.appendChild(this.timeSeparator);
// Create the total duration display
this.durationDisplay = document.createElement("span");
@@ -162,97 +184,119 @@ var VideoJS = Class.extend({
this.controls.style.display = "none";
},
- // React to clicks on the play/pause button
- onPlayControlClick: function(e){
- var player = videoJSPlayers[this.parentNode.getAttribute("data-video-js")];
- if (player.video.paused) {
- player.playVideo();
- } else {
- player.pauseVideo();
- }
- },
-
- // Adjust the play position when the user drags on the progress bar
- onProgressHolderMouseDown: function(e){
- var player = videoJSPlayers[this.parentNode.parentNode.parentNode.getAttribute("data-video-js")];
- player.stopTrackingPlayProgress();
-
- if (player.video.paused) {
- player.videoWasPlaying = false;
- } else {
- player.videoWasPlaying = true;
- player.video.pause();
- }
-
- player.blockTextSelection();
- document.onmousemove = function(e) {
- player.setPlayProgress(e.pageX);
- }
-
- document.onmouseup = function() {
- player.unblockTextSelection();
- document.onmousemove = null;
- document.onmouseup = null;
- if (player.videoWasPlaying) {
- player.video.play();
- player.trackPlayProgress();
- }
- }
- },
-
- // When the user stops dragging on the progress bar, update play position
- // Backup for when the user only clicks and doesn't drag
- onProgressHolderMouseUp: function(e){
- var player = videoJSPlayers[this.parentNode.parentNode.parentNode.getAttribute("data-video-js")];
- player.setPlayProgress(e.pageX);
- },
-
- // Adjust the volume when the user drags on the volume control
- onVolumeControlMouseDown: function(e){
- var player = videoJSPlayers[this.parentNode.getAttribute("data-video-js")];
- player.blockTextSelection();
- document.onmousemove = function(e) {
- player.setVolume(e.pageX);
- }
- document.onmouseup = function() {
- player.unblockTextSelection();
- document.onmousemove = null;
- document.onmouseup = null;
- }
- },
-
- // When the user stops dragging, set a new volume
- // Backup for when the user only clicks and doesn't drag
- onVolumeControlMouseUp: function(e){
- var player = videoJSPlayers[this.parentNode.getAttribute("data-video-js")];
- player.setVolume(e.pageX);
- },
-
- // When the user clicks on the fullscreen button, update fullscreen setting
- onFullscreenControlClick: function(e){
- var player = videoJSPlayers[this.parentNode.getAttribute("data-video-js")];
- if (!player.videoIsFullScreen) {
- player.fullscreenOn();
- } else {
- player.fullscreenOff();
- }
- },
-
- // Play the video
- playVideo: function(){
- this.video.play();
+ // When the video is played
+ onPlay: function(event){
this.playControl.className = "vjs-play-control vjs-pause";
this.trackPlayProgress();
},
- // Pause the video
- pauseVideo: function(){
- this.video.pause();
+ // When the video is paused
+ onPause: function(event){
this.playControl.className = "vjs-play-control vjs-play";
this.stopTrackingPlayProgress();
},
- // Adjust the width of the progress bar to fill the controls width
+ // When the video ends
+ onEnded: function(event){
+ this.video.pause();
+ this.onPause();
+ },
+
+ onVolumeChange: function(event){
+ this.updateVolumeDisplay();
+ },
+
+ onError: function(event){
+ console.log(event);
+ console.log(this.video.error);
+ },
+
+ // React to clicks on the play/pause button
+ onPlayControlClick: function(event){
+ if (this.video.paused) {
+ this.video.play();
+ } else {
+ this.video.pause();
+ }
+ },
+
+ // Adjust the play position when the user drags on the progress bar
+ onProgressHolderMouseDown: function(event){
+ this.stopTrackingPlayProgress();
+
+ if (this.video.paused) {
+ this.videoWasPlaying = false;
+ } else {
+ this.videoWasPlaying = true;
+ this.video.pause();
+ }
+
+ this.blockTextSelection();
+ document.onmousemove = function(event) {
+ this.setPlayProgress(event.pageX);
+ }.context(this);
+
+ document.onmouseup = function(event) {
+ this.unblockTextSelection();
+ document.onmousemove = null;
+ document.onmouseup = null;
+ if (this.videoWasPlaying) {
+ this.video.play();
+ this.trackPlayProgress();
+ }
+ }.context(this);
+ },
+
+ // When the user stops dragging on the progress bar, update play position
+ // Backup for when the user only clicks and doesn't drag
+ onProgressHolderMouseUp: function(event){
+ this.setPlayProgress(event.pageX);
+ },
+
+ // Adjust the volume when the user drags on the volume control
+ onVolumeControlMouseDown: function(event){
+ this.blockTextSelection();
+ document.onmousemove = function(event) {
+ this.setVolume(event.pageX);
+ }.context(this);
+ document.onmouseup = function() {
+ this.unblockTextSelection();
+ document.onmousemove = null;
+ document.onmouseup = null;
+ }.context(this);
+ },
+
+ // When the user stops dragging, set a new volume
+ // Backup for when the user only clicks and doesn't drag
+ onVolumeControlMouseUp: function(event){
+ this.setVolume(event.pageX);
+ },
+
+ // When the user clicks on the fullscreen button, update fullscreen setting
+ onFullscreenControlClick: function(event){
+ if (!this.videoIsFullScreen) {
+ this.fullscreenOn();
+ } else {
+ this.fullscreenOff();
+ }
+ },
+
+ onVideoMouseOver: function(event){
+ this.showController();
+ },
+
+ onVideoMouseOut: function(event){
+ // Prevent flicker by making sure mouse hasn't left the video
+ var parent = event.relatedTarget;
+ while (parent && parent !== this.video && parent !== this.controls) {
+ parent = parent.parentNode;
+ }
+ if (parent !== this.video && parent !== this.controls) {
+ this.hideController();
+ }
+ },
+
+ // Adjust the width of the progress bar to fill the controls width
sizeProgressBar: function(){
this.progressControl.style.width = (this.controls.offsetWidth - 125) + "px";
this.progressHolder.style.width = (this.progressControl.offsetWidth - 80) + "px";
@@ -261,8 +305,7 @@ var VideoJS = Class.extend({
// Track & display the current play progress
trackPlayProgress: function(){
- context = this;
- this.playProgressInterval = setInterval(function(){ context.updatePlayProgress(); }, 33);
+ this.playProgressInterval = setInterval(function(){ this.updatePlayProgress(); }.context(this), 33);
},
// Turn off play progress tracking (when paused)
@@ -299,7 +342,6 @@ var VideoJS = Class.extend({
newVol = 0;
}
this.video.volume = newVol;
- this.updateVolumeDisplay();
},
// Update the volume control display
@@ -380,10 +422,28 @@ var VideoJS = Class.extend({
// Add video-js to any video tag with the class
VideoJS.setup = function(){
- var videoTags = document.getElementsByTagName("video");
- for (var i=0;i