Commit d0fbd502 by Valera Rozuvan

Initial commit for feature BLD-391: Add arrows to the interface for start/end times.

If end time is specified (which means that there is also a start time), we
add an extra DOM element to the slider that will show the are in time between
start time and end time. Unfortunately, this visual aid will become available
ony after start of playback. This is because until then we don't know the length
of the video.
parent 6c087081
...@@ -75,6 +75,8 @@ function (VideoPlayer) { ...@@ -75,6 +75,8 @@ function (VideoPlayer) {
state.parseYoutubeStreams = _.bind(parseYoutubeStreams, state); state.parseYoutubeStreams = _.bind(parseYoutubeStreams, state);
state.parseVideoSources = _.bind(parseVideoSources, state); state.parseVideoSources = _.bind(parseVideoSources, state);
state.getVideoMetadata = _.bind(getVideoMetadata, state); state.getVideoMetadata = _.bind(getVideoMetadata, state);
state.checkStartEndTimes = _.bind(checkStartEndTimes, state);
} }
// function _renderElements(state) // function _renderElements(state)
...@@ -277,6 +279,10 @@ function (VideoPlayer) { ...@@ -277,6 +279,10 @@ function (VideoPlayer) {
availableQualities: ['hd720', 'hd1080', 'highres'] availableQualities: ['hd720', 'hd1080', 'highres']
}; };
// Make sure that start end end times are valid. If not, they will be
// set to `null` and will not be used later on.
this.checkStartEndTimes();
// Check if the YT test timeout has been set. If not, or it is in // Check if the YT test timeout has been set. If not, or it is in
// improper format, then set to default value. // improper format, then set to default value.
tempYtTestTimeout = parseInt(data['ytTestTimeout'], 10); tempYtTestTimeout = parseInt(data['ytTestTimeout'], 10);
...@@ -360,6 +366,30 @@ function (VideoPlayer) { ...@@ -360,6 +366,30 @@ function (VideoPlayer) {
} }
} }
/*
* function checkStartEndTimes()
*
* Validate config.start and config.end times.
*
* We can check at this time if the times are proper integers, and if they
* make general sense. I.e. if start time is => 0 and <= end time.
*
* An invalid start time will be reset to 0. An invalid end time will be
* set to `null`. It the task for the appropriate player API to figure out
* if start time and/or end time are greater than the length of the video.
*/
function checkStartEndTimes() {
this.config.start = parseInt(this.config.start, 10);
if ((!isFinite(this.config.start)) || (this.config.start < 0)) {
this.config.start = 0;
}
this.config.end = parseInt(this.config.end, 10);
if ((!isFinite(this.config.end)) || (this.config.end < this.config.start)) {
this.config.end = null;
}
}
// function parseYoutubeStreams(state, youtubeStreams) // function parseYoutubeStreams(state, youtubeStreams)
// //
// Take a string in the form: // Take a string in the form:
......
...@@ -191,19 +191,8 @@ function () { ...@@ -191,19 +191,8 @@ function () {
} }
// Determine the starting and ending time for the video. // Determine the starting and ending time for the video.
this.start = 0; this.start = config.playerVars.start;
this.end = null; this.end = config.playerVars.end;
if (config.playerVars) {
this.start = parseFloat(config.playerVars.start);
if ((!isFinite(this.start)) || (this.start < 0)) {
this.start = 0;
}
this.end = parseFloat(config.playerVars.end);
if ((!isFinite(this.end)) || (this.end < this.start)) {
this.end = null;
}
}
// Create HTML markup for the <video> element, populating it with sources from previous step. // Create HTML markup for the <video> element, populating it with sources from previous step.
// Because of problems with creating video element via jquery // Because of problems with creating video element via jquery
...@@ -217,7 +206,6 @@ function () { ...@@ -217,7 +206,6 @@ function () {
this.videoEl = $(this.video); this.videoEl = $(this.video);
this.playerState = HTML5Video.PlayerState.UNSTARTED; this.playerState = HTML5Video.PlayerState.UNSTARTED;
// this.callStateChangeCallback();
// Attach a 'click' event on the <video> element. It will cause the video to pause/play. // Attach a 'click' event on the <video> element. It will cause the video to pause/play.
this.videoEl.on('click', function (event) { this.videoEl.on('click', function (event) {
......
...@@ -34,9 +34,7 @@ function (HTML5Video, Resizer) { ...@@ -34,9 +34,7 @@ function (HTML5Video, Resizer) {
state.videoPlayer.onPause = _.bind(onPause, state); state.videoPlayer.onPause = _.bind(onPause, state);
state.videoPlayer.onPlay = _.bind(onPlay, state); state.videoPlayer.onPlay = _.bind(onPlay, state);
state.videoPlayer.onUnstarted = _.bind( state.videoPlayer.onUnstarted = _.bind(onUnstarted, state);
onUnstarted, state
);
state.videoPlayer.handlePlaybackQualityChange = _.bind( state.videoPlayer.handlePlaybackQualityChange = _.bind(
handlePlaybackQualityChange, state handlePlaybackQualityChange, state
...@@ -86,13 +84,8 @@ function (HTML5Video, Resizer) { ...@@ -86,13 +84,8 @@ function (HTML5Video, Resizer) {
state.videoPlayer.playerVars.html5 = 1; state.videoPlayer.playerVars.html5 = 1;
} }
if (state.config.start) { state.videoPlayer.playerVars.start = state.config.start;
state.videoPlayer.playerVars.start = state.config.start; state.videoPlayer.playerVars.end = state.config.end;
state.videoPlayer.playerVars.wmode = 'window';
}
if (state.config.end) {
state.videoPlayer.playerVars.end = state.config.end;
}
// There is a bug which prevents YouTube API to correctly set the speed // There is a bug which prevents YouTube API to correctly set the speed
// to 1.0 from another speed in Firefox when in HTML5 mode. There is a // to 1.0 from another speed in Firefox when in HTML5 mode. There is a
...@@ -479,6 +472,13 @@ function (HTML5Video, Resizer) { ...@@ -479,6 +472,13 @@ function (HTML5Video, Resizer) {
); );
this.trigger( this.trigger(
'videoProgressSlider.updateStartEndTimeRegion',
{
duration: duration
}
);
this.trigger(
'videoControl.updateVcrVidTime', 'videoControl.updateVcrVidTime',
{ {
time: time, time: time,
......
...@@ -28,21 +28,29 @@ function () { ...@@ -28,21 +28,29 @@ function () {
// function _makeFunctionsPublic(state) // function _makeFunctionsPublic(state)
// //
// Functions which will be accessible via 'state' object. When called, these functions will // Functions which will be accessible via 'state' object. When called,
// get the 'state' object as a context. // these functions will get the 'state' object as a context.
function _makeFunctionsPublic(state) { function _makeFunctionsPublic(state) {
state.videoProgressSlider.onSlide = _.bind(onSlide, state); state.videoProgressSlider.onSlide = _.bind(onSlide, state);
state.videoProgressSlider.onStop = _.bind(onStop, state); state.videoProgressSlider.onStop = _.bind(onStop, state);
state.videoProgressSlider.updatePlayTime = _.bind(updatePlayTime, state); state.videoProgressSlider.updatePlayTime = _.bind(
updatePlayTime, state
);
//Added for tests -- JM //Added for tests -- JM
state.videoProgressSlider.buildSlider = _.bind(buildSlider, state); state.videoProgressSlider.buildSlider = _.bind(buildSlider, state);
state.videoProgressSlider.updateStartEndTimeRegion = _.bind(
updateStartEndTimeRegion, state
);
} }
// function _renderElements(state) // function _renderElements(state)
// //
// Create any necessary DOM elements, attach them, and set their initial configuration. Also // Create any necessary DOM elements, attach them, and set their
// make the created DOM elements available via the 'state' object. Much easier to work this // initial configuration. Also make the created DOM elements available
// way - you don't have to do repeated jQuery element selects. // via the 'state' object. Much easier to work this way - you don't
// have to do repeated jQuery element selects.
function _renderElements(state) { function _renderElements(state) {
if (!onTouchBasedDevice()) { if (!onTouchBasedDevice()) {
state.videoProgressSlider.el = state.videoControl.sliderEl; state.videoProgressSlider.el = state.videoControl.sliderEl;
...@@ -53,8 +61,9 @@ function () { ...@@ -53,8 +61,9 @@ function () {
} }
function _buildHandle(state) { function _buildHandle(state) {
state.videoProgressSlider.handle = state.videoProgressSlider.el.find('.ui-slider-handle'); state.videoProgressSlider.handle = state.videoProgressSlider.el
.find('.ui-slider-handle');
// ARIA // ARIA
// We just want the knob to be selectable with keyboard // We just want the knob to be selectable with keyboard
state.videoProgressSlider.el.attr('tabindex', -1); state.videoProgressSlider.el.attr('tabindex', -1);
...@@ -64,28 +73,75 @@ function () { ...@@ -64,28 +73,75 @@ function () {
'role': 'slider', 'role': 'slider',
'title': 'video position', 'title': 'video position',
'aria-disabled': false, 'aria-disabled': false,
'aria-valuetext': getTimeDescription(state.videoProgressSlider.slider.slider('option', 'value')) 'aria-valuetext': getTimeDescription(state.videoProgressSlider
.slider.slider('option', 'value'))
}); });
} }
// *************************************************************** // ***************************************************************
// Public functions start here. // Public functions start here.
// These are available via the 'state' object. Their context ('this' keyword) is the 'state' object. // These are available via the 'state' object. Their context ('this'
// The magic private function that makes them available and sets up their context is makeFunctionsPublic(). // keyword) is the 'state' object. The magic private function that makes
// them available and sets up their context is makeFunctionsPublic().
// *************************************************************** // ***************************************************************
function buildSlider(state) { function buildSlider(state) {
state.videoProgressSlider.slider = state.videoProgressSlider.el.slider({ console.log('state = ', state);
range: 'min',
slide: state.videoProgressSlider.onSlide, state.videoProgressSlider.slider = state.videoProgressSlider.el
stop: state.videoProgressSlider.onStop .slider({
}); range: 'min',
slide: state.videoProgressSlider.onSlide,
stop: state.videoProgressSlider.onStop
});
state.videoProgressSlider.sliderProgress = state.videoProgressSlider
.slider
.find('.ui-slider-range.ui-widget-header.ui-slider-range-min');
}
function updateStartEndTimeRegion(params) {
var left, width;
if (this.config.end && params.duration) {
left = parseInt(100 * (this.config.start / params.duration), 10);
width = parseInt(
100 * (
(this.config.end - this.config.start) / params.duration
),
10
);
if (!this.videoProgressSlider.sliderRange) {
this.videoProgressSlider.sliderRange = $('<div />')
.addClass('ui-slider-range')
.addClass('ui-widget-header')
.addClass('ui-corner-all')
.css({
left: left + '%',
width: width + '%',
'background-color': 'blue'
});
this.videoProgressSlider.sliderProgress
.after(this.videoProgressSlider.sliderRange);
} else {
this.videoProgressSlider.sliderRange
.css({
left: left + '%',
width: width + '%'
});
}
}
} }
function onSlide(event, ui) { function onSlide(event, ui) {
this.videoProgressSlider.frozen = true; this.videoProgressSlider.frozen = true;
this.trigger('videoPlayer.onSlideSeek', {'type': 'onSlideSeek', 'time': ui.value}); this.trigger(
'videoPlayer.onSlideSeek',
{'type': 'onSlideSeek', 'time': ui.value}
);
// ARIA // ARIA
this.videoProgressSlider.handle.attr( this.videoProgressSlider.handle.attr(
...@@ -98,7 +154,10 @@ function () { ...@@ -98,7 +154,10 @@ function () {
this.videoProgressSlider.frozen = true; this.videoProgressSlider.frozen = true;
this.trigger('videoPlayer.onSlideSeek', {'type': 'onSlideSeek', 'time': ui.value}); this.trigger(
'videoPlayer.onSlideSeek',
{'type': 'onSlideSeek', 'time': ui.value}
);
// ARIA // ARIA
this.videoProgressSlider.handle.attr( this.videoProgressSlider.handle.attr(
...@@ -110,23 +169,28 @@ function () { ...@@ -110,23 +169,28 @@ function () {
}, 200); }, 200);
} }
//Changed for tests -- JM: Check if it is the cause of Chrome Bug Valera noticed // Changed for tests -- JM: Check if it is the cause of Chrome Bug Valera
// noticed
function updatePlayTime(params) { function updatePlayTime(params) {
if ((this.videoProgressSlider.slider) && (!this.videoProgressSlider.frozen)) { if (
/*this.videoProgressSlider.slider (this.videoProgressSlider.slider) &&
.slider('option', 'max', params.duration) (!this.videoProgressSlider.frozen)
.slider('value', params.time);*/ ) {
this.videoProgressSlider.slider.slider('option', 'max', params.duration); this.videoProgressSlider.slider
this.videoProgressSlider.slider.slider('option', 'value', params.time); .slider('option', 'max', params.duration);
this.videoProgressSlider.slider
.slider('option', 'value', params.time);
} }
} }
// Returns a string describing the current time of video in hh:mm:ss format. // Returns a string describing the current time of video in hh:mm:ss
// format.
function getTimeDescription(time) { function getTimeDescription(time) {
var seconds = Math.floor(time), var seconds = Math.floor(time),
minutes = Math.floor(seconds / 60), minutes = Math.floor(seconds / 60),
hours = Math.floor(minutes / 60), hours = Math.floor(minutes / 60),
hrStr, minStr, secStr; hrStr, minStr, secStr;
seconds = seconds % 60; seconds = seconds % 60;
minutes = minutes % 60; minutes = minutes % 60;
...@@ -136,30 +200,36 @@ function () { ...@@ -136,30 +200,36 @@ function () {
if (hours) { if (hours) {
hrStr += (hours < 2 ? ' hour ' : ' hours '); hrStr += (hours < 2 ? ' hour ' : ' hours ');
if (minutes) {
if (minutes) {
minStr += (minutes < 2 ? ' minute ' : ' minutes '); minStr += (minutes < 2 ? ' minute ' : ' minutes ');
} else { } else {
minStr += ' 0 minutes '; minStr += ' 0 minutes ';
} }
if (seconds) {
if (seconds) {
secStr += (seconds < 2 ? ' second ' : ' seconds '); secStr += (seconds < 2 ? ' second ' : ' seconds ');
} else { } else {
secStr += ' 0 seconds '; secStr += ' 0 seconds ';
} }
return hrStr + minStr + secStr; return hrStr + minStr + secStr;
} else if (minutes) { } else if (minutes) {
minStr += (minutes < 2 ? ' minute ' : ' minutes '); minStr += (minutes < 2 ? ' minute ' : ' minutes ');
if (seconds) {
if (seconds) {
secStr += (seconds < 2 ? ' second ' : ' seconds '); secStr += (seconds < 2 ? ' second ' : ' seconds ');
} else { } else {
secStr += ' 0 seconds '; secStr += ' 0 seconds ';
} }
return minStr + secStr; return minStr + secStr;
} else if (seconds) { } else if (seconds) {
secStr += (seconds < 2 ? ' second ' : ' seconds '); secStr += (seconds < 2 ? ' second ' : ' seconds ');
return secStr; return secStr;
} }
return '0 seconds'; return '0 seconds';
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment