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
298f168e
Commit
298f168e
authored
Jun 14, 2016
by
Chris Rodriguez
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
AC-486 updating tabbed_view to be accessible
parent
7c647e5e
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
129 additions
and
84 deletions
+129
-84
common/static/common/js/components/views/tabbed_view.js
+0
-0
common/static/common/js/spec/components/tabbed_view_spec.js
+92
-66
common/static/common/templates/components/tab.underscore
+1
-1
common/static/common/templates/components/tabbed_view.underscore
+1
-1
common/static/common/templates/components/tabpanel.underscore
+1
-3
common/test/acceptance/tests/lms/test_learner_profile.py
+1
-0
lms/djangoapps/teams/static/teams/js/spec/views/teams_tab_spec.js
+2
-2
lms/djangoapps/teams/static/teams/js/views/teams_tab.js
+2
-2
lms/djangoapps/teams/static/teams/templates/teams.underscore
+1
-1
lms/djangoapps/teams/static/teams/templates/topics.underscore
+1
-1
lms/djangoapps/teams/templates/teams/teams.html
+4
-2
lms/static/sass/elements/_navigation.scss
+23
-5
No files found.
common/static/common/js/components/views/tabbed_view.js
View file @
298f168e
This diff is collapsed.
Click to expand it.
common/static/common/js/spec/components/tabbed_view_spec.js
View file @
298f168e
...
...
@@ -4,9 +4,12 @@
define
([
'jquery'
,
'underscore'
,
'backbone'
,
'common/js/components/views/tabbed_view'
'common/js/components/views/tabbed_view'
,
'jquery.simulate'
],
function
(
$
,
_
,
Backbone
,
TabbedView
)
{
var
keys
=
$
.
simulate
.
keyCode
;
var
view
,
TestSubview
=
Backbone
.
View
.
extend
({
initialize
:
function
(
options
)
{
...
...
@@ -22,7 +25,7 @@
return
view
.
$
(
'.page-content-nav'
);
},
activeTabPanel
=
function
()
{
return
view
.
$
(
'.tabpanel[aria-
expanded="tru
e"]'
);
return
view
.
$
(
'.tabpanel[aria-
hidden="fals
e"]'
);
};
describe
(
'TabbedView component'
,
function
()
{
...
...
@@ -39,21 +42,10 @@
}],
viewLabel
:
'Tabs'
,
}).
render
();
// _.defer() is used to make calls to
// jQuery.focus() work in Chrome. _.defer()
// delays the execution of a function until the
// current call stack is clear. That behavior
// will cause tests to fail, so we'll instead
// make _.defer() immediately invoke its
// argument.
spyOn
(
_
,
'defer'
).
and
.
callFake
(
function
(
func
)
{
func
();
});
});
it
(
'can render itself'
,
function
()
{
expect
(
view
.
$el
.
html
()).
toContain
(
'<
na
v class="page-content-nav"'
);
expect
(
view
.
$el
.
html
()).
toContain
(
'<
di
v class="page-content-nav"'
);
});
it
(
'shows its first tab by default'
,
function
()
{
...
...
@@ -73,66 +65,100 @@
});
it
(
'marks the active tab as selected using aria attributes'
,
function
()
{
expect
(
view
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
(
'aria-expanded'
,
'true'
);
expect
(
view
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
(
'aria-expanded'
,
'false'
);
expect
(
view
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
({
'aria-expanded'
:
'true'
,
'aria-selected'
:
'true'
,
'tabindex'
:
'0'
});
expect
(
view
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
({
'aria-expanded'
:
'false'
,
'aria-selected'
:
'false'
,
'tabindex'
:
'-1'
});
view
.
$
(
'.nav-item[data-index=1]'
).
click
();
expect
(
view
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
(
'aria-expanded'
,
'false'
);
expect
(
view
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
(
'aria-expanded'
,
'true'
);
expect
(
view
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
({
'aria-expanded'
:
'false'
,
'aria-selected'
:
'false'
,
'tabindex'
:
'-1'
});
expect
(
view
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
({
'aria-expanded'
:
'true'
,
'aria-selected'
:
'true'
,
'tabindex'
:
'0'
});
});
it
(
'sets focus for screen readers'
,
function
()
{
spyOn
(
$
.
fn
,
'focus'
);
view
.
$
(
'.nav-item[data-url="test-2"]'
).
click
();
expect
(
view
.
$
(
'.sr-is-focusable.test-2'
).
focus
).
toHaveBeenCalled
();
it
(
'works with keyboard navigation RIGHT and ENTER'
,
function
()
{
view
.
$
(
'.nav-item[data-index=0]'
).
focus
();
view
.
$
(
'.nav-item[data-index=0]'
)
.
simulate
(
"keydown"
,
{
keyCode
:
keys
.
RIGHT
})
.
simulate
(
"keydown"
,
{
keyCode
:
keys
.
ENTER
});
expect
(
view
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
({
'aria-expanded'
:
'false'
,
'aria-selected'
:
'false'
,
'tabindex'
:
'-1'
});
expect
(
view
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
({
'aria-expanded'
:
'true'
,
'aria-selected'
:
'true'
,
'tabindex'
:
'0'
});
});
describe
(
'history'
,
function
()
{
beforeEach
(
function
()
{
spyOn
(
Backbone
.
history
,
'navigate'
).
and
.
callThrough
();
view
=
new
TabbedView
({
tabs
:
[{
url
:
'test 1'
,
title
:
'Test 1'
,
view
:
new
TestSubview
({
text
:
'this is test text'
})
},
{
url
:
'test 2'
,
title
:
'Test 2'
,
view
:
new
TestSubview
({
text
:
'other text'
})
}],
router
:
new
Backbone
.
Router
({
routes
:
{
'test 1'
:
function
()
{
view
.
setActiveTab
(
0
);
},
'test 2'
:
function
()
{
view
.
setActiveTab
(
1
);
}
}
})
}).
render
();
Backbone
.
history
.
start
();
it
(
'works with keyboard navigation DOWN and ENTER'
,
function
()
{
view
.
$
(
'.nav-item[data-index=0]'
).
focus
();
view
.
$
(
'.nav-item[data-index=0]'
)
.
simulate
(
"keydown"
,
{
keyCode
:
keys
.
DOWN
})
.
simulate
(
"keydown"
,
{
keyCode
:
keys
.
ENTER
});
expect
(
view
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
({
'aria-expanded'
:
'false'
,
'aria-selected'
:
'false'
,
'tabindex'
:
'-1'
});
afterEach
(
function
()
{
view
.
router
.
navigate
(
''
);
Backbone
.
history
.
stop
();
expect
(
view
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
({
'aria-expanded'
:
'true'
,
'aria-selected'
:
'true'
,
'tabindex'
:
'0'
});
it
(
'updates the page URL on tab switches without adding to browser history'
,
function
()
{
view
.
$
(
'.nav-item[data-index=1]'
).
click
();
expect
(
Backbone
.
history
.
navigate
).
toHaveBeenCalledWith
(
'test 2'
,
{
replace
:
true
}
);
});
it
(
'works with keyboard navigation LEFT and ENTER'
,
function
()
{
view
.
$
(
'.nav-item[data-index=1]'
).
focus
();
view
.
$
(
'.nav-item[data-index=1]'
)
.
simulate
(
"keydown"
,
{
keyCode
:
keys
.
LEFT
})
.
simulate
(
"keydown"
,
{
keyCode
:
keys
.
ENTER
});
expect
(
view
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
({
'aria-expanded'
:
'false'
,
'aria-selected'
:
'false'
,
'tabindex'
:
'-1'
});
it
(
'changes tabs on URL navigation'
,
function
()
{
expect
(
view
.
$
(
'.nav-item.is-active'
).
data
(
'index'
)).
toEqual
(
0
);
Backbone
.
history
.
navigate
(
'test 2'
,
{
trigger
:
true
});
expect
(
view
.
$
(
'.nav-item.is-active'
).
data
(
'index'
)).
toEqual
(
1
);
expect
(
view
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
({
'aria-expanded'
:
'true'
,
'aria-selected'
:
'true'
,
'tabindex'
:
'0'
});
});
it
(
'works with keyboard navigation UP and ENTER'
,
function
()
{
view
.
$
(
'.nav-item[data-index=1]'
).
focus
();
view
.
$
(
'.nav-item[data-index=1]'
)
.
simulate
(
"keydown"
,
{
keyCode
:
keys
.
UP
})
.
simulate
(
"keydown"
,
{
keyCode
:
keys
.
ENTER
});
expect
(
view
.
$
(
'.nav-item[data-index=1]'
)).
toHaveAttr
({
'aria-expanded'
:
'false'
,
'aria-selected'
:
'false'
,
'tabindex'
:
'-1'
});
expect
(
view
.
$
(
'.nav-item[data-index=0]'
)).
toHaveAttr
({
'aria-expanded'
:
'true'
,
'aria-selected'
:
'true'
,
'tabindex'
:
'0'
});
});
});
});
}).
call
(
this
,
define
||
RequireJS
.
define
);
common/static/common/templates/components/tab.underscore
View file @
298f168e
<button
class="nav-item tab" data-url="<%= url %>" data-index="<%= index %>" is-active="false" aria-expanded="false" aria-controls="<%= tabPanelId
%>"><%= title %></button>
<button
role="tab" class="nav-item tab" data-url="<%= url %>" data-index="<%= index %>" aria-selected="false" aria-expanded="false" aria-controls="<%= tabPanelId %>" tabindex="-1" id="tab-<%= index
%>"><%= title %></button>
common/static/common/templates/components/tabbed_view.underscore
View file @
298f168e
<
nav class="page-content-nav" aria-label="<%- viewLabel %>"></na
v>
<
div class="page-content-nav" role="tablist"></di
v>
<div class="page-content-main">
<div class="tabs"></div>
</div>
common/static/common/templates/components/tabpanel.underscore
View file @
298f168e
<div class="tabpanel is-hidden" id="<%= tabId %>" aria-expanded="false">
<div class="sr-is-focusable <%= tabId %>" tabindex="-1"></div>
</div>
<div role="tabpanel" class="tabpanel is-hidden" id="<%= tabId %>" aria-labelledby="tab-<%= index %>" aria-hidden="true" tabindex="0"></div>
common/test/acceptance/tests/lms/test_learner_profile.py
View file @
298f168e
...
...
@@ -826,6 +826,7 @@ class LearnerProfileA11yTest(LearnerProfileTestMixin, WebAppTest):
"ignore"
:
[
'section'
,
# TODO: AC-491
'link-href'
,
# TODO: AC-231
'color-contrast'
,
# TODO: AC-231
],
})
profile_page
.
display_accomplishments
()
...
...
lms/djangoapps/teams/static/teams/js/spec/views/teams_tab_spec.js
View file @
298f168e
...
...
@@ -71,9 +71,9 @@ define([
expect
(
teamsTabView
.
$
(
'.breadcrumbs'
).
length
).
toBe
(
0
);
});
it
(
'does not interfere with anchor links to #
content'
,
function
()
{
it
(
'does not interfere with anchor links to #
main'
,
function
()
{
var
teamsTabView
=
createTeamsTabView
(
this
);
teamsTabView
.
router
.
navigate
(
'#
content
'
,
{
trigger
:
true
});
teamsTabView
.
router
.
navigate
(
'#
main
'
,
{
trigger
:
true
});
expect
(
teamsTabView
.
$
(
'.wrapper-msg'
)).
toHaveClass
(
'is-hidden'
);
});
...
...
lms/djangoapps/teams/static/teams/js/views/teams_tab.js
View file @
298f168e
...
...
@@ -68,7 +68,7 @@
router
=
this
.
router
=
new
Backbone
.
Router
();
_
.
each
([
[
':default'
,
_
.
bind
(
this
.
routeNotFound
,
this
)],
[
'
content
'
,
_
.
bind
(
function
()
{
[
'
main
'
,
_
.
bind
(
function
()
{
// The backbone router unfortunately usurps the
// default behavior of in-page-links. This hack
// prevents the screen reader in-page-link from
...
...
@@ -580,7 +580,7 @@
/**
* Set up the tabbed view and switch tabs.
*/
goToTab
:
function
(
tab
)
{
goToTab
:
function
(
tab
)
{
this
.
mainView
=
this
.
tabbedView
;
// Note that `render` should be called first so
// that the tabbed view's element is set
...
...
lms/djangoapps/teams/static/teams/templates/teams.underscore
View file @
298f168e
<div class="sr-is-focusable sr-teams-view" tabindex="-1"></div>
<div class="sr-is-focusable sr-teams-view" tabindex="-1"
aria-label="Tab content"
></div>
<div class="teams-paging-header"></div>
<div class="teams-list"></div>
<div class="teams-paging-footer"></div>
lms/djangoapps/teams/static/teams/templates/topics.underscore
View file @
298f168e
<div class="sr-is-focusable sr-topics-view" tabindex="-1"></div>
<div class="sr-is-focusable sr-topics-view" tabindex="-1"
aria-label="Tab content"
></div>
<div class="topics-paging-header"></div>
<div class="topics-list"></div>
<div class="topics-paging-footer"></div>
lms/djangoapps/teams/templates/teams/teams.html
View file @
298f168e
...
...
@@ -22,8 +22,10 @@ from openedx.core.djangolib.js_utils import (
<div
class=
"container"
>
<div
class=
"teams-wrapper"
>
<section
class=
"teams-content"
>
</section>
<main
id=
"main"
aria-label=
"Content"
tabindex=
"-1"
>
<section
class=
"teams-content"
>
</section>
</main>
</div>
</div>
...
...
lms/static/sass/elements/_navigation.scss
View file @
298f168e
...
...
@@ -8,6 +8,7 @@
// +utility navigation
// +toggling utilities
// +case - calculator spacing
// +tabs
// +notes:
// --------------------
...
...
@@ -128,26 +129,43 @@
%page-content-nav
{
margin-bottom
:
$baseline
;
border-bottom
:
3
px
solid
$gray-l5
;
border-bottom
:
1
px
solid
$gray-l5
;
.nav-item
{
@extend
%button-reset
;
display
:
inline-block
;
margin-bottom
:
-3px
;
// to match the border
border-bottom
:
3px
solid
$gray-l5
;
padding
:
(
$baseline
*.
75
);
color
:
$gray-d2
;
&
.is-active
{
border-bottom
:
3px
solid
$gray-d2
;
border-bottom
:
4px
solid
$link-color
;
color
:
$gray-d2
;
}
// STATE: hover and focus
&
:hover
,
&
:focus
{
border-bottom
:
3
px
solid
$link-color
;
border-bottom
:
4
px
solid
$link-color
;
color
:
$link-color
;
}
}
}
// +tabs - styles for tabs and tabpanels (teams and learner profile, currently)
// --------------------
.page-content-nav
{
.tab
{
}
}
.page-content-main
{
.tabs
{
.tabpanel
{
outline
:
none
;
}
}
}
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