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
2df00412
Commit
2df00412
authored
Sep 18, 2013
by
jmclaus
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #933 from edx/jmclaus/bugfix_tabbing_captions
Tabbing through captions
parents
c0b710b8
7659c5b1
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
227 additions
and
5 deletions
+227
-5
common/lib/xmodule/xmodule/css/video/display.scss
+7
-0
common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
+109
-2
common/lib/xmodule/xmodule/js/src/video/09_video_caption.js
+111
-3
No files found.
common/lib/xmodule/xmodule/css/video/display.scss
View file @
2df00412
...
...
@@ -525,12 +525,19 @@ div.video {
margin-bottom
:
8px
;
padding
:
0
;
line-height
:
lh
();
outline-width
:
0px
;
outline-style
:
none
;
&
.current
{
color
:
#333
;
font-weight
:
700
;
}
&
.focused
{
outline-width
:
1px
;
outline-style
:
dotted
;
}
&
:hover
{
color
:
$blue
;
}
...
...
common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
View file @
2df00412
...
...
@@ -93,6 +93,7 @@
$
(
'.subtitles li[data-index]'
).
each
(
function
(
index
,
link
)
{
expect
(
$
(
link
)).
toHaveData
(
'index'
,
index
);
expect
(
$
(
link
)).
toHaveData
(
'start'
,
captionsData
.
start
[
index
]);
expect
(
$
(
link
)).
toHaveAttr
(
'tabindex'
,
0
);
expect
(
$
(
link
)).
toHaveText
(
captionsData
.
text
[
index
]);
});
});
...
...
@@ -104,7 +105,13 @@
it
(
'bind all the caption link'
,
function
()
{
$
(
'.subtitles li[data-index]'
).
each
(
function
(
index
,
link
)
{
expect
(
$
(
link
)).
toHandleWith
(
'click'
,
videoCaption
.
seekPlayer
);
expect
(
$
(
link
)).
toHandleWith
(
'mouseover'
,
videoCaption
.
captionMouseOverOut
);
expect
(
$
(
link
)).
toHandleWith
(
'mouseout'
,
videoCaption
.
captionMouseOverOut
);
expect
(
$
(
link
)).
toHandleWith
(
'mousedown'
,
videoCaption
.
captionMouseDown
);
expect
(
$
(
link
)).
toHandleWith
(
'click'
,
videoCaption
.
captionClick
);
expect
(
$
(
link
)).
toHandleWith
(
'focus'
,
videoCaption
.
captionFocus
);
expect
(
$
(
link
)).
toHandleWith
(
'blur'
,
videoCaption
.
captionBlur
);
expect
(
$
(
link
)).
toHandleWith
(
'keydown'
,
videoCaption
.
captionKeyDown
);
});
});
...
...
@@ -278,6 +285,7 @@
$
(
'.subtitles li[data-index]'
).
each
(
function
(
index
,
link
)
{
expect
(
$
(
link
)).
toHaveData
(
'index'
,
index
);
expect
(
$
(
link
)).
toHaveData
(
'start'
,
captionsData
.
start
[
index
]);
expect
(
$
(
link
)).
toHaveAttr
(
'tabindex'
,
0
);
expect
(
$
(
link
)).
toHaveText
(
captionsData
.
text
[
index
]);
});
});
...
...
@@ -289,7 +297,13 @@
it
(
'bind all the caption link'
,
function
()
{
$
(
'.subtitles li[data-index]'
).
each
(
function
(
index
,
link
)
{
expect
(
$
(
link
)).
toHandleWith
(
'click'
,
videoCaption
.
seekPlayer
);
expect
(
$
(
link
)).
toHandleWith
(
'mouseover'
,
videoCaption
.
captionMouseOverOut
);
expect
(
$
(
link
)).
toHandleWith
(
'mouseout'
,
videoCaption
.
captionMouseOverOut
);
expect
(
$
(
link
)).
toHandleWith
(
'mousedown'
,
videoCaption
.
captionMouseDown
);
expect
(
$
(
link
)).
toHandleWith
(
'click'
,
videoCaption
.
captionClick
);
expect
(
$
(
link
)).
toHandleWith
(
'focus'
,
videoCaption
.
captionFocus
);
expect
(
$
(
link
)).
toHandleWith
(
'blur'
,
videoCaption
.
captionBlur
);
expect
(
$
(
link
)).
toHandleWith
(
'keydown'
,
videoCaption
.
captionKeyDown
);
});
});
...
...
@@ -558,6 +572,99 @@
});
});
});
describe
(
'caption accessibility'
,
function
()
{
beforeEach
(
function
()
{
initialize
();
});
describe
(
'when getting focus through TAB key'
,
function
()
{
beforeEach
(
function
()
{
videoCaption
.
isMouseFocus
=
false
;
$
(
'.subtitles li[data-index=0]'
).
trigger
(
jQuery
.
Event
(
'focus'
));
});
it
(
'shows an outline around the caption'
,
function
()
{
expect
(
$
(
'.subtitles li[data-index=0]'
)).
toHaveClass
(
'focused'
);
});
it
(
'has automatic scrolling disabled'
,
function
()
{
expect
(
videoCaption
.
autoScrolling
).
toBe
(
false
);
});
});
describe
(
'when loosing focus through TAB key'
,
function
()
{
beforeEach
(
function
()
{
$
(
'.subtitles li[data-index=0]'
).
trigger
(
jQuery
.
Event
(
'blur'
));
});
it
(
'does not show an outline around the caption'
,
function
()
{
expect
(
$
(
'.subtitles li[data-index=0]'
)).
not
.
toHaveClass
(
'focused'
);
});
it
(
'has automatic scrolling enabled'
,
function
()
{
expect
(
videoCaption
.
autoScrolling
).
toBe
(
true
);
});
});
describe
(
'when same caption gets the focus through mouse after having focus through TAB key'
,
function
()
{
beforeEach
(
function
()
{
videoCaption
.
isMouseFocus
=
false
;
$
(
'.subtitles li[data-index=0]'
).
trigger
(
jQuery
.
Event
(
'focus'
));
$
(
'.subtitles li[data-index=0]'
).
trigger
(
jQuery
.
Event
(
'mousedown'
));
});
it
(
'does not show an outline around it'
,
function
()
{
expect
(
$
(
'.subtitles li[data-index=0]'
)).
not
.
toHaveClass
(
'focused'
);
});
it
(
'has automatic scrolling enabled'
,
function
()
{
expect
(
videoCaption
.
autoScrolling
).
toBe
(
true
);
});
});
describe
(
'when a second caption gets focus through mouse after first had focus through TAB key'
,
function
()
{
beforeEach
(
function
()
{
videoCaption
.
isMouseFocus
=
false
;
$
(
'.subtitles li[data-index=0]'
).
trigger
(
jQuery
.
Event
(
'focus'
));
$
(
'.subtitles li[data-index=0]'
).
trigger
(
jQuery
.
Event
(
'blur'
));
videoCaption
.
isMouseFocus
=
true
;
$
(
'.subtitles li[data-index=1]'
).
trigger
(
jQuery
.
Event
(
'mousedown'
));
});
it
(
'does not show an outline around the first'
,
function
()
{
expect
(
$
(
'.subtitles li[data-index=0]'
)).
not
.
toHaveClass
(
'focused'
);
});
it
(
'does not show an outline around the second'
,
function
()
{
expect
(
$
(
'.subtitles li[data-index=1]'
)).
not
.
toHaveClass
(
'focused'
);
});
it
(
'has automatic scrolling enabled'
,
function
()
{
expect
(
videoCaption
.
autoScrolling
).
toBe
(
true
);
});
});
describe
(
'when enter key is pressed on a caption'
,
function
()
{
beforeEach
(
function
()
{
var
e
;
spyOn
(
videoCaption
,
'seekPlayer'
).
andCallThrough
();
videoCaption
.
isMouseFocus
=
false
;
$
(
'.subtitles li[data-index=0]'
).
trigger
(
jQuery
.
Event
(
'focus'
));
e
=
jQuery
.
Event
(
'keydown'
);
e
.
which
=
13
;
// ENTER key
$
(
'.subtitles li[data-index=0]'
).
trigger
(
e
);
});
it
(
'shows an outline around it'
,
function
()
{
expect
(
$
(
'.subtitles li[data-index=0]'
)).
toHaveClass
(
'focused'
);
});
it
(
'calls seekPlayer'
,
function
()
{
expect
(
videoCaption
.
seekPlayer
).
toHaveBeenCalled
();
});
});
});
});
}).
call
(
this
);
common/lib/xmodule/xmodule/js/src/video/09_video_caption.js
View file @
2df00412
...
...
@@ -62,6 +62,12 @@ function () {
state
.
videoCaption
.
bindHandlers
=
_
.
bind
(
bindHandlers
,
state
);
state
.
videoCaption
.
fetchCaption
=
_
.
bind
(
fetchCaption
,
state
);
state
.
videoCaption
.
captionURL
=
_
.
bind
(
captionURL
,
state
);
state
.
videoCaption
.
captionMouseOverOut
=
_
.
bind
(
captionMouseOverOut
,
state
);
state
.
videoCaption
.
captionMouseDown
=
_
.
bind
(
captionMouseDown
,
state
);
state
.
videoCaption
.
captionClick
=
_
.
bind
(
captionClick
,
state
);
state
.
videoCaption
.
captionFocus
=
_
.
bind
(
captionFocus
,
state
);
state
.
videoCaption
.
captionBlur
=
_
.
bind
(
captionBlur
,
state
);
state
.
videoCaption
.
captionKeyDown
=
_
.
bind
(
captionKeyDown
,
state
);
}
// ***************************************************************
...
...
@@ -309,7 +315,8 @@ function () {
liEl
.
attr
({
'data-index'
:
index
,
'data-start'
:
_this
.
videoCaption
.
start
[
index
]
'data-start'
:
_this
.
videoCaption
.
start
[
index
],
'tabindex'
:
0
});
container
.
append
(
liEl
);
...
...
@@ -317,7 +324,33 @@ function () {
this
.
videoCaption
.
subtitlesEl
.
html
(
container
.
html
());
this
.
videoCaption
.
subtitlesEl
.
find
(
'li[data-index]'
).
on
(
'click'
,
this
.
videoCaption
.
seekPlayer
);
this
.
videoCaption
.
subtitlesEl
.
find
(
'li[data-index]'
).
on
({
mouseover
:
this
.
videoCaption
.
captionMouseOverOut
,
mouseout
:
this
.
videoCaption
.
captionMouseOverOut
,
mousedown
:
this
.
videoCaption
.
captionMouseDown
,
click
:
this
.
videoCaption
.
captionClick
,
focus
:
this
.
videoCaption
.
captionFocus
,
blur
:
this
.
videoCaption
.
captionBlur
,
keydown
:
this
.
videoCaption
.
captionKeyDown
});
// Enables or disables automatic scrolling of the captions when the
// video is playing. This feature has to be disabled when tabbing
// through them as it interferes with that action. Initially, have this
// flag enabled as we assume mouse use. Then, if the first caption
// (through forward tabbing) or the last caption (through backwards
// tabbing) gets the focus, disable that feature. Renable it if tabbing
// then cycles out of the the captions.
this
.
videoCaption
.
autoScrolling
=
true
;
// Keeps track of where the focus is situated in the array of captions.
// Used to implement the automatic scrolling behavior and decide if the
// outline around a caption has to be hidden or shown on a mouseenter or
// mouseleave.
this
.
videoCaption
.
currentCaptionIndex
=
0
;
// Used to track if the focus is coming from a click or tabbing. This
// has to be known to decide if, when a caption gets the focus, an
// outline has to be drawn (tabbing) or not (mouse click).
this
.
videoCaption
.
isMouseFocus
=
false
;
this
.
videoCaption
.
subtitlesEl
.
prepend
(
$
(
'<li class="spacing">'
).
height
(
this
.
videoCaption
.
topSpacingHeight
()));
this
.
videoCaption
.
subtitlesEl
.
append
(
$
(
'<li class="spacing">'
).
height
(
this
.
videoCaption
.
bottomSpacingHeight
()));
...
...
@@ -325,10 +358,85 @@ function () {
this
.
videoCaption
.
rendered
=
true
;
}
// On mouseOver, hide the outline of a caption that has been tabbed to.
// On mouseOut, show the outline of a caption that has been tabbed to.
function
captionMouseOverOut
(
event
)
{
var
caption
=
$
(
event
.
target
),
captionIndex
=
parseInt
(
caption
.
attr
(
'data-index'
),
10
);
if
(
captionIndex
===
this
.
videoCaption
.
currentCaptionIndex
)
{
if
(
event
.
type
===
'mouseover'
)
{
caption
.
removeClass
(
'focused'
);
}
else
{
// mouseout
caption
.
addClass
(
'focused'
);
}
}
}
function
captionMouseDown
(
event
)
{
var
caption
=
$
(
event
.
target
);
this
.
videoCaption
.
isMouseFocus
=
true
;
this
.
videoCaption
.
autoScrolling
=
true
;
caption
.
removeClass
(
'focused'
);
this
.
videoCaption
.
currentCaptionIndex
=
-
1
;
}
function
captionClick
(
event
)
{
this
.
videoCaption
.
seekPlayer
(
event
);
}
function
captionFocus
(
event
)
{
var
caption
=
$
(
event
.
target
),
captionIndex
=
parseInt
(
caption
.
attr
(
'data-index'
),
10
);
// If the focus comes from a mouse click, hide the outline, turn on
// automatic scrolling and set currentCaptionIndex to point outside of
// caption list (ie -1) to disable mouseenter, mouseleave behavior.
if
(
this
.
videoCaption
.
isMouseFocus
)
{
this
.
videoCaption
.
autoScrolling
=
true
;
caption
.
removeClass
(
'focused'
);
this
.
videoCaption
.
currentCaptionIndex
=
-
1
;
}
// If the focus comes from tabbing, show the outline and turn off
// automatic scrolling.
else
{
this
.
videoCaption
.
currentCaptionIndex
=
captionIndex
;
caption
.
addClass
(
'focused'
);
// The second and second to last elements turn automatic scrolling
// off again as it may have been enabled in captionBlur.
if
(
captionIndex
<=
1
||
captionIndex
>=
this
.
videoCaption
.
captions
.
length
-
2
)
{
this
.
videoCaption
.
autoScrolling
=
false
;
}
}
}
function
captionBlur
(
event
)
{
var
caption
=
$
(
event
.
target
),
captionIndex
=
parseInt
(
caption
.
attr
(
'data-index'
),
10
);
caption
.
removeClass
(
'focused'
);
// If we are on first or last index, we have to turn automatic scroll on
// again when losing focus. There is no way to know in what direction we
// are tabbing. So we could be on the first element and tabbing back out
// of the captions or on the last element and tabbing forward out of the
// captions.
if
(
captionIndex
===
0
||
captionIndex
===
this
.
videoCaption
.
captions
.
length
-
1
)
{
this
.
videoCaption
.
autoScrolling
=
true
;
}
}
function
captionKeyDown
(
event
)
{
this
.
videoCaption
.
isMouseFocus
=
false
;
if
(
event
.
which
===
13
)
{
//Enter key
this
.
videoCaption
.
seekPlayer
(
event
);
}
}
function
scrollCaption
()
{
var
el
=
this
.
videoCaption
.
subtitlesEl
.
find
(
'.current:first'
);
if
(
!
this
.
videoCaption
.
frozen
&&
el
.
length
)
{
// Automatic scrolling gets disabled if one of the captions has received
// focus through tabbing.
if
(
!
this
.
videoCaption
.
frozen
&&
el
.
length
&&
this
.
videoCaption
.
autoScrolling
)
{
this
.
videoCaption
.
subtitlesEl
.
scrollTo
(
el
,
{
...
...
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