Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
58eaaf29
Commit
58eaaf29
authored
Mar 07, 2014
by
Anton Stupak
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2813 from edx/anton/fix-transcript-in-full-screen-mode
Fix video positioning in full view mode.
parents
c34fef6c
fe8e6026
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
308 additions
and
109 deletions
+308
-109
CHANGELOG.rst
+2
-0
common/lib/xmodule/xmodule/css/video/display.scss
+25
-22
common/lib/xmodule/xmodule/js/spec/helper.js
+8
-1
common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js
+81
-9
common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
+0
-7
common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js
+11
-0
common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
+4
-1
common/lib/xmodule/xmodule/js/src/video/00_resizer.js
+40
-9
common/lib/xmodule/xmodule/js/src/video/03_video_player.js
+6
-2
common/lib/xmodule/xmodule/js/src/video/04_video_control.js
+31
-14
common/lib/xmodule/xmodule/js/src/video/09_video_caption.js
+7
-13
lms/djangoapps/courseware/features/video.feature
+29
-3
lms/djangoapps/courseware/features/video.py
+64
-28
No files found.
CHANGELOG.rst
View file @
58eaaf29
...
@@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes,
...
@@ -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
in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected.
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.
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.
Common: Upgraded CodeMirror to 3.21.0 with an accessibility patch applied.
...
...
common/lib/xmodule/xmodule/css/video/display.scss
View file @
58eaaf29
...
@@ -256,6 +256,11 @@ div.video {
...
@@ -256,6 +256,11 @@ div.video {
margin
:
0
lh
()
0
0
;
margin
:
0
lh
()
0
0
;
padding
:
0
;
padding
:
0
;
@media
(
max-width
:
1120px
)
{
margin-right
:
lh
(
.5
);
font-size
:
em
(
14
);
}
li
{
li
{
float
:
left
;
float
:
left
;
margin-bottom
:
0
;
margin-bottom
:
0
;
...
@@ -292,11 +297,13 @@ div.video {
...
@@ -292,11 +297,13 @@ div.video {
}
}
div
.vidtime
{
div
.vidtime
{
padding-left
:
lh
(
.75
);
font-weight
:
bold
;
font-weight
:
bold
;
line-height
:
46px
;
//height of play pause buttons
line-height
:
46px
;
//height of play pause buttons
padding-left
:
lh
(
.75
);
-webkit-font-smoothing
:
antialiased
;
-webkit-font-smoothing
:
antialiased
;
padding-left
:
lh
(
.75
);
@media
(
max-width
:
1120px
)
{
padding-left
:
lh
(
.5
);
}
}
}
}
}
}
}
...
@@ -389,8 +396,8 @@ div.video {
...
@@ -389,8 +396,8 @@ div.video {
.menu
{
.menu
{
width
:
131px
;
width
:
131px
;
@media
(
max-width
:
1
024
px
)
{
@media
(
max-width
:
1
120
px
)
{
width
:
101
px
;
width
:
80
px
;
}
}
}
}
...
@@ -403,9 +410,9 @@ div.video {
...
@@ -403,9 +410,9 @@ div.video {
min-width
:
116px
;
min-width
:
116px
;
text-indent
:
0
;
text-indent
:
0
;
@media
(
max-width
:
1
024
px
)
{
@media
(
max-width
:
1
120
px
)
{
min-width
:
0
;
min-width
:
0
;
width
:
86
px
;
width
:
60
px
;
}
}
h3
{
h3
{
...
@@ -418,7 +425,7 @@ div.video {
...
@@ -418,7 +425,7 @@ div.video {
text-transform
:
uppercase
;
text-transform
:
uppercase
;
color
:
#999
;
color
:
#999
;
@media
(
max-width
:
1
024
px
)
{
@media
(
max-width
:
1
120
px
)
{
display
:
none
;
display
:
none
;
}
}
}
}
...
@@ -429,7 +436,7 @@ div.video {
...
@@ -429,7 +436,7 @@ div.video {
margin-bottom
:
0
;
margin-bottom
:
0
;
padding
:
0
lh
(
.5
)
0
0
;
padding
:
0
lh
(
.5
)
0
0
;
@media
(
max-width
:
1
024
px
)
{
@media
(
max-width
:
1
120
px
)
{
padding
:
0
lh
(
.5
)
0
lh
(
.5
);
padding
:
0
lh
(
.5
)
0
lh
(
.5
);
}
}
...
@@ -676,9 +683,10 @@ div.video {
...
@@ -676,9 +683,10 @@ div.video {
vertical-align
:
middle
;
vertical-align
:
middle
;
&
.closed
{
&
.closed
{
ol
.subtitles
{
div
.tc-wrapper
{
right
:
-
(
flex-grid
(
4
));
article
.video-wrapper
{
width
:
auto
;
width
:
100%
;
}
}
}
}
}
...
@@ -698,17 +706,16 @@ div.video {
...
@@ -698,17 +706,16 @@ div.video {
div
.tc-wrapper
{
div
.tc-wrapper
{
@include
clearfix
;
@include
clearfix
;
display
:
table
;
width
:
100%
;
width
:
100%
;
height
:
100%
;
height
:
100%
;
position
:
static
;
position
:
static
;
article
.video-wrapper
{
article
.video-wrapper
{
width
:
100%
;
height
:
100%
;
display
:
table-cell
;
width
:
75%
;
vertical-align
:
middle
;
vertical-align
:
middle
;
float
:
none
;
margin-right
:
0
;
object
,
iframe
,
video
{
object
,
iframe
,
video
{
position
:
absolute
;
position
:
absolute
;
...
@@ -727,16 +734,12 @@ div.video {
...
@@ -727,16 +734,12 @@ div.video {
}
}
ol
.subtitles
{
ol
.subtitles
{
@include
box-sizing
(
border-box
);
@include
transition
(
none
);
@include
transition
(
none
);
background
:
rgba
(
#000
,
.8
);
background
:
#000
;
bottom
:
0
;
height
:
100%
;
height
:
100%
;
max-height
:
460px
;
width
:
25%
;
max-width
:
flex-grid
(
3
);
padding
:
lh
();
padding
:
lh
();
position
:
fixed
;
right
:
0
;
top
:
0
;
visibility
:
visible
;
visibility
:
visible
;
li
{
li
{
...
...
common/lib/xmodule/xmodule/js/spec/helper.js
View file @
58eaaf29
...
@@ -240,12 +240,19 @@
...
@@ -240,12 +240,19 @@
'setParams'
,
'setParams'
,
'setMode'
'setMode'
],
],
obj
=
{};
obj
=
{},
delta
=
{
add
:
jasmine
.
createSpy
().
andReturn
(
obj
),
substract
:
jasmine
.
createSpy
().
andReturn
(
obj
),
reset
:
jasmine
.
createSpy
().
andReturn
(
obj
)
};
$
.
each
(
methods
,
function
(
index
,
method
)
{
$
.
each
(
methods
,
function
(
index
,
method
)
{
obj
[
method
]
=
jasmine
.
createSpy
(
method
).
andReturn
(
obj
);
obj
[
method
]
=
jasmine
.
createSpy
(
method
).
andReturn
(
obj
);
});
});
obj
.
delta
=
delta
;
return
obj
;
return
obj
;
}());
}());
...
...
common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js
View file @
58eaaf29
...
@@ -18,7 +18,7 @@ function (Resizer) {
...
@@ -18,7 +18,7 @@ function (Resizer) {
'</div>'
,
'</div>'
,
'</div>'
'</div>'
].
join
(
''
),
].
join
(
''
),
config
,
container
,
element
,
originalConsoleLog
;
config
,
container
,
element
;
beforeEach
(
function
()
{
beforeEach
(
function
()
{
setFixtures
(
html
);
setFixtures
(
html
);
...
@@ -30,14 +30,9 @@ function (Resizer) {
...
@@ -30,14 +30,9 @@ function (Resizer) {
element
:
element
element
:
element
};
};
originalConsoleLog
=
window
.
console
.
log
;
spyOn
(
console
,
'log'
);
spyOn
(
console
,
'log'
);
});
});
afterEach
(
function
()
{
window
.
console
.
log
=
originalConsoleLog
;
});
it
(
'When Initialize without required parameters, log message is shown'
,
it
(
'When Initialize without required parameters, log message is shown'
,
function
()
{
function
()
{
new
Resizer
({
});
new
Resizer
({
});
...
@@ -134,7 +129,7 @@ function (Resizer) {
...
@@ -134,7 +129,7 @@ function (Resizer) {
expect
(
spiesList
[
0
].
calls
.
length
).
toEqual
(
1
);
expect
(
spiesList
[
0
].
calls
.
length
).
toEqual
(
1
);
});
});
it
(
'
A
ll callbacks are removed'
,
function
()
{
it
(
'
a
ll callbacks are removed'
,
function
()
{
$
.
each
(
spiesList
,
function
(
index
,
spy
)
{
$
.
each
(
spiesList
,
function
(
index
,
spy
)
{
resizer
.
callbacks
.
add
(
spy
);
resizer
.
callbacks
.
add
(
spy
);
});
});
...
@@ -147,7 +142,7 @@ function (Resizer) {
...
@@ -147,7 +142,7 @@ function (Resizer) {
});
});
});
});
it
(
'
S
pecific callback is removed'
,
function
()
{
it
(
'
s
pecific callback is removed'
,
function
()
{
$
.
each
(
spiesList
,
function
(
index
,
spy
)
{
$
.
each
(
spiesList
,
function
(
index
,
spy
)
{
resizer
.
callbacks
.
add
(
spy
);
resizer
.
callbacks
.
add
(
spy
);
});
});
...
@@ -176,9 +171,86 @@ function (Resizer) {
...
@@ -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
);
});
});
});
});
});
});
...
...
common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
View file @
58eaaf29
...
@@ -106,13 +106,6 @@
...
@@ -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
()
{
it
(
'bind the hide caption button'
,
function
()
{
state
=
jasmine
.
initializePlayer
();
state
=
jasmine
.
initializePlayer
();
expect
(
$
(
'.hide-subtitles'
)).
toHandleWith
(
expect
(
$
(
'.hide-subtitles'
)).
toHandleWith
(
...
...
common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js
View file @
58eaaf29
...
@@ -549,6 +549,17 @@
...
@@ -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
()
{
describe
(
'play'
,
function
()
{
beforeEach
(
function
()
{
beforeEach
(
function
()
{
state
=
jasmine
.
initializePlayer
();
state
=
jasmine
.
initializePlayer
();
...
...
common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
View file @
58eaaf29
...
@@ -711,6 +711,7 @@ function (VideoPlayer) {
...
@@ -711,6 +711,7 @@ function (VideoPlayer) {
state
.
videoEl
=
$
(
'video, iframe'
);
state
.
videoEl
=
$
(
'video, iframe'
);
spyOn
(
state
.
videoCaption
,
'resize'
).
andCallThrough
();
spyOn
(
state
.
videoCaption
,
'resize'
).
andCallThrough
();
spyOn
(
$
.
fn
,
'trigger'
).
andCallThrough
();
state
.
videoControl
.
toggleFullScreen
(
jQuery
.
Event
(
'click'
));
state
.
videoControl
.
toggleFullScreen
(
jQuery
.
Event
(
'click'
));
});
});
...
@@ -725,7 +726,8 @@ function (VideoPlayer) {
...
@@ -725,7 +726,8 @@ function (VideoPlayer) {
it
(
'tell VideoCaption to resize'
,
function
()
{
it
(
'tell VideoCaption to resize'
,
function
()
{
expect
(
state
.
videoCaption
.
resize
).
toHaveBeenCalled
();
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) {
...
@@ -758,6 +760,7 @@ function (VideoPlayer) {
expect
(
state
.
videoCaption
.
resize
).
toHaveBeenCalled
();
expect
(
state
.
videoCaption
.
resize
).
toHaveBeenCalled
();
expect
(
state
.
resizer
.
setMode
)
expect
(
state
.
resizer
.
setMode
)
.
toHaveBeenCalledWith
(
'width'
);
.
toHaveBeenCalledWith
(
'width'
);
expect
(
state
.
resizer
.
delta
.
reset
).
toHaveBeenCalled
();
});
});
});
});
});
});
...
...
common/lib/xmodule/xmodule/js/src/video/00_resizer.js
View file @
58eaaf29
...
@@ -13,20 +13,24 @@ function () {
...
@@ -13,20 +13,24 @@ function () {
elementRatio
:
null
elementRatio
:
null
},
},
callbacksList
=
[],
callbacksList
=
[],
delta
=
{
height
:
0
,
width
:
0
},
module
=
{},
module
=
{},
mode
=
null
,
mode
=
null
,
config
;
config
;
var
initialize
=
function
(
params
)
{
var
initialize
=
function
(
params
)
{
if
(
config
)
{
if
(
!
config
)
{
config
=
$
.
extend
(
true
,
config
,
params
);
config
=
defaults
;
}
else
{
config
=
$
.
extend
(
true
,
{},
defaults
,
params
);
}
}
config
=
$
.
extend
(
true
,
{},
config
,
params
);
if
(
!
config
.
element
)
{
if
(
!
config
.
element
)
{
console
.
log
(
console
.
log
(
'
[Video info]:
Required parameter `element` is not passed.'
'Required parameter `element` is not passed.'
);
);
}
}
...
@@ -35,8 +39,8 @@ function () {
...
@@ -35,8 +39,8 @@ function () {
var
getData
=
function
()
{
var
getData
=
function
()
{
var
container
=
$
(
config
.
container
),
var
container
=
$
(
config
.
container
),
containerWidth
=
container
.
width
(),
containerWidth
=
container
.
width
()
+
delta
.
width
,
containerHeight
=
container
.
height
(),
containerHeight
=
container
.
height
()
+
delta
.
height
,
containerRatio
=
config
.
containerRatio
,
containerRatio
=
config
.
containerRatio
,
element
=
$
(
config
.
element
),
element
=
$
(
config
.
element
),
...
@@ -74,7 +78,6 @@ function () {
...
@@ -74,7 +78,6 @@ function () {
default
:
default
:
if
(
data
.
containerRatio
>=
data
.
elementRatio
)
{
if
(
data
.
containerRatio
>=
data
.
elementRatio
)
{
alignByHeightOnly
();
alignByHeightOnly
();
}
else
{
}
else
{
alignByWidthOnly
();
alignByWidthOnly
();
}
}
...
@@ -142,7 +145,7 @@ function () {
...
@@ -142,7 +145,7 @@ function () {
addCallback
(
decorator
);
addCallback
(
decorator
);
}
else
{
}
else
{
console
.
error
(
'
[Video info]:
TypeError: Argument is not a function.'
);
console
.
error
(
'TypeError: Argument is not a function.'
);
}
}
return
module
;
return
module
;
...
@@ -168,6 +171,29 @@ function () {
...
@@ -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
);
initialize
.
apply
(
module
,
arguments
);
return
$
.
extend
(
true
,
module
,
{
return
$
.
extend
(
true
,
module
,
{
...
@@ -181,6 +207,11 @@ function () {
...
@@ -181,6 +207,11 @@ function () {
once
:
addOnceCallback
,
once
:
addOnceCallback
,
remove
:
removeCallback
,
remove
:
removeCallback
,
removeAll
:
removeCallbacks
removeAll
:
removeCallbacks
},
delta
:
{
add
:
addDelta
,
substract
:
substractDelta
,
reset
:
cleanDelta
}
}
});
});
};
};
...
...
common/lib/xmodule/xmodule/js/src/video/03_video_player.js
View file @
58eaaf29
...
@@ -221,7 +221,7 @@ function (HTML5Video, Resizer) {
...
@@ -221,7 +221,7 @@ function (HTML5Video, Resizer) {
state
.
resizer
=
new
Resizer
({
state
.
resizer
=
new
Resizer
({
element
:
state
.
videoEl
,
element
:
state
.
videoEl
,
elementRatio
:
videoWidth
/
videoHeight
,
elementRatio
:
videoWidth
/
videoHeight
,
container
:
state
.
videoEl
.
parent
()
container
:
state
.
container
})
})
.
callbacks
.
once
(
function
()
{
.
callbacks
.
once
(
function
()
{
state
.
trigger
(
'videoCaption.resize'
,
null
);
state
.
trigger
(
'videoCaption.resize'
,
null
);
...
@@ -235,7 +235,11 @@ function (HTML5Video, Resizer) {
...
@@ -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)
// function _restartUsingFlash(state)
...
...
common/lib/xmodule/xmodule/js/src/video/04_video_control.js
View file @
58eaaf29
...
@@ -40,6 +40,7 @@ function () {
...
@@ -40,6 +40,7 @@ function () {
showPlayPlaceholder
:
showPlayPlaceholder
,
showPlayPlaceholder
:
showPlayPlaceholder
,
toggleFullScreen
:
toggleFullScreen
,
toggleFullScreen
:
toggleFullScreen
,
togglePlayback
:
togglePlayback
,
togglePlayback
:
togglePlayback
,
updateControlsHeight
:
updateControlsHeight
,
updateVcrVidTime
:
updateVcrVidTime
updateVcrVidTime
:
updateVcrVidTime
};
};
...
@@ -83,6 +84,8 @@ function () {
...
@@ -83,6 +84,8 @@ function () {
'role'
:
'slider'
,
'role'
:
'slider'
,
'title'
:
gettext
(
'Video slider'
)
'title'
:
gettext
(
'Video slider'
)
});
});
state
.
videoControl
.
updateControlsHeight
();
}
}
// function _bindHandlers(state)
// function _bindHandlers(state)
...
@@ -91,6 +94,23 @@ function () {
...
@@ -91,6 +94,23 @@ function () {
function
_bindHandlers
(
state
)
{
function
_bindHandlers
(
state
)
{
state
.
videoControl
.
playPauseEl
.
on
(
'click'
,
state
.
videoControl
.
togglePlayback
);
state
.
videoControl
.
playPauseEl
.
on
(
'click'
,
state
.
videoControl
.
togglePlayback
);
state
.
videoControl
.
fullScreenEl
.
on
(
'click'
,
state
.
videoControl
.
toggleFullScreen
);
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
);
$
(
document
).
on
(
'keyup'
,
state
.
videoControl
.
exitFullScreen
);
if
((
state
.
videoType
===
'html5'
)
&&
(
state
.
config
.
autohideHtml5
))
{
if
((
state
.
videoType
===
'html5'
)
&&
(
state
.
config
.
autohideHtml5
))
{
...
@@ -110,12 +130,22 @@ function () {
...
@@ -110,12 +130,22 @@ function () {
});
});
}
}
}
}
function
_getControlsHeight
(
control
)
{
return
control
.
el
.
height
()
+
0.5
*
control
.
sliderEl
.
height
();
}
// ***************************************************************
// ***************************************************************
// 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' keyword) is the 'state' object.
// The magic private function that makes them available and sets up their context is makeFunctionsPublic().
// 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
()
{
function
show
()
{
this
.
videoControl
.
el
.
removeClass
(
'is-hidden'
);
this
.
videoControl
.
el
.
removeClass
(
'is-hidden'
);
this
.
el
.
trigger
(
'controls:show'
,
arguments
);
this
.
el
.
trigger
(
'controls:show'
,
arguments
);
...
@@ -234,13 +264,6 @@ function () {
...
@@ -234,13 +264,6 @@ function () {
this
.
videoControl
.
fullScreenState
=
this
.
isFullScreen
=
false
;
this
.
videoControl
.
fullScreenState
=
this
.
isFullScreen
=
false
;
fullScreenClassNameEl
.
removeClass
(
'video-fullscreen'
);
fullScreenClassNameEl
.
removeClass
(
'video-fullscreen'
);
text
=
gettext
(
'Fill browser'
);
text
=
gettext
(
'Fill browser'
);
this
.
resizer
.
setParams
({
container
:
this
.
videoEl
.
parent
()
})
.
setMode
(
'width'
);
win
.
scrollTop
(
this
.
scrollPos
);
win
.
scrollTop
(
this
.
scrollPos
);
}
else
{
}
else
{
this
.
scrollPos
=
win
.
scrollTop
();
this
.
scrollPos
=
win
.
scrollTop
();
...
@@ -248,13 +271,6 @@ function () {
...
@@ -248,13 +271,6 @@ function () {
this
.
videoControl
.
fullScreenState
=
this
.
isFullScreen
=
true
;
this
.
videoControl
.
fullScreenState
=
this
.
isFullScreen
=
true
;
fullScreenClassNameEl
.
addClass
(
'video-fullscreen'
);
fullScreenClassNameEl
.
addClass
(
'video-fullscreen'
);
text
=
gettext
(
'Exit full browser'
);
text
=
gettext
(
'Exit full browser'
);
this
.
resizer
.
setParams
({
container
:
window
})
.
setMode
(
'both'
);
}
}
this
.
videoControl
.
fullScreenEl
this
.
videoControl
.
fullScreenEl
...
@@ -262,6 +278,7 @@ function () {
...
@@ -262,6 +278,7 @@ function () {
.
text
(
text
);
.
text
(
text
);
this
.
trigger
(
'videoCaption.resize'
,
null
);
this
.
trigger
(
'videoCaption.resize'
,
null
);
this
.
el
.
trigger
(
'fullscreen'
,
[
this
.
isFullScreen
]);
}
}
function
exitFullScreen
(
event
)
{
function
exitFullScreen
(
event
)
{
...
...
common/lib/xmodule/xmodule/js/src/video/09_video_caption.js
View file @
58eaaf29
...
@@ -135,7 +135,6 @@ function () {
...
@@ -135,7 +135,6 @@ function () {
var
self
=
this
,
var
self
=
this
,
Caption
=
this
.
videoCaption
;
Caption
=
this
.
videoCaption
;
$
(
window
).
bind
(
'resize'
,
Caption
.
resize
);
Caption
.
hideSubtitlesEl
.
on
({
Caption
.
hideSubtitlesEl
.
on
({
'click'
:
Caption
.
toggle
'click'
:
Caption
.
toggle
});
});
...
@@ -754,8 +753,12 @@ function () {
...
@@ -754,8 +753,12 @@ function () {
});
});
}
}
if
(
this
.
resizer
&&
!
this
.
isFullScreen
)
{
if
(
this
.
resizer
)
{
this
.
resizer
.
alignByWidthOnly
();
if
(
this
.
isFullScreen
)
{
this
.
resizer
.
setMode
(
'both'
);
}
else
{
this
.
resizer
.
alignByWidthOnly
();
}
}
}
this
.
videoCaption
.
setSubtitlesHeight
();
this
.
videoCaption
.
setSubtitlesHeight
();
...
@@ -769,17 +772,8 @@ function () {
...
@@ -769,17 +772,8 @@ function () {
}
}
function
captionHeight
()
{
function
captionHeight
()
{
var
paddingTop
;
if
(
this
.
isFullScreen
)
{
if
(
this
.
isFullScreen
)
{
paddingTop
=
parseInt
(
return
this
.
container
.
height
()
-
this
.
videoControl
.
height
;
this
.
videoCaption
.
subtitlesEl
.
css
(
'padding-top'
),
10
);
return
$
(
window
).
height
()
-
this
.
videoControl
.
el
.
height
()
-
0.5
*
this
.
videoControl
.
sliderEl
.
height
()
-
2
*
paddingTop
;
}
else
{
}
else
{
return
this
.
container
.
height
();
return
this
.
container
.
height
();
}
}
...
...
lms/djangoapps/courseware/features/video.feature
View file @
58eaaf29
...
@@ -83,7 +83,7 @@ Feature: LMS Video component
...
@@ -83,7 +83,7 @@ Feature: LMS Video component
Scenario
:
Language menu works correctly in Video component
Scenario
:
Language menu works correctly in Video component
Given the course has a Video component in Youtube mode
:
Given the course has a Video component in Youtube mode
:
|
transcripts
|
sub
|
|
transcripts
|
sub
|
|
{"zh":
"
OEoXaMPEzfM
"}
|
OEoXaMPEzfM
|
|
{"zh":
"
chinese_transcripts.srt
"}
|
OEoXaMPEzfM
|
And
I make sure captions are closed
And
I make sure captions are closed
And
I see video menu
"language"
with correct items
And
I see video menu
"language"
with correct items
And
I select language with code
"zh"
And
I select language with code
"zh"
...
@@ -95,7 +95,7 @@ Feature: LMS Video component
...
@@ -95,7 +95,7 @@ Feature: LMS Video component
Scenario
:
CC button works correctly w/o english transcript in HTML5 mode of 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
:
Given the course has a Video component in HTML5 mode
:
|
transcripts
|
|
transcripts
|
|
{"zh":
"
OEoXaMPEzfM
"}
|
|
{"zh":
"
chinese_transcripts.srt
"}
|
And
I make sure captions are opened
And
I make sure captions are opened
Then
I see
"好 各位同学"
text in the captions
Then
I see
"好 各位同学"
text in the captions
...
@@ -113,7 +113,7 @@ Feature: LMS Video component
...
@@ -113,7 +113,7 @@ Feature: LMS Video component
Scenario
:
CC button works correctly w/o english transcript in Youtube mode of 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
:
Given the course has a Video component in Youtube mode
:
|
transcripts
|
|
transcripts
|
|
{"zh":
"
OEoXaMPEzfM
"}
|
|
{"zh":
"
chinese_transcripts.srt
"}
|
And
I make sure captions are opened
And
I make sure captions are opened
Then
I see
"好 各位同学"
text in the captions
Then
I see
"好 各位同学"
text in the captions
...
@@ -129,3 +129,29 @@ Feature: LMS Video component
...
@@ -129,3 +129,29 @@ Feature: LMS Video component
Scenario
:
CC button is hidden if no translations
Scenario
:
CC button is hidden if no translations
Given
the course has a Video component in Youtube mode
Given
the course has a Video component in Youtube mode
Then
button
"CC"
is hidden
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
lms/djangoapps/courseware/features/video.py
View file @
58eaaf29
...
@@ -21,27 +21,24 @@ HTML5_SOURCES = [
...
@@ -21,27 +21,24 @@ 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.webm'
,
'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.ogv'
,
'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.ogv'
,
]
]
HTML5_SOURCES_INCORRECT
=
[
HTML5_SOURCES_INCORRECT
=
[
'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.mp99'
,
'https://s3.amazonaws.com/edx-course-videos/edx-intro/edX-FA12-cware-1_100.mp99'
,
]
]
VIDEO_BUTTONS
=
{
VIDEO_BUTTONS
=
{
'CC'
:
'.hide-subtitles'
,
'CC'
:
'.hide-subtitles'
,
'volume'
:
'.volume'
,
'volume'
:
'.volume'
,
'play'
:
'.video_control.play'
,
'play'
:
'.video_control.play'
,
'pause'
:
'.video_control.pause'
,
'pause'
:
'.video_control.pause'
,
'fullscreen'
:
'.add-fullscreen'
,
}
}
VIDEO_MENUS
=
{
VIDEO_MENUS
=
{
'language'
:
'.lang .menu'
,
'language'
:
'.lang .menu'
,
'speed'
:
'.speed .menu'
,
'speed'
:
'.speed .menu'
,
}
}
VIDEO_BUTTONS
=
{
'CC'
:
'.hide-subtitles'
,
'volume'
:
'.volume'
,
'play'
:
'.video_control.play'
,
'pause'
:
'.video_control.pause'
,
}
coursenum
=
'test_course'
coursenum
=
'test_course'
sequence
=
{}
sequence
=
{}
...
@@ -83,23 +80,22 @@ def add_video_to_course(course, player_mode, hashes, display_name='Video'):
...
@@ -83,23 +80,22 @@ def add_video_to_course(course, player_mode, hashes, display_name='Video'):
if
hashes
:
if
hashes
:
kwargs
[
'metadata'
]
.
update
(
hashes
[
0
])
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'
]:
if
'transcripts'
in
kwargs
[
'metadata'
]:
kwargs
[
'metadata'
][
'transcripts'
]
=
json
.
loads
(
kwargs
[
'metadata'
][
'transcripts'
])
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
():
for
lang
,
filename
in
kwargs
[
'metadata'
][
'transcripts'
]
.
items
():
filename
=
_get_transcript_filename
(
videoId
,
lang
)
_upload_file
(
filename
,
course_location
)
_upload_file
(
filename
,
course_location
)
world
.
scenario_dict
[
'VIDEO'
]
=
world
.
ItemFactory
.
create
(
**
kwargs
)
world
.
scenario_dict
[
'VIDEO'
]
=
world
.
ItemFactory
.
create
(
**
kwargs
)
def
_get_
transcript
_filename
(
videoId
,
lang
):
def
_get_
sjson
_filename
(
videoId
,
lang
):
if
lang
==
'en'
:
if
lang
==
'en'
:
return
'subs_{0}.srt.sjson'
.
format
(
videoId
)
return
'subs_{0}.srt.sjson'
.
format
(
videoId
)
else
:
else
:
...
@@ -120,7 +116,7 @@ def _upload_file(filename, location):
...
@@ -120,7 +116,7 @@ def _upload_file(filename, location):
def
_navigate_to_an_item_in_a_sequence
(
number
):
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
)
world
.
css_click
(
sequence_css
)
...
@@ -136,6 +132,33 @@ def _open_menu(menu):
...
@@ -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$'
)
@step
(
'when I view the (.*) it does not have autoplay enabled$'
)
def
does_not_autoplay
(
_step
,
video_type
):
def
does_not_autoplay
(
_step
,
video_type
):
assert
(
world
.
css_find
(
'.
%
s'
%
video_type
)[
0
][
'data-autoplay'
]
==
'False'
)
assert
(
world
.
css_find
(
'.
%
s'
%
video_type
)[
0
][
'data-autoplay'
]
==
'False'
)
...
@@ -143,10 +166,7 @@ def does_not_autoplay(_step, video_type):
...
@@ -143,10 +166,7 @@ def does_not_autoplay(_step, video_type):
@step
(
'the course has a Video component in (.*) mode(?:
\
:)?$'
)
@step
(
'the course has a Video component in (.*) mode(?:
\
:)?$'
)
def
view_video
(
_step
,
player_mode
):
def
view_video
(
_step
,
player_mode
):
i_am_registered_for_the_course
(
_step
,
coursenum
)
i_am_registered_for_the_course
(
_step
,
coursenum
)
# Make sure we have a video
add_video_to_course
(
coursenum
,
player_mode
.
lower
(),
_step
.
hashes
)
add_video_to_course
(
coursenum
,
player_mode
.
lower
(),
_step
.
hashes
)
visit_scenario_item
(
'SECTION'
)
visit_scenario_item
(
'SECTION'
)
...
@@ -203,7 +223,7 @@ def video_is_rendered(_step, mode):
...
@@ -203,7 +223,7 @@ def video_is_rendered(_step, mode):
@step
(
'all sources are correct$'
)
@step
(
'all sources are correct$'
)
def
all_sources_are_correct
(
_step
):
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
]
sources
=
[
source
[
'src'
]
.
split
(
'?'
)[
0
]
for
source
in
elements
]
assert
set
(
sources
)
==
set
(
HTML5_SOURCES
)
assert
set
(
sources
)
==
set
(
HTML5_SOURCES
)
...
@@ -273,15 +293,8 @@ def select_language(_step, code):
...
@@ -273,15 +293,8 @@ def select_language(_step, code):
world
.
wait_for_ajax_complete
()
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 "([^"]*)"$'
)
@step
(
'I click video button "([^"]*)"$'
)
def
click_button_video
(
_step
,
button_type
):
def
click_button
(
_step
,
button
):
world
.
wait_for_ajax_complete
()
button
=
button_type
.
strip
()
world
.
css_click
(
VIDEO_BUTTONS
[
button
])
world
.
css_click
(
VIDEO_BUTTONS
[
button
])
...
@@ -309,3 +322,26 @@ def upload_to_assets(_step, filename):
...
@@ -309,3 +322,26 @@ def upload_to_assets(_step, filename):
def
is_hidden_button
(
_step
,
button
):
def
is_hidden_button
(
_step
,
button
):
assert
not
world
.
css_visible
(
VIDEO_BUTTONS
[
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
])
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment