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
88e10e0e
Commit
88e10e0e
authored
Dec 22, 2016
by
alisan617
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sequence navs keyboard support and test update
parent
4503ab42
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
199 additions
and
28 deletions
+199
-28
common/lib/xmodule/xmodule/css/sequence/display.scss
+1
-0
common/lib/xmodule/xmodule/js/fixtures/sequence.html
+43
-16
common/lib/xmodule/xmodule/js/spec/.gitignore
+1
-0
common/lib/xmodule/xmodule/js/spec/sequence/display_spec.js
+68
-0
common/lib/xmodule/xmodule/js/src/sequence/display.js
+69
-2
lms/djangoapps/courseware/tests/test_split_module.py
+1
-1
lms/static/lms/js/spec/main.js
+1
-0
lms/templates/seq_module.html
+15
-9
No files found.
common/lib/xmodule/xmodule/css/sequence/display.scss
View file @
88e10e0e
...
@@ -272,6 +272,7 @@ nav.sequence-bottom {
...
@@ -272,6 +272,7 @@ nav.sequence-bottom {
// hover and active states
// hover and active states
.sequence-nav-button
,
.sequence-nav-button
,
.sequence-nav
button
{
.sequence-nav
button
{
&
.focused
,
&
:hover
,
&
:hover
,
&
:active
,
&
:active
,
&
.active
{
&
.active
{
...
...
common/lib/xmodule/xmodule/js/fixtures/sequence.html
View file @
88e10e0e
<div
id=
"sequence_1"
class=
"sequence"
>
<div
class=
"xblock-student_view-sequential"
>
<nav
class=
"sequence-nav"
>
<div
id=
"sequence_workflow"
class=
"sequence"
>
<ol
id=
"sequence-list"
>
<div
class=
"sequence-nav"
>
</ol>
<button
class=
"sequence-nav-button button-previous"
>
<span
class=
"icon fa fa-chevron-prev"
aria-hidden=
"true"
></span>
<span>
Previous
</span>
</button>
<nav
class=
"sequence-list-wrapper"
aria-label=
"Unit"
>
<ol
id=
"sequence-list"
role=
"tablist"
>
<li>
<button
role=
"tab"
tabindex=
"0"
aria-selected=
"true"
aria-expanded=
"true"
aria-controls=
"seq_content"
class=
"seq_problem nav-item tab active"
data-index=
"0"
data-id=
"block-v1:edX+DemoX+Demo_Course+type@vertical+block@fb79dcbad35b466a8c6364f8ffee9050"
data-element=
"1"
data-page-title=
"Unit 101"
data-path=
"Example Week 2: Get Interactive > Homework - Part 1 > Unit 101"
id=
"tab_0"
>
<span
class=
"icon fa seq_problem"
aria-hidden=
"true"
></span>
<span
class=
"fa fa-fw fa-bookmark bookmark-icon is-hidden"
aria-hidden=
"true"
></span>
<div
class=
"sequence-tooltip sr"
><span
class=
"sr"
>
problem
</span>
Unit 101
<span
class=
"sr bookmark-icon-sr"
></span></div>
</button>
</li>
<li>
<button
role=
"tab"
tabindex=
"-1"
aria-selected=
"true"
aria-expanded=
"true"
aria-controls=
"seq_content"
class=
"seq_problem inactive nav-item tab"
data-index=
"1"
data-id=
"block-v1:edX+DemoX+Demo_Course+type@vertical+block@fb79dcbad35b466a8c6364f8ffee9051"
data-element=
"2"
data-page-title=
"Unit 102"
data-path=
"Example Week 2: Get Interactive > Homework - Part 1 > Unit 102"
id=
"tab_1"
>
<span
class=
"icon fa seq_problem"
aria-hidden=
"true"
></span>
<span
class=
"fa fa-fw fa-bookmark bookmark-icon is-hidden"
aria-hidden=
"true"
></span>
<div
class=
"sequence-tooltip sr"
><span
class=
"sr"
>
problem
</span>
Unit 102
<span
class=
"sr bookmark-icon-sr"
></span></div>
</button>
</li>
</ol>
</nav>
<button
class=
"sequence-nav-button button-next"
>
<span>
Next
</span>
<span
class=
"icon fa fa-chevron-next"
aria-hidden=
"true"
></span>
</button>
</div>
<ul
class=
"sequence-nav-buttons"
>
<div
class=
"sr-is-focusable"
tabindex=
"-1"
></div>
<li
class=
"prev"
><button>
Previous
</button></li>
<li
class=
"next"
><button>
Next
</button></li>
</ul>
</nav>
<div
id=
"seq_content
"
></div>
<div
id=
"seq_content"
role=
"tabpanel
"
></div>
<nav
class=
"sequence-bottom"
>
<nav
class=
"sequence-bottom"
aria-label=
"Section"
>
<ul
class=
"sequence-nav-buttons"
>
<button
class=
"sequence-nav-button button-previous"
>
<li
class=
"prev"
><button>
Previous
</button></li>
<span
class=
"icon fa fa-chevron-prev"
aria-hidden=
"true"
></span>
<li
class=
"next"
><button>
Next
</button></li>
<span>
Previous
</span>
</ul>
</button>
</nav>
<button
class=
"sequence-nav-button button-next"
>
<span>
Next
</span>
<span
class=
"icon fa fa-chevron-next"
aria-hidden=
"true"
></span>
</button>
</nav>
</div>
</div>
</div>
common/lib/xmodule/xmodule/js/spec/.gitignore
View file @
88e10e0e
...
@@ -7,3 +7,4 @@
...
@@ -7,3 +7,4 @@
!time_spec.js
!time_spec.js
!collapsible_spec.js
!collapsible_spec.js
!xmodule_spec.js
!xmodule_spec.js
!sequence/display_spec.js
common/lib/xmodule/xmodule/js/spec/sequence/display_spec.js
0 → 100644
View file @
88e10e0e
/* globals Sequence */
(
function
()
{
'use strict'
;
describe
(
'Sequence'
,
function
()
{
var
local
=
{},
keydownHandler
,
keys
=
{
ENTER
:
13
,
LEFT
:
37
,
RIGHT
:
39
};
beforeEach
(
function
()
{
loadFixtures
(
'sequence.html'
);
local
.
XBlock
=
window
.
XBlock
=
jasmine
.
createSpyObj
(
'XBlock'
,
[
'initializeBlocks'
]);
});
afterEach
(
function
()
{
delete
local
.
XBlock
;
});
keydownHandler
=
function
(
key
)
{
var
event
=
document
.
createEvent
(
'Event'
);
event
.
keyCode
=
key
;
event
.
initEvent
(
'keydown'
,
false
,
false
);
document
.
dispatchEvent
(
event
);
};
describe
(
'Navbar'
,
function
()
{
it
(
'works with keyboard navigation LEFT and ENTER'
,
function
()
{
this
.
sequence
=
new
Sequence
(
$
(
'.xblock-student_view-sequential'
));
this
.
sequence
.
$
(
'.nav-item[data-index=0]'
).
focus
();
keydownHandler
(
keys
.
LEFT
);
keydownHandler
(
keys
.
ENTER
);
expect
(
this
.
sequence
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
({
'aria-expanded'
:
'false'
,
'aria-selected'
:
'false'
,
tabindex
:
'-1'
});
expect
(
this
.
sequence
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
({
'aria-expanded'
:
'true'
,
'aria-selected'
:
'true'
,
tabindex
:
'0'
});
});
it
(
'works with keyboard navigation RIGHT and ENTER'
,
function
()
{
this
.
sequence
=
new
Sequence
(
$
(
'.xblock-student_view-sequential'
));
this
.
sequence
.
$
(
'.nav-item[data-index=0]'
).
focus
();
keydownHandler
(
keys
.
RIGHT
);
keydownHandler
(
keys
.
ENTER
);
expect
(
this
.
sequence
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
({
'aria-expanded'
:
'false'
,
'aria-selected'
:
'false'
,
tabindex
:
'-1'
});
expect
(
this
.
sequence
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
({
'aria-expanded'
:
'true'
,
'aria-selected'
:
'true'
,
tabindex
:
'0'
});
});
});
});
}).
call
(
this
);
common/lib/xmodule/xmodule/js/src/sequence/display.js
View file @
88e10e0e
...
@@ -38,6 +38,12 @@
...
@@ -38,6 +38,12 @@
this
.
displayTabTooltip
=
function
(
event
)
{
this
.
displayTabTooltip
=
function
(
event
)
{
return
Sequence
.
prototype
.
displayTabTooltip
.
apply
(
self
,
[
event
]);
return
Sequence
.
prototype
.
displayTabTooltip
.
apply
(
self
,
[
event
]);
};
};
this
.
arrowKeys
=
{
LEFT
:
37
,
UP
:
38
,
RIGHT
:
39
,
DOWN
:
40
};
this
.
updatedProblems
=
{};
this
.
updatedProblems
=
{};
this
.
requestToken
=
$
(
element
).
data
(
'request-token'
);
this
.
requestToken
=
$
(
element
).
data
(
'request-token'
);
...
@@ -52,6 +58,7 @@
...
@@ -52,6 +58,7 @@
this
.
nextUrl
=
this
.
el
.
data
(
'next-url'
);
this
.
nextUrl
=
this
.
el
.
data
(
'next-url'
);
this
.
prevUrl
=
this
.
el
.
data
(
'prev-url'
);
this
.
prevUrl
=
this
.
el
.
data
(
'prev-url'
);
this
.
base_page_title
=
' | '
+
document
.
title
;
this
.
base_page_title
=
' | '
+
document
.
title
;
this
.
keydownHandler
(
$
(
element
).
find
(
'#sequence-list .tab'
));
this
.
bind
();
this
.
bind
();
this
.
render
(
parseInt
(
this
.
el
.
data
(
'position'
),
10
));
this
.
render
(
parseInt
(
this
.
el
.
data
(
'position'
),
10
));
}
}
...
@@ -62,12 +69,63 @@
...
@@ -62,12 +69,63 @@
Sequence
.
prototype
.
bind
=
function
()
{
Sequence
.
prototype
.
bind
=
function
()
{
this
.
$
(
'#sequence-list .nav-item'
).
click
(
this
.
goto
);
this
.
$
(
'#sequence-list .nav-item'
).
click
(
this
.
goto
);
this
.
$
(
'#sequence-list .nav-item'
).
keypress
(
this
.
keyDownHandler
);
this
.
el
.
on
(
'bookmark:add'
,
this
.
addBookmarkIconToActiveNavItem
);
this
.
el
.
on
(
'bookmark:add'
,
this
.
addBookmarkIconToActiveNavItem
);
this
.
el
.
on
(
'bookmark:remove'
,
this
.
removeBookmarkIconFromActiveNavItem
);
this
.
el
.
on
(
'bookmark:remove'
,
this
.
removeBookmarkIconFromActiveNavItem
);
this
.
$
(
'#sequence-list .nav-item'
).
on
(
'focus mouseenter'
,
this
.
displayTabTooltip
);
this
.
$
(
'#sequence-list .nav-item'
).
on
(
'focus mouseenter'
,
this
.
displayTabTooltip
);
this
.
$
(
'#sequence-list .nav-item'
).
on
(
'blur mouseleave'
,
this
.
hideTabTooltip
);
this
.
$
(
'#sequence-list .nav-item'
).
on
(
'blur mouseleave'
,
this
.
hideTabTooltip
);
};
};
Sequence
.
prototype
.
previousNav
=
function
(
focused
,
index
)
{
var
$navItemList
,
$sequenceList
=
$
(
focused
).
parent
().
parent
();
if
(
index
===
0
)
{
$navItemList
=
$sequenceList
.
find
(
'li'
).
last
();
}
else
{
$navItemList
=
$sequenceList
.
find
(
'li:eq('
+
index
+
')'
).
prev
();
}
$sequenceList
.
find
(
'.tab'
).
removeClass
(
'visited'
).
removeClass
(
'focused'
);
$navItemList
.
find
(
'.tab'
).
addClass
(
'focused'
).
focus
();
};
Sequence
.
prototype
.
nextNav
=
function
(
focused
,
index
,
total
)
{
var
$navItemList
,
$sequenceList
=
$
(
focused
).
parent
().
parent
();
if
(
index
===
total
)
{
$navItemList
=
$sequenceList
.
find
(
'li'
).
first
();
}
else
{
$navItemList
=
$sequenceList
.
find
(
'li:eq('
+
index
+
')'
).
next
();
}
$sequenceList
.
find
(
'.tab'
).
removeClass
(
'visited'
).
removeClass
(
'focused'
);
$navItemList
.
find
(
'.tab'
).
addClass
(
'focused'
).
focus
();
};
Sequence
.
prototype
.
keydownHandler
=
function
(
element
)
{
var
self
=
this
;
element
.
keydown
(
function
(
event
)
{
var
key
=
event
.
keyCode
,
$focused
=
$
(
event
.
currentTarget
),
$sequenceList
=
$focused
.
parent
().
parent
(),
index
=
$sequenceList
.
find
(
'li'
)
.
index
(
$focused
.
parent
()),
total
=
$sequenceList
.
find
(
'li'
)
.
size
()
-
1
;
switch
(
key
)
{
case
self
.
arrowKeys
.
LEFT
:
event
.
preventDefault
();
self
.
previousNav
(
$focused
,
index
);
break
;
case
self
.
arrowKeys
.
RIGHT
:
event
.
preventDefault
();
self
.
nextNav
(
$focused
,
index
,
total
);
break
;
// no default
}
});
};
Sequence
.
prototype
.
displayTabTooltip
=
function
(
event
)
{
Sequence
.
prototype
.
displayTabTooltip
=
function
(
event
)
{
$
(
event
.
currentTarget
).
find
(
'.sequence-tooltip'
).
removeClass
(
'sr'
);
$
(
event
.
currentTarget
).
find
(
'.sequence-tooltip'
).
removeClass
(
'sr'
);
};
};
...
@@ -317,13 +375,22 @@
...
@@ -317,13 +375,22 @@
Sequence
.
prototype
.
mark_visited
=
function
(
position
)
{
Sequence
.
prototype
.
mark_visited
=
function
(
position
)
{
// Don't overwrite class attribute to avoid changing Progress class
// Don't overwrite class attribute to avoid changing Progress class
var
element
=
this
.
link_for
(
position
);
var
element
=
this
.
link_for
(
position
);
element
.
removeClass
(
'inactive'
).
removeClass
(
'active'
).
addClass
(
'visited'
);
element
.
attr
({
tabindex
:
'-1'
,
'aria-selected'
:
'false'
,
'aria-expanded'
:
'false'
})
.
removeClass
(
'inactive'
)
.
removeClass
(
'active'
)
.
removeClass
(
'focused'
)
.
addClass
(
'visited'
);
};
};
Sequence
.
prototype
.
mark_active
=
function
(
position
)
{
Sequence
.
prototype
.
mark_active
=
function
(
position
)
{
// Don't overwrite class attribute to avoid changing Progress class
// Don't overwrite class attribute to avoid changing Progress class
var
element
=
this
.
link_for
(
position
);
var
element
=
this
.
link_for
(
position
);
element
.
removeClass
(
'inactive'
).
removeClass
(
'visited'
).
addClass
(
'active'
);
element
.
attr
({
tabindex
:
'0'
,
'aria-selected'
:
'true'
,
'aria-expanded'
:
'true'
})
.
removeClass
(
'inactive'
)
.
removeClass
(
'visited'
)
.
removeClass
(
'focused'
)
.
addClass
(
'active'
);
this
.
$
(
'.sequence-list-wrapper'
).
focus
();
};
};
Sequence
.
prototype
.
addBookmarkIconToActiveNavItem
=
function
(
event
)
{
Sequence
.
prototype
.
addBookmarkIconToActiveNavItem
=
function
(
event
)
{
...
...
lms/djangoapps/courseware/tests/test_split_module.py
View file @
88e10e0e
...
@@ -125,7 +125,7 @@ class SplitTestBase(SharedModuleStoreTestCase):
...
@@ -125,7 +125,7 @@ class SplitTestBase(SharedModuleStoreTestCase):
content
=
resp
.
content
content
=
resp
.
content
# Assert we see the proper icon in the top display
# Assert we see the proper icon in the top display
self
.
assertIn
(
'<button class="{} inactive nav-item"'
.
format
(
self
.
ICON_CLASSES
[
user_tag
]),
content
)
self
.
assertIn
(
'<button class="{} inactive nav-item
tab
"'
.
format
(
self
.
ICON_CLASSES
[
user_tag
]),
content
)
# And proper tooltips
# And proper tooltips
for
tooltip
in
self
.
TOOLTIPS
[
user_tag
]:
for
tooltip
in
self
.
TOOLTIPS
[
user_tag
]:
self
.
assertIn
(
tooltip
,
content
)
self
.
assertIn
(
tooltip
,
content
)
...
...
lms/static/lms/js/spec/main.js
View file @
88e10e0e
...
@@ -64,6 +64,7 @@
...
@@ -64,6 +64,7 @@
'xblock/lms.runtime.v1'
:
'lms/js/xblock/lms.runtime.v1'
,
'xblock/lms.runtime.v1'
:
'lms/js/xblock/lms.runtime.v1'
,
'xblock'
:
'common/js/xblock'
,
'xblock'
:
'common/js/xblock'
,
'capa/display'
:
'xmodule_js/src/capa/display'
,
'capa/display'
:
'xmodule_js/src/capa/display'
,
'sequence/display'
:
'xmodule_js/src/sequence/display'
,
'string_utils'
:
'xmodule_js/common_static/js/src/string_utils'
,
'string_utils'
:
'xmodule_js/common_static/js/src/string_utils'
,
'logger'
:
'xmodule_js/common_static/js/src/logger'
,
'logger'
:
'xmodule_js/common_static/js/src/logger'
,
'Markdown.Converter'
:
'js/Markdown.Converter'
,
'Markdown.Converter'
:
'js/Markdown.Converter'
,
...
...
lms/templates/seq_module.html
View file @
88e10e0e
...
@@ -17,16 +17,22 @@
...
@@ -17,16 +17,22 @@
<span
class=
"icon fa fa-chevron-prev"
aria-hidden=
"true"
></span>
<span
class=
"icon fa fa-chevron-prev"
aria-hidden=
"true"
></span>
<span>
${_('Previous')}
</span>
<span>
${_('Previous')}
</span>
</button>
</button>
<nav
class=
"sequence-list-wrapper"
aria-label=
"${_('
Unit
')}"
>
<nav
class=
"sequence-list-wrapper"
aria-label=
"${_('
Sequence
')}"
>
<ol
id=
"sequence-list"
>
<ol
id=
"sequence-list"
role=
"tablist"
>
% for idx, item in enumerate(items):
% for idx, item in enumerate(items):
<li>
<li>
<button
class=
"seq_${item['type']} inactive nav-item"
<button
class=
"seq_${item['type']} inactive nav-item tab"
data-id=
"${item['id']}"
role=
"tab"
data-element=
"${idx+1}"
tabindex=
"-1"
data-page-title=
"${item['page_title']}"
aria-selected=
"false"
data-path=
"${item['path']}"
aria-expanded=
"false"
id=
"tab_${idx}"
>
aria-controls=
"seq_content"
data-index=
"${idx}"
data-id=
"${item['id']}"
data-element=
"${idx+1}"
data-page-title=
"${item['page_title']}"
data-path=
"${item['path']}"
id=
"tab_${idx}"
>
<span
class=
"icon fa seq_${item['type']}"
aria-hidden=
"true"
></span>
<span
class=
"icon fa seq_${item['type']}"
aria-hidden=
"true"
></span>
<span
class=
"fa fa-fw fa-bookmark bookmark-icon ${"
is-hidden
"
if
not
item
['
bookmarked
']
else
"
bookmarked
"}"
aria-hidden=
"true"
></span>
<span
class=
"fa fa-fw fa-bookmark bookmark-icon ${"
is-hidden
"
if
not
item
['
bookmarked
']
else
"
bookmarked
"}"
aria-hidden=
"true"
></span>
<div
class=
"sequence-tooltip sr"
><span
class=
"sr"
>
${item['type']}
</span>
${item['page_title']}
<span
class=
"sr bookmark-icon-sr"
>
${_("Bookmarked") if item['bookmarked'] else ""}
</span></div>
<div
class=
"sequence-tooltip sr"
><span
class=
"sr"
>
${item['type']}
</span>
${item['page_title']}
<span
class=
"sr bookmark-icon-sr"
>
${_("Bookmarked") if item['bookmarked'] else ""}
</span></div>
...
@@ -51,7 +57,7 @@
...
@@ -51,7 +57,7 @@
${item['content']}
${item['content']}
</div>
</div>
% endfor
% endfor
<div
id=
"seq_content"
></div>
<div
id=
"seq_content"
role=
"tabpanel"
></div>
<nav
class=
"sequence-bottom"
aria-label=
"${_('Section')}"
>
<nav
class=
"sequence-bottom"
aria-label=
"${_('Section')}"
>
<button
class=
"sequence-nav-button button-previous"
>
<button
class=
"sequence-nav-button button-previous"
>
...
...
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