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) {
state.parseYoutubeStreams = _.bind(parseYoutubeStreams, state);
state.parseVideoSources = _.bind(parseVideoSources, state);
state.getVideoMetadata = _.bind(getVideoMetadata, state);
state.checkStartEndTimes = _.bind(checkStartEndTimes, state);
}
// function _renderElements(state)
......@@ -277,6 +279,10 @@ function (VideoPlayer) {
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
// improper format, then set to default value.
tempYtTestTimeout = parseInt(data['ytTestTimeout'], 10);
......@@ -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)
//
// Take a string in the form:
......
......@@ -191,19 +191,8 @@ function () {
}
// Determine the starting and ending time for the video.
this.start = 0;
this.end = null;
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;
}
}
this.start = config.playerVars.start;
this.end = config.playerVars.end;
// Create HTML markup for the <video> element, populating it with sources from previous step.
// Because of problems with creating video element via jquery
......@@ -217,7 +206,6 @@ function () {
this.videoEl = $(this.video);
this.playerState = HTML5Video.PlayerState.UNSTARTED;
// this.callStateChangeCallback();
// Attach a 'click' event on the <video> element. It will cause the video to pause/play.
this.videoEl.on('click', function (event) {
......
......@@ -34,9 +34,7 @@ function (HTML5Video, Resizer) {
state.videoPlayer.onPause = _.bind(onPause, state);
state.videoPlayer.onPlay = _.bind(onPlay, state);
state.videoPlayer.onUnstarted = _.bind(
onUnstarted, state
);
state.videoPlayer.onUnstarted = _.bind(onUnstarted, state);
state.videoPlayer.handlePlaybackQualityChange = _.bind(
handlePlaybackQualityChange, state
......@@ -86,13 +84,8 @@ function (HTML5Video, Resizer) {
state.videoPlayer.playerVars.html5 = 1;
}
if (state.config.start) {
state.videoPlayer.playerVars.start = state.config.start;
state.videoPlayer.playerVars.wmode = 'window';
}
if (state.config.end) {
state.videoPlayer.playerVars.end = state.config.end;
}
state.videoPlayer.playerVars.start = state.config.start;
state.videoPlayer.playerVars.end = state.config.end;
// 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
......@@ -479,6 +472,13 @@ function (HTML5Video, Resizer) {
);
this.trigger(
'videoProgressSlider.updateStartEndTimeRegion',
{
duration: duration
}
);
this.trigger(
'videoControl.updateVcrVidTime',
{
time: time,
......
......@@ -28,21 +28,29 @@ function () {
// function _makeFunctionsPublic(state)
//
// Functions which will be accessible via 'state' object. When called, these functions will
// get the 'state' object as a context.
// Functions which will be accessible via 'state' object. When called,
// these functions will get the 'state' object as a context.
function _makeFunctionsPublic(state) {
state.videoProgressSlider.onSlide = _.bind(onSlide, state);
state.videoProgressSlider.onStop = _.bind(onStop, state);
state.videoProgressSlider.updatePlayTime = _.bind(updatePlayTime, state);
state.videoProgressSlider.updatePlayTime = _.bind(
updatePlayTime, state
);
//Added for tests -- JM
state.videoProgressSlider.buildSlider = _.bind(buildSlider, state);
state.videoProgressSlider.updateStartEndTimeRegion = _.bind(
updateStartEndTimeRegion, state
);
}
// function _renderElements(state)
//
// Create any necessary DOM elements, attach them, and set their initial configuration. Also
// make the created DOM elements available via the 'state' object. Much easier to work this
// way - you don't have to do repeated jQuery element selects.
// Create any necessary DOM elements, attach them, and set their
// initial configuration. Also make the created DOM elements available
// via the 'state' object. Much easier to work this way - you don't
// have to do repeated jQuery element selects.
function _renderElements(state) {
if (!onTouchBasedDevice()) {
state.videoProgressSlider.el = state.videoControl.sliderEl;
......@@ -53,8 +61,9 @@ function () {
}
function _buildHandle(state) {
state.videoProgressSlider.handle = state.videoProgressSlider.el.find('.ui-slider-handle');
state.videoProgressSlider.handle = state.videoProgressSlider.el
.find('.ui-slider-handle');
// ARIA
// We just want the knob to be selectable with keyboard
state.videoProgressSlider.el.attr('tabindex', -1);
......@@ -64,28 +73,75 @@ function () {
'role': 'slider',
'title': 'video position',
'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.
// These are available via the 'state' object. Their context ('this' keyword) is the 'state' object.
// The magic private function that makes them available and sets up their context is makeFunctionsPublic().
// These are available via the 'state' object. Their context ('this'
// keyword) is the 'state' object. The magic private function that makes
// them available and sets up their context is makeFunctionsPublic().
// ***************************************************************
function buildSlider(state) {
state.videoProgressSlider.slider = state.videoProgressSlider.el.slider({
range: 'min',
slide: state.videoProgressSlider.onSlide,
stop: state.videoProgressSlider.onStop
});
console.log('state = ', state);
state.videoProgressSlider.slider = state.videoProgressSlider.el
.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) {
this.videoProgressSlider.frozen = true;
this.trigger('videoPlayer.onSlideSeek', {'type': 'onSlideSeek', 'time': ui.value});
this.trigger(
'videoPlayer.onSlideSeek',
{'type': 'onSlideSeek', 'time': ui.value}
);
// ARIA
this.videoProgressSlider.handle.attr(
......@@ -98,7 +154,10 @@ function () {
this.videoProgressSlider.frozen = true;
this.trigger('videoPlayer.onSlideSeek', {'type': 'onSlideSeek', 'time': ui.value});
this.trigger(
'videoPlayer.onSlideSeek',
{'type': 'onSlideSeek', 'time': ui.value}
);
// ARIA
this.videoProgressSlider.handle.attr(
......@@ -110,23 +169,28 @@ function () {
}, 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) {
if ((this.videoProgressSlider.slider) && (!this.videoProgressSlider.frozen)) {
/*this.videoProgressSlider.slider
.slider('option', 'max', params.duration)
.slider('value', params.time);*/
this.videoProgressSlider.slider.slider('option', 'max', params.duration);
this.videoProgressSlider.slider.slider('option', 'value', params.time);
if (
(this.videoProgressSlider.slider) &&
(!this.videoProgressSlider.frozen)
) {
this.videoProgressSlider.slider
.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) {
var seconds = Math.floor(time),
minutes = Math.floor(seconds / 60),
hours = Math.floor(minutes / 60),
hrStr, minStr, secStr;
seconds = seconds % 60;
minutes = minutes % 60;
......@@ -136,30 +200,36 @@ function () {
if (hours) {
hrStr += (hours < 2 ? ' hour ' : ' hours ');
if (minutes) {
if (minutes) {
minStr += (minutes < 2 ? ' minute ' : ' minutes ');
} else {
minStr += ' 0 minutes ';
}
if (seconds) {
if (seconds) {
secStr += (seconds < 2 ? ' second ' : ' seconds ');
} else {
secStr += ' 0 seconds ';
}
}
return hrStr + minStr + secStr;
} else if (minutes) {
minStr += (minutes < 2 ? ' minute ' : ' minutes ');
if (seconds) {
if (seconds) {
secStr += (seconds < 2 ? ' second ' : ' seconds ');
} else {
secStr += ' 0 seconds ';
}
return minStr + secStr;
} else if (seconds) {
secStr += (seconds < 2 ? ' second ' : ' seconds ');
return secStr;
}
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