Merge pull request #1336 from edx/anton/fix-video-display-issue
Fix Video player display issue
This commit is contained in:
@@ -74,10 +74,8 @@ div.video {
|
||||
}
|
||||
|
||||
section.video-player {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
padding-bottom: 56.25%;
|
||||
position: relative;
|
||||
min-height: 300px;
|
||||
|
||||
div {
|
||||
&.hidden {
|
||||
@@ -85,12 +83,9 @@ div.video {
|
||||
}
|
||||
}
|
||||
|
||||
object, iframe {
|
||||
object, iframe, video {
|
||||
border: none;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -701,15 +696,12 @@ div.video {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
float: none;
|
||||
}
|
||||
|
||||
object, iframe {
|
||||
bottom: 0;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
object, iframe, video{
|
||||
position: absolute;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
section.video-controls {
|
||||
|
||||
93
common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js
Normal file
93
common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js
Normal file
@@ -0,0 +1,93 @@
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
require(
|
||||
['video/00_resizer.js'],
|
||||
function (Resizer) {
|
||||
|
||||
describe('Resizer', function () {
|
||||
var html = [
|
||||
'<div class="rszr-wrapper" style="width:200px; height: 200px;">',
|
||||
'<div class="rszr-el" style="width:100px; height: 150px;">',
|
||||
'Content',
|
||||
'</div>',
|
||||
'</div>'
|
||||
].join(''),
|
||||
config, container, element;
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures(html);
|
||||
|
||||
container = $('.rszr-wrapper');
|
||||
element = $('.rszr-el');
|
||||
config = {
|
||||
container: container,
|
||||
element: element
|
||||
};
|
||||
});
|
||||
|
||||
it('When Initialize without required parameters, log message is shown',
|
||||
function () {
|
||||
spyOn(console, 'log');
|
||||
|
||||
new Resizer({ });
|
||||
expect(console.log).toHaveBeenCalled();
|
||||
}
|
||||
);
|
||||
|
||||
it('`alignByWidthOnly` works correctly', function () {
|
||||
var resizer = new Resizer(config).alignByWidthOnly(),
|
||||
expectedWidth = container.width(),
|
||||
realWidth = element.width();
|
||||
|
||||
expect(realWidth).toBe(expectedWidth);
|
||||
});
|
||||
|
||||
it('`alignByHeightOnly` works correctly', function () {
|
||||
var resizer = new Resizer(config).alignByHeightOnly(),
|
||||
expectedHeight = container.height(),
|
||||
realHeight = element.height(),
|
||||
realWidth;
|
||||
|
||||
expect(realHeight).toBe(expectedHeight);
|
||||
});
|
||||
|
||||
it('`align` works correctly', function () {
|
||||
var resizer = new Resizer(config).align(),
|
||||
expectedHeight = container.height(),
|
||||
realHeight = element.height(),
|
||||
expectedWidth = 50;
|
||||
|
||||
// containerRatio >= elementRatio
|
||||
expect(realHeight).toBe(expectedHeight);
|
||||
|
||||
// containerRatio < elementRatio
|
||||
container.width(expectedWidth);
|
||||
resizer.align();
|
||||
realWidth = element.width();
|
||||
|
||||
expect(realWidth).toBe(expectedWidth);
|
||||
|
||||
});
|
||||
|
||||
it('`setMode` works correctly', function () {
|
||||
var resizer = new Resizer(config).setMode('height'),
|
||||
expectedHeight = container.height(),
|
||||
realHeight = element.height(),
|
||||
expectedWidth = 50;
|
||||
|
||||
// containerRatio >= elementRatio
|
||||
expect(realHeight).toBe(expectedHeight);
|
||||
|
||||
// containerRatio < elementRatio
|
||||
container.width(expectedWidth);
|
||||
resizer.setMode('width');
|
||||
realWidth = element.width();
|
||||
|
||||
expect(realWidth).toBe(expectedWidth);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define));
|
||||
@@ -10,6 +10,8 @@
|
||||
}
|
||||
|
||||
state = new Video('#example');
|
||||
|
||||
state.videoEl = $('video, iframe');
|
||||
videoPlayer = state.videoPlayer;
|
||||
player = videoPlayer.player;
|
||||
videoControl = state.videoControl;
|
||||
@@ -17,6 +19,19 @@
|
||||
videoProgressSlider = state.videoProgressSlider;
|
||||
videoSpeedControl = state.videoSpeedControl;
|
||||
videoVolumeControl = state.videoVolumeControl;
|
||||
|
||||
state.resizer = (function () {
|
||||
var methods = [
|
||||
'align', 'alignByWidthOnly', 'alignByHeightOnly', 'setParams', 'setMode'
|
||||
],
|
||||
obj = {};
|
||||
|
||||
$.each(methods, function(index, method) {
|
||||
obj[method] = jasmine.createSpy(method).andReturn(obj);
|
||||
});
|
||||
|
||||
return obj;
|
||||
})();
|
||||
}
|
||||
|
||||
function initializeYouTube() {
|
||||
@@ -557,6 +572,7 @@
|
||||
|
||||
it('tell VideoCaption to resize', function() {
|
||||
expect(videoCaption.resize).toHaveBeenCalled();
|
||||
expect(state.resizer.setMode).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -583,6 +599,7 @@
|
||||
|
||||
it('tell VideoCaption to resize', function() {
|
||||
expect(videoCaption.resize).toHaveBeenCalled();
|
||||
expect(state.resizer.setMode).toHaveBeenCalledWith('width');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
134
common/lib/xmodule/xmodule/js/src/video/00_resizer.js
Normal file
134
common/lib/xmodule/xmodule/js/src/video/00_resizer.js
Normal file
@@ -0,0 +1,134 @@
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(
|
||||
'video/00_resizer.js',
|
||||
[],
|
||||
function () {
|
||||
|
||||
var Resizer = function (params) {
|
||||
var defaults = {
|
||||
container: window,
|
||||
element: null,
|
||||
containerRatio: null,
|
||||
elementRatio: null
|
||||
},
|
||||
mode = null,
|
||||
config;
|
||||
|
||||
var initialize = function (params) {
|
||||
if (config) {
|
||||
config = $.extend(true, config, params);
|
||||
} else {
|
||||
config = $.extend(true, {}, defaults, params);
|
||||
}
|
||||
|
||||
if (!config.element) {
|
||||
console.log('Required parameter `element` is not passed.');
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
var getData = function () {
|
||||
var container = $(config.container),
|
||||
containerWidth = container.width(),
|
||||
containerHeight = container.height(),
|
||||
containerRatio = config.containerRatio,
|
||||
|
||||
element = $(config.element),
|
||||
elementRatio = config.elementRatio;
|
||||
|
||||
if (!containerRatio) {
|
||||
containerRatio = containerWidth/containerHeight;
|
||||
}
|
||||
|
||||
if (!elementRatio) {
|
||||
elementRatio = element.width()/element.height();
|
||||
}
|
||||
|
||||
return {
|
||||
containerWidth: containerWidth,
|
||||
containerHeight: containerHeight,
|
||||
containerRatio: containerRatio,
|
||||
element: element,
|
||||
elementRatio: elementRatio
|
||||
};
|
||||
};
|
||||
|
||||
var align = function() {
|
||||
var data = getData();
|
||||
|
||||
switch (mode) {
|
||||
case 'height':
|
||||
alignByHeightOnly();
|
||||
break;
|
||||
|
||||
case 'width':
|
||||
alignByWidthOnly();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (data.containerRatio >= data.elementRatio) {
|
||||
alignByHeightOnly();
|
||||
|
||||
} else {
|
||||
alignByWidthOnly();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
var alignByWidthOnly = function () {
|
||||
var data = getData(),
|
||||
height = data.containerWidth/data.elementRatio;
|
||||
|
||||
data.element.css({
|
||||
'height': height,
|
||||
'width': data.containerWidth,
|
||||
'top': 0.5*(data.containerHeight - height),
|
||||
'left': 0
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
var alignByHeightOnly = function () {
|
||||
var data = getData(),
|
||||
width = data.containerHeight*data.elementRatio;
|
||||
|
||||
data.element.css({
|
||||
'height': data.containerHeight,
|
||||
'width': data.containerHeight*data.elementRatio,
|
||||
'top': 0,
|
||||
'left': 0.5*(data.containerWidth - width)
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
var setMode = function (param) {
|
||||
if (_.isString(param)) {
|
||||
mode = param;
|
||||
align();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
initialize.apply(this, arguments);
|
||||
|
||||
return {
|
||||
align: align,
|
||||
alignByWidthOnly: alignByWidthOnly,
|
||||
alignByHeightOnly: alignByHeightOnly,
|
||||
setParams: initialize,
|
||||
setMode: setMode
|
||||
};
|
||||
};
|
||||
|
||||
return Resizer;
|
||||
});
|
||||
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define));
|
||||
@@ -216,10 +216,6 @@ function () {
|
||||
// currently doing.
|
||||
this.videoEl = $(this.video);
|
||||
|
||||
this.videoEl.css({
|
||||
'width': '100%'
|
||||
});
|
||||
|
||||
this.playerState = HTML5Video.PlayerState.UNSTARTED;
|
||||
// this.callStateChangeCallback();
|
||||
|
||||
@@ -318,6 +314,6 @@ function () {
|
||||
|
||||
// HTML5Video object - what this module exports.
|
||||
return HTML5Video;
|
||||
})
|
||||
});
|
||||
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define));
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// VideoPlayer module.
|
||||
define(
|
||||
'video/03_video_player.js',
|
||||
['video/02_html5_video.js'],
|
||||
function (HTML5Video) {
|
||||
['video/02_html5_video.js', 'video/00_resizer.js' ],
|
||||
function (HTML5Video, Resizer) {
|
||||
|
||||
// VideoPlayer() function - what this module "exports".
|
||||
return function (state) {
|
||||
@@ -343,7 +343,8 @@ function (HTML5Video) {
|
||||
}
|
||||
|
||||
function onReady() {
|
||||
var availablePlaybackRates, baseSpeedSubs, _this;
|
||||
var availablePlaybackRates, baseSpeedSubs, _this,
|
||||
player, videoWidth, videoHeight;
|
||||
|
||||
this.videoPlayer.log('load_video');
|
||||
|
||||
@@ -420,6 +421,27 @@ function (HTML5Video) {
|
||||
this.videoPlayer.player.setPlaybackRate(this.speed);
|
||||
}
|
||||
|
||||
if (this.videoType === 'html5') {
|
||||
player = this.videoEl = this.videoPlayer.player.videoEl;
|
||||
videoWidth = player[0].videoWidth || player.width();
|
||||
videoHeight = player[0].videoHeight || player.height();
|
||||
} else {
|
||||
player = this.videoEl = this.el.find('iframe');
|
||||
videoWidth = player.attr('width') || player.width();
|
||||
videoHeight = player.attr('height') || player.height();
|
||||
}
|
||||
|
||||
this.resizer = new Resizer({
|
||||
element: this.videoEl,
|
||||
elementRatio: videoWidth/videoHeight,
|
||||
container: this.videoEl.parent()
|
||||
})
|
||||
.setMode('width');
|
||||
|
||||
this.trigger('videoCaption.resize', null);
|
||||
$(window).bind('resize', _.debounce(this.resizer.align, 100));
|
||||
|
||||
|
||||
/* The following has been commented out to make sure autoplay is
|
||||
disabled for students.
|
||||
if (
|
||||
|
||||
@@ -170,22 +170,41 @@ function () {
|
||||
|
||||
function toggleFullScreen(event) {
|
||||
event.preventDefault();
|
||||
var fullScreenClassNameEl = this.el.add(document.documentElement);
|
||||
var fullScreenClassNameEl = this.el.add(document.documentElement),
|
||||
win = $(window),
|
||||
text;
|
||||
|
||||
if (this.videoControl.fullScreenState) {
|
||||
this.videoControl.fullScreenState = false;
|
||||
this.videoControl.fullScreenState = this.isFullScreen = false;
|
||||
fullScreenClassNameEl.removeClass('video-fullscreen');
|
||||
this.isFullScreen = false;
|
||||
this.videoControl.fullScreenEl.attr('title', gettext('Fill browser'))
|
||||
.text(gettext('Fill browser'));
|
||||
text = gettext('Fill browser');
|
||||
|
||||
this.resizer
|
||||
.setParams({
|
||||
container: this.videoEl.parent()
|
||||
})
|
||||
.setMode('width');
|
||||
|
||||
win.scrollTop(this.scrollPos);
|
||||
} else {
|
||||
this.videoControl.fullScreenState = true;
|
||||
this.scrollPos = win.scrollTop();
|
||||
win.scrollTop(0);
|
||||
this.videoControl.fullScreenState = this.isFullScreen = true;
|
||||
fullScreenClassNameEl.addClass('video-fullscreen');
|
||||
this.isFullScreen = true;
|
||||
this.videoControl.fullScreenEl.attr('title', gettext('Exit full browser'))
|
||||
.text(gettext('Exit full browser'));
|
||||
text = gettext('Exit full browser');
|
||||
|
||||
this.resizer
|
||||
.setParams({
|
||||
container: window
|
||||
})
|
||||
.setMode('both');
|
||||
|
||||
}
|
||||
|
||||
this.videoControl.fullScreenEl
|
||||
.attr('title', text)
|
||||
.text(text);
|
||||
|
||||
this.trigger('videoCaption.resize', null);
|
||||
}
|
||||
|
||||
|
||||
@@ -700,7 +700,7 @@ function () {
|
||||
|
||||
function hideCaptions(hide_captions, update_cookie) {
|
||||
var hideSubtitlesEl = this.videoCaption.hideSubtitlesEl,
|
||||
type;
|
||||
type, text;
|
||||
|
||||
if (typeof update_cookie === 'undefined') {
|
||||
update_cookie = true;
|
||||
@@ -710,29 +710,33 @@ function () {
|
||||
type = 'hide_transcript';
|
||||
this.captionsHidden = true;
|
||||
|
||||
hideSubtitlesEl
|
||||
.attr('title', gettext('Turn on captions'))
|
||||
.text(gettext('Turn on captions'));
|
||||
|
||||
this.el.addClass('closed');
|
||||
|
||||
text = gettext('Turn on captions');
|
||||
} else {
|
||||
type = 'show_transcript';
|
||||
this.captionsHidden = false;
|
||||
|
||||
hideSubtitlesEl
|
||||
.attr('title', gettext('Turn off captions'))
|
||||
.text(gettext('Turn off captions'));
|
||||
|
||||
this.el.removeClass('closed');
|
||||
this.videoCaption.scrollCaption();
|
||||
|
||||
text = gettext('Turn off captions');
|
||||
}
|
||||
|
||||
hideSubtitlesEl
|
||||
.attr('title', text)
|
||||
.text(gettext(text));
|
||||
|
||||
if (this.videoPlayer) {
|
||||
this.videoPlayer.log(type, {
|
||||
currentTime: this.videoPlayer.currentTime
|
||||
});
|
||||
}
|
||||
|
||||
if (this.resizer) {
|
||||
this.resizer.alignByWidthOnly();
|
||||
}
|
||||
|
||||
this.videoCaption.setSubtitlesHeight();
|
||||
|
||||
if (update_cookie) {
|
||||
|
||||
@@ -135,6 +135,7 @@ class VideoModule(VideoFields, XModule):
|
||||
|
||||
js = {
|
||||
'js': [
|
||||
resource_string(__name__, 'js/src/video/00_resizer.js'),
|
||||
resource_string(__name__, 'js/src/video/01_initialize.js'),
|
||||
resource_string(__name__, 'js/src/video/025_focus_grabber.js'),
|
||||
resource_string(__name__, 'js/src/video/02_html5_video.js'),
|
||||
|
||||
Reference in New Issue
Block a user