From fe8e6026a1bb42e003273c02b3efb40089b3fc03 Mon Sep 17 00:00:00 2001 From: polesye Date: Thu, 27 Feb 2014 17:50:17 +0200 Subject: [PATCH] BLD-852: Fix video positioning in full view mode. --- CHANGELOG.rst | 2 + .../xmodule/xmodule/css/video/display.scss | 47 ++++----- common/lib/xmodule/xmodule/js/spec/helper.js | 9 +- .../xmodule/js/spec/video/resizer_spec.js | 90 +++++++++++++++-- .../js/spec/video/video_caption_spec.js | 7 -- .../js/spec/video/video_control_spec.js | 11 +++ .../js/spec/video/video_player_spec.js | 5 +- .../xmodule/js/src/video/00_resizer.js | 49 ++++++++-- .../xmodule/js/src/video/03_video_player.js | 8 +- .../xmodule/js/src/video/04_video_control.js | 45 ++++++--- .../xmodule/js/src/video/09_video_caption.js | 20 ++-- .../courseware/features/video.feature | 32 +++++- lms/djangoapps/courseware/features/video.py | 98 +++++++++++++------ 13 files changed, 311 insertions(+), 112 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 41fb577b70..92142399f6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes, in roughly chronological order, most recent first. Add your entries at or near the top. Include a label indicating the component affected. +Blades: Fix bug when transcript cutting off view in full view mode. BLD-852. + Blades: Show start time or starting position on slider and VCR. BLD-823. Common: Upgraded CodeMirror to 3.21.0 with an accessibility patch applied. diff --git a/common/lib/xmodule/xmodule/css/video/display.scss b/common/lib/xmodule/xmodule/css/video/display.scss index 5fc6486698..e90d688372 100644 --- a/common/lib/xmodule/xmodule/css/video/display.scss +++ b/common/lib/xmodule/xmodule/css/video/display.scss @@ -256,6 +256,11 @@ div.video { margin: 0 lh() 0 0; padding: 0; + @media (max-width: 1120px) { + margin-right: lh(.5); + font-size: em(14); + } + li { float: left; margin-bottom: 0; @@ -292,11 +297,13 @@ div.video { } div.vidtime { - padding-left: lh(.75); font-weight: bold; line-height: 46px; //height of play pause buttons - padding-left: lh(.75); -webkit-font-smoothing: antialiased; + padding-left: lh(.75); + @media (max-width: 1120px) { + padding-left: lh(.5); + } } } } @@ -389,8 +396,8 @@ div.video { .menu{ width: 131px; - @media (max-width: 1024px) { - width: 101px; + @media (max-width: 1120px) { + width: 80px; } } @@ -403,9 +410,9 @@ div.video { min-width: 116px; text-indent: 0; - @media (max-width: 1024px) { + @media (max-width: 1120px) { min-width: 0; - width: 86px; + width: 60px; } h3 { @@ -418,7 +425,7 @@ div.video { text-transform: uppercase; color: #999; - @media (max-width: 1024px) { + @media (max-width: 1120px) { display: none; } } @@ -429,7 +436,7 @@ div.video { margin-bottom: 0; padding: 0 lh(.5) 0 0; - @media (max-width: 1024px) { + @media (max-width: 1120px) { padding: 0 lh(.5) 0 lh(.5); } @@ -676,9 +683,10 @@ div.video { vertical-align: middle; &.closed { - ol.subtitles { - right: -(flex-grid(4)); - width: auto; + div.tc-wrapper { + article.video-wrapper { + width: 100%; + } } } @@ -698,17 +706,16 @@ div.video { div.tc-wrapper { @include clearfix; - display: table; width: 100%; height: 100%; position: static; article.video-wrapper { - width: 100%; - display: table-cell; + height: 100%; + width: 75%; vertical-align: middle; - float: none; + margin-right: 0; object, iframe, video{ position: absolute; @@ -727,16 +734,12 @@ div.video { } ol.subtitles { + @include box-sizing(border-box); @include transition(none); - background: rgba(#000, .8); - bottom: 0; + background: #000; height: 100%; - max-height: 460px; - max-width: flex-grid(3); + width: 25%; padding: lh(); - position: fixed; - right: 0; - top: 0; visibility: visible; li { diff --git a/common/lib/xmodule/xmodule/js/spec/helper.js b/common/lib/xmodule/xmodule/js/spec/helper.js index 1013faf367..2d81328d62 100644 --- a/common/lib/xmodule/xmodule/js/spec/helper.js +++ b/common/lib/xmodule/xmodule/js/spec/helper.js @@ -240,12 +240,19 @@ 'setParams', 'setMode' ], - obj = {}; + obj = {}, + delta = { + add: jasmine.createSpy().andReturn(obj), + substract: jasmine.createSpy().andReturn(obj), + reset: jasmine.createSpy().andReturn(obj) + }; $.each(methods, function (index, method) { obj[method] = jasmine.createSpy(method).andReturn(obj); }); + obj.delta = delta; + return obj; }()); diff --git a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js index ea296bfa81..a09508670e 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js @@ -18,7 +18,7 @@ function (Resizer) { '', '' ].join(''), - config, container, element, originalConsoleLog; + config, container, element; beforeEach(function () { setFixtures(html); @@ -30,14 +30,9 @@ function (Resizer) { element: element }; - originalConsoleLog = window.console.log; spyOn(console, 'log'); }); - afterEach(function () { - window.console.log = originalConsoleLog; - }); - it('When Initialize without required parameters, log message is shown', function () { new Resizer({ }); @@ -134,7 +129,7 @@ function (Resizer) { expect(spiesList[0].calls.length).toEqual(1); }); - it('All callbacks are removed', function () { + it('all callbacks are removed', function () { $.each(spiesList, function (index, spy) { resizer.callbacks.add(spy); }); @@ -147,7 +142,7 @@ function (Resizer) { }); }); - it('Specific callback is removed', function () { + it('specific callback is removed', function () { $.each(spiesList, function (index, spy) { resizer.callbacks.add(spy); }); @@ -176,9 +171,86 @@ function (Resizer) { }); }); - }); + describe('Delta', function () { + var resizer; + + beforeEach(function () { + resizer = new Resizer(config); + }); + + it('adding delta align correctly by height', function () { + var delta = 100, + expectedHeight = container.height() + delta, + realHeight; + + resizer + .delta.add(delta, 'height') + .setMode('height'); + + realHeight = element.height(); + + expect(realHeight).toBe(expectedHeight); + }); + + it('adding delta align correctly by width', function () { + var delta = 100, + expectedWidth = container.width() + delta, + realWidth; + + resizer + .delta.add(delta, 'width') + .setMode('width'); + + realWidth = element.width(); + + expect(realWidth).toBe(expectedWidth); + }); + + it('substract delta align correctly by height', function () { + var delta = 100, + expectedHeight = container.height() - delta, + realHeight; + + resizer + .delta.substract(delta, 'height') + .setMode('height'); + + realHeight = element.height(); + + expect(realHeight).toBe(expectedHeight); + }); + + it('substract delta align correctly by width', function () { + var delta = 100, + expectedWidth = container.width() - delta, + realWidth; + + resizer + .delta.substract(delta, 'width') + .setMode('width'); + + realWidth = element.width(); + + expect(realWidth).toBe(expectedWidth); + }); + + it('reset delta', function () { + var delta = 100, + expectedWidth = container.width(), + realWidth; + + resizer + .delta.substract(delta, 'width') + .delta.reset() + .setMode('width'); + + realWidth = element.width(); + + expect(realWidth).toBe(expectedWidth); + }); + }); }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js index 24e238fcb0..f57cde4d1c 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js @@ -106,13 +106,6 @@ }); }); - it('bind window resize event', function () { - state = jasmine.initializePlayer(); - expect($(window)).toHandleWith( - 'resize', state.videoCaption.resize - ); - }); - it('bind the hide caption button', function () { state = jasmine.initializePlayer(); expect($('.hide-subtitles')).toHandleWith( diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js index ac442e391d..cdc43a7ae8 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js @@ -549,6 +549,17 @@ }); }); + it('Controls height is actual on switch to fullscreen', function () { + spyOn($.fn, 'height').andCallFake(function (val) { + return _.isUndefined(val) ? 100: this; + }); + + state = jasmine.initializePlayer(); + $(state.el).trigger('fullscreen'); + + expect(state.videoControl.height).toBe(150); + }); + describe('play', function () { beforeEach(function () { state = jasmine.initializePlayer(); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js index 2ffa89d25d..55c1cc4a53 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js @@ -711,6 +711,7 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); spyOn(state.videoCaption, 'resize').andCallThrough(); + spyOn($.fn, 'trigger').andCallThrough(); state.videoControl.toggleFullScreen(jQuery.Event('click')); }); @@ -725,7 +726,8 @@ function (VideoPlayer) { it('tell VideoCaption to resize', function () { expect(state.videoCaption.resize).toHaveBeenCalled(); - expect(state.resizer.setMode).toHaveBeenCalled(); + expect(state.resizer.setMode).toHaveBeenCalledWith('both'); + expect(state.resizer.delta.substract).toHaveBeenCalled(); }); }); @@ -758,6 +760,7 @@ function (VideoPlayer) { expect(state.videoCaption.resize).toHaveBeenCalled(); expect(state.resizer.setMode) .toHaveBeenCalledWith('width'); + expect(state.resizer.delta.reset).toHaveBeenCalled(); }); }); }); diff --git a/common/lib/xmodule/xmodule/js/src/video/00_resizer.js b/common/lib/xmodule/xmodule/js/src/video/00_resizer.js index 0fd34968a6..edff5a9163 100644 --- a/common/lib/xmodule/xmodule/js/src/video/00_resizer.js +++ b/common/lib/xmodule/xmodule/js/src/video/00_resizer.js @@ -13,20 +13,24 @@ function () { elementRatio: null }, callbacksList = [], + delta = { + height: 0, + width: 0 + }, module = {}, mode = null, config; var initialize = function (params) { - if (config) { - config = $.extend(true, config, params); - } else { - config = $.extend(true, {}, defaults, params); + if (!config) { + config = defaults; } + config = $.extend(true, {}, config, params); + if (!config.element) { console.log( - '[Video info]: Required parameter `element` is not passed.' + 'Required parameter `element` is not passed.' ); } @@ -35,8 +39,8 @@ function () { var getData = function () { var container = $(config.container), - containerWidth = container.width(), - containerHeight = container.height(), + containerWidth = container.width() + delta.width, + containerHeight = container.height() + delta.height, containerRatio = config.containerRatio, element = $(config.element), @@ -74,7 +78,6 @@ function () { default: if (data.containerRatio >= data.elementRatio) { alignByHeightOnly(); - } else { alignByWidthOnly(); } @@ -142,7 +145,7 @@ function () { addCallback(decorator); } else { - console.error('[Video info]: TypeError: Argument is not a function.'); + console.error('TypeError: Argument is not a function.'); } return module; @@ -168,6 +171,29 @@ function () { } }; + var cleanDelta = function () { + delta['height'] = 0; + delta['width'] = 0; + + return module; + }; + + var addDelta = function (value, side) { + if (_.isNumber(value) && _.isNumber(delta[side])) { + delta[side] += value; + } + + return module; + }; + + var substractDelta = function (value, side) { + if (_.isNumber(value) && _.isNumber(delta[side])) { + delta[side] -= value; + } + + return module; + }; + initialize.apply(module, arguments); return $.extend(true, module, { @@ -181,6 +207,11 @@ function () { once: addOnceCallback, remove: removeCallback, removeAll: removeCallbacks + }, + delta: { + add: addDelta, + substract: substractDelta, + reset: cleanDelta } }); }; diff --git a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js index 70d883baf8..7678a2db1e 100644 --- a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js +++ b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js @@ -221,7 +221,7 @@ function (HTML5Video, Resizer) { state.resizer = new Resizer({ element: state.videoEl, elementRatio: videoWidth/videoHeight, - container: state.videoEl.parent() + container: state.container }) .callbacks.once(function() { state.trigger('videoCaption.resize', null); @@ -235,7 +235,11 @@ function (HTML5Video, Resizer) { }); } - $(window).bind('resize', _.debounce(state.resizer.align, 100)); + $(window).on('resize', _.debounce(function () { + state.trigger('videoControl.updateControlsHeight', null); + state.trigger('videoCaption.resize', null); + state.resizer.align(); + }, 100)); } // function _restartUsingFlash(state) diff --git a/common/lib/xmodule/xmodule/js/src/video/04_video_control.js b/common/lib/xmodule/xmodule/js/src/video/04_video_control.js index 8c21568a0f..205d062551 100644 --- a/common/lib/xmodule/xmodule/js/src/video/04_video_control.js +++ b/common/lib/xmodule/xmodule/js/src/video/04_video_control.js @@ -40,6 +40,7 @@ function () { showPlayPlaceholder: showPlayPlaceholder, toggleFullScreen: toggleFullScreen, togglePlayback: togglePlayback, + updateControlsHeight: updateControlsHeight, updateVcrVidTime: updateVcrVidTime }; @@ -83,6 +84,8 @@ function () { 'role': 'slider', 'title': gettext('Video slider') }); + + state.videoControl.updateControlsHeight(); } // function _bindHandlers(state) @@ -91,6 +94,23 @@ function () { function _bindHandlers(state) { state.videoControl.playPauseEl.on('click', state.videoControl.togglePlayback); state.videoControl.fullScreenEl.on('click', state.videoControl.toggleFullScreen); + state.el.on('fullscreen', function (event, isFullScreen) { + var height = state.videoControl.updateControlsHeight(); + + if (isFullScreen) { + state.resizer + .delta + .substract(height, 'height') + .setMode('both'); + + } else { + state.resizer + .delta + .reset() + .setMode('width'); + } + }); + $(document).on('keyup', state.videoControl.exitFullScreen); if ((state.videoType === 'html5') && (state.config.autohideHtml5)) { @@ -110,12 +130,22 @@ function () { }); } } + function _getControlsHeight(control) { + return control.el.height() + 0.5 * control.sliderEl.height(); + } // *************************************************************** // 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(). // *************************************************************** + + function updateControlsHeight () { + this.videoControl.height = _getControlsHeight(this.videoControl); + + return this.videoControl.height; + } + function show() { this.videoControl.el.removeClass('is-hidden'); this.el.trigger('controls:show', arguments); @@ -234,13 +264,6 @@ function () { this.videoControl.fullScreenState = this.isFullScreen = false; fullScreenClassNameEl.removeClass('video-fullscreen'); text = gettext('Fill browser'); - - this.resizer - .setParams({ - container: this.videoEl.parent() - }) - .setMode('width'); - win.scrollTop(this.scrollPos); } else { this.scrollPos = win.scrollTop(); @@ -248,13 +271,6 @@ function () { this.videoControl.fullScreenState = this.isFullScreen = true; fullScreenClassNameEl.addClass('video-fullscreen'); text = gettext('Exit full browser'); - - this.resizer - .setParams({ - container: window - }) - .setMode('both'); - } this.videoControl.fullScreenEl @@ -262,6 +278,7 @@ function () { .text(text); this.trigger('videoCaption.resize', null); + this.el.trigger('fullscreen', [this.isFullScreen]); } function exitFullScreen(event) { diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index f71c4a17c4..13917defd2 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -135,7 +135,6 @@ function () { var self = this, Caption = this.videoCaption; - $(window).bind('resize', Caption.resize); Caption.hideSubtitlesEl.on({ 'click': Caption.toggle }); @@ -754,8 +753,12 @@ function () { }); } - if (this.resizer && !this.isFullScreen) { - this.resizer.alignByWidthOnly(); + if (this.resizer) { + if (this.isFullScreen) { + this.resizer.setMode('both'); + } else { + this.resizer.alignByWidthOnly(); + } } this.videoCaption.setSubtitlesHeight(); @@ -769,17 +772,8 @@ function () { } function captionHeight() { - var paddingTop; - if (this.isFullScreen) { - paddingTop = parseInt( - this.videoCaption.subtitlesEl.css('padding-top'), 10 - ); - - return $(window).height() - - this.videoControl.el.height() - - 0.5 * this.videoControl.sliderEl.height() - - 2 * paddingTop; + return this.container.height() - this.videoControl.height; } else { return this.container.height(); } diff --git a/lms/djangoapps/courseware/features/video.feature b/lms/djangoapps/courseware/features/video.feature index 36d051a22c..55b89ae165 100644 --- a/lms/djangoapps/courseware/features/video.feature +++ b/lms/djangoapps/courseware/features/video.feature @@ -83,7 +83,7 @@ Feature: LMS Video component Scenario: Language menu works correctly in Video component Given the course has a Video component in Youtube mode: | transcripts | sub | - | {"zh": "OEoXaMPEzfM"} | OEoXaMPEzfM | + | {"zh": "chinese_transcripts.srt"} | OEoXaMPEzfM | And I make sure captions are closed And I see video menu "language" with correct items And I select language with code "zh" @@ -95,7 +95,7 @@ Feature: LMS Video component Scenario: CC button works correctly w/o english transcript in HTML5 mode of Video component Given the course has a Video component in HTML5 mode: | transcripts | - | {"zh": "OEoXaMPEzfM"} | + | {"zh": "chinese_transcripts.srt"} | And I make sure captions are opened Then I see "好 各位同学" text in the captions @@ -113,7 +113,7 @@ Feature: LMS Video component Scenario: CC button works correctly w/o english transcript in Youtube mode of Video component Given the course has a Video component in Youtube mode: | transcripts | - | {"zh": "OEoXaMPEzfM"} | + | {"zh": "chinese_transcripts.srt"} | And I make sure captions are opened Then I see "好 各位同学" text in the captions @@ -129,3 +129,29 @@ Feature: LMS Video component Scenario: CC button is hidden if no translations Given the course has a Video component in Youtube mode Then button "CC" is hidden + + # 16 + Scenario: Video is aligned correctly if transcript is visible in fullscreen mode + Given the course has a Video component in HTML5 mode: + | sub | + | OEoXaMPEzfM | + And I make sure captions are opened + And I click video button "fullscreen" + Then I see video aligned correctly with enabled transcript + + # 17 + Scenario: Video is aligned correctly if transcript is hidden in fullscreen mode + Given the course has a Video component in Youtube mode + And I click video button "fullscreen" + Then I see video aligned correctly without enabled transcript + + # 18 + Scenario: Video is aligned correctly on transcript toggle in fullscreen mode + Given the course has a Video component in Youtube mode: + | sub | + | OEoXaMPEzfM | + And I make sure captions are opened + And I click video button "fullscreen" + Then I see video aligned correctly with enabled transcript + And I click video button "CC" + Then I see video aligned correctly without enabled transcript diff --git a/lms/djangoapps/courseware/features/video.py b/lms/djangoapps/courseware/features/video.py index 6b44c4405d..c1b221f8eb 100644 --- a/lms/djangoapps/courseware/features/video.py +++ b/lms/djangoapps/courseware/features/video.py @@ -21,25 +21,22 @@ HTML5_SOURCES = [ 'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.webm', 'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.ogv', ] + HTML5_SOURCES_INCORRECT = [ 'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.mp99', ] -VIDEO_BUTTONS = { - 'CC': '.hide-subtitles', - 'volume': '.volume', - 'play': '.video_control.play', - 'pause': '.video_control.pause', -} -VIDEO_MENUS = { - 'language': '.lang .menu', - 'speed': '.speed .menu', -} VIDEO_BUTTONS = { 'CC': '.hide-subtitles', 'volume': '.volume', 'play': '.video_control.play', 'pause': '.video_control.pause', + 'fullscreen': '.add-fullscreen', +} + +VIDEO_MENUS = { + 'language': '.lang .menu', + 'speed': '.speed .menu', } coursenum = 'test_course' @@ -83,23 +80,22 @@ def add_video_to_course(course, player_mode, hashes, display_name='Video'): if hashes: kwargs['metadata'].update(hashes[0]) + course_location = world.scenario_dict['COURSE'].location + + if 'sub' in kwargs['metadata']: + filename = _get_sjson_filename(kwargs['metadata']['sub'], 'en') + _upload_file(filename, course_location) if 'transcripts' in kwargs['metadata']: kwargs['metadata']['transcripts'] = json.loads(kwargs['metadata']['transcripts']) - course_location = world.scenario_dict['COURSE'].location - if 'sub' in kwargs['metadata']: - filename = _get_transcript_filename(kwargs['metadata']['sub'], 'en') - _upload_file(filename, course_location) - - for lang, videoId in kwargs['metadata']['transcripts'].items(): - filename = _get_transcript_filename(videoId, lang) + for lang, filename in kwargs['metadata']['transcripts'].items(): _upload_file(filename, course_location) world.scenario_dict['VIDEO'] = world.ItemFactory.create(**kwargs) -def _get_transcript_filename(videoId, lang): +def _get_sjson_filename(videoId, lang): if lang == 'en': return 'subs_{0}.srt.sjson'.format(videoId) else: @@ -120,7 +116,7 @@ def _upload_file(filename, location): def _navigate_to_an_item_in_a_sequence(number): - sequence_css = 'a[data-element="{0}"]'.format(number) + sequence_css = '#sequence-list a[data-element="{0}"]'.format(number) world.css_click(sequence_css) @@ -136,6 +132,33 @@ def _open_menu(menu): )) +def _get_all_dimensions(): + video = _get_dimensions('.video-player iframe, .video-player video') + wrapper = _get_dimensions('.tc-wrapper') + controls = _get_dimensions('.video-controls') + progress_slider = _get_dimensions('.video-controls > .slider') + + expected = dict(wrapper) + expected['height'] -= controls['height'] + 0.5 * progress_slider['height'] + + return (video, expected) + + +def _get_dimensions(selector): + element = world.css_find(selector).first + return element._element.size + + +def _get_window_dimensions(): + return world.browser.driver.get_window_size() + + +def _set_window_dimensions(width, height): + world.browser.driver.set_window_size(width, height) + # Wait 200 ms when JS finish resizing + world.wait(0.2) + + @step('when I view the (.*) it does not have autoplay enabled$') def does_not_autoplay(_step, video_type): assert(world.css_find('.%s' % video_type)[0]['data-autoplay'] == 'False') @@ -143,10 +166,7 @@ def does_not_autoplay(_step, video_type): @step('the course has a Video component in (.*) mode(?:\:)?$') def view_video(_step, player_mode): - i_am_registered_for_the_course(_step, coursenum) - - # Make sure we have a video add_video_to_course(coursenum, player_mode.lower(), _step.hashes) visit_scenario_item('SECTION') @@ -203,7 +223,7 @@ def video_is_rendered(_step, mode): @step('all sources are correct$') def all_sources_are_correct(_step): - elements = world.css_find('.video video source') + elements = world.css_find('.video-player video source') sources = [source['src'].split('?')[0] for source in elements] assert set(sources) == set(HTML5_SOURCES) @@ -273,15 +293,8 @@ def select_language(_step, code): world.wait_for_ajax_complete() -@step('I click on video button "([^"]*)"$') -def click_button(_step, button): - world.css_find(VIDEO_BUTTONS[button]).click() - - @step('I click video button "([^"]*)"$') -def click_button_video(_step, button_type): - world.wait_for_ajax_complete() - button = button_type.strip() +def click_button(_step, button): world.css_click(VIDEO_BUTTONS[button]) @@ -309,3 +322,26 @@ def upload_to_assets(_step, filename): def is_hidden_button(_step, button): assert not world.css_visible(VIDEO_BUTTONS[button]) + +@step('I see video aligned correctly (with(?:out)?) enabled transcript$') +def video_alignment(_step, transcript_visibility): + # Width of the video container in css equal 75% of window if transcript enabled + wrapper_width = 75 if transcript_visibility == "with" else 100 + initial = _get_window_dimensions() + + _set_window_dimensions(300, 600) + real, expected = _get_all_dimensions() + + width = round(100 * real['width']/expected['width']) == wrapper_width + + _set_window_dimensions(600, 300) + real, expected = _get_all_dimensions() + + height = abs(expected['height'] - real['height']) <= 5 + + # Restore initial window size + _set_window_dimensions( + initial['width'], initial['height'] + ) + + assert all([width, height])