Merge pull request #1468 from edx/diana/navigation-skip-links
Add skip links to both CMS and LMS
This commit is contained in:
@@ -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.
|
||||
|
||||
Common: Add skip links for accessibility to CMS and LMS (LMS-1311)
|
||||
|
||||
Studio: Change course overview page, checklists, assets, and course staff management
|
||||
page URLs to a RESTful interface. Also removed "\listing", which duplicated
|
||||
"\index".
|
||||
|
||||
@@ -30,6 +30,7 @@ requirejs.config({
|
||||
"xmodule": "xmodule_js/src/xmodule",
|
||||
"xblock": "xmodule_js/common_static/coffee/src/xblock",
|
||||
"utility": "xmodule_js/common_static/js/src/utility",
|
||||
"accessibility": "xmodule_js/common_static/js/src/accessibility_tools",
|
||||
"sinon": "xmodule_js/common_static/js/vendor/sinon-1.7.1",
|
||||
"squire": "xmodule_js/common_static/js/vendor/Squire",
|
||||
"jasmine-jquery": "xmodule_js/common_static/js/vendor/jasmine-jquery",
|
||||
|
||||
@@ -826,10 +826,32 @@ hr.divide {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
// ui - semantic + visual divider
|
||||
hr.divider {
|
||||
@extend %cont-text-sr;
|
||||
}
|
||||
|
||||
// ui - skipnav
|
||||
.nav-skip {
|
||||
@include font-size(13);
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: -($baseline*30);
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
background: $white;
|
||||
border-bottom: 1px solid $gray-l4;
|
||||
padding: ($baseline*0.75) ($baseline/2);
|
||||
|
||||
&:focus, &:active {
|
||||
position: static;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================
|
||||
|
||||
// js dependant
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
|
||||
<!doctype html>
|
||||
@@ -29,211 +30,209 @@
|
||||
</head>
|
||||
|
||||
<body class="<%block name='bodyclass'></%block> hide-wip">
|
||||
<script type="text/javascript">
|
||||
window.baseUrl = "${settings.STATIC_URL}";
|
||||
var require = {
|
||||
baseUrl: baseUrl,
|
||||
waitSeconds: 60,
|
||||
paths: {
|
||||
"domReady": "js/vendor/domReady",
|
||||
"gettext": "/i18n",
|
||||
"mustache": "js/vendor/mustache",
|
||||
"codemirror": "js/vendor/codemirror-compressed",
|
||||
"codemirror/stex": "js/vendor/CodeMirror/stex",
|
||||
"jquery": "js/vendor/jquery.min",
|
||||
"jquery.ui": "js/vendor/jquery-ui.min",
|
||||
"jquery.form": "js/vendor/jquery.form",
|
||||
"jquery.markitup": "js/vendor/markitup/jquery.markitup",
|
||||
"jquery.leanModal": "js/vendor/jquery.leanModal.min",
|
||||
"jquery.ajaxQueue": "js/vendor/jquery.ajaxQueue",
|
||||
"jquery.smoothScroll": "js/vendor/jquery.smooth-scroll.min",
|
||||
"jquery.timepicker": "js/vendor/timepicker/jquery.timepicker",
|
||||
"jquery.cookie": "js/vendor/jquery.cookie",
|
||||
"jquery.qtip": "js/vendor/jquery.qtip.min",
|
||||
"jquery.scrollTo": "js/vendor/jquery.scrollTo-1.4.2-min",
|
||||
"jquery.flot": "js/vendor/flot/jquery.flot.min",
|
||||
"jquery.maskedinput": "js/vendor/jquery.maskedinput.min",
|
||||
"jquery.fileupload": "js/vendor/jQuery-File-Upload/js/jquery.fileupload",
|
||||
"jquery.iframe-transport": "js/vendor/jQuery-File-Upload/js/jquery.iframe-transport",
|
||||
"jquery.inputnumber": "js/vendor/html5-input-polyfills/number-polyfill",
|
||||
"jquery.immediateDescendents": "coffee/src/jquery.immediateDescendents",
|
||||
"datepair": "js/vendor/timepicker/datepair",
|
||||
"date": "js/vendor/date",
|
||||
"tzAbbr": "js/vendor/tzAbbr",
|
||||
"underscore": "js/vendor/underscore-min",
|
||||
"underscore.string": "js/vendor/underscore.string.min",
|
||||
"backbone": "js/vendor/backbone-min",
|
||||
"backbone.associations": "js/vendor/backbone-associations-min",
|
||||
"tinymce": "js/vendor/tiny_mce/tiny_mce",
|
||||
"jquery.tinymce": "js/vendor/tiny_mce/jquery.tinymce",
|
||||
"xmodule": "/xmodule/xmodule",
|
||||
"xblock": "coffee/src/xblock",
|
||||
"utility": "js/src/utility",
|
||||
"draggabilly": "js/vendor/draggabilly.pkgd",
|
||||
<a class="nav-skip" href="#content">${_("Skip to this view's content")}</a>
|
||||
|
||||
// externally hosted files
|
||||
"tender": "//edxedge.tenderapp.com/tender_widget",
|
||||
"mathjax": "//edx-static.s3.amazonaws.com/mathjax-MathJax-727332c/MathJax.js?config=TeX-MML-AM_HTMLorMML-full&delayStartupUntil=configured",
|
||||
// youtube URL does not end in ".js". We add "?noext" to the path so
|
||||
// that require.js adds the ".js" to the query component of the URL,
|
||||
// and leaves the path component intact.
|
||||
"youtube": "//www.youtube.com/player_api?noext"
|
||||
},
|
||||
shim: {
|
||||
"gettext": {
|
||||
exports: "gettext"
|
||||
<script type="text/javascript">
|
||||
window.baseUrl = "${settings.STATIC_URL}";
|
||||
var require = {
|
||||
baseUrl: baseUrl,
|
||||
waitSeconds: 60,
|
||||
paths: {
|
||||
"domReady": "js/vendor/domReady",
|
||||
"gettext": "/i18n",
|
||||
"mustache": "js/vendor/mustache",
|
||||
"codemirror": "js/vendor/codemirror-compressed",
|
||||
"codemirror/stex": "js/vendor/CodeMirror/stex",
|
||||
"jquery": "js/vendor/jquery.min",
|
||||
"jquery.ui": "js/vendor/jquery-ui.min",
|
||||
"jquery.form": "js/vendor/jquery.form",
|
||||
"jquery.markitup": "js/vendor/markitup/jquery.markitup",
|
||||
"jquery.leanModal": "js/vendor/jquery.leanModal.min",
|
||||
"jquery.ajaxQueue": "js/vendor/jquery.ajaxQueue",
|
||||
"jquery.smoothScroll": "js/vendor/jquery.smooth-scroll.min",
|
||||
"jquery.timepicker": "js/vendor/timepicker/jquery.timepicker",
|
||||
"jquery.cookie": "js/vendor/jquery.cookie",
|
||||
"jquery.qtip": "js/vendor/jquery.qtip.min",
|
||||
"jquery.scrollTo": "js/vendor/jquery.scrollTo-1.4.2-min",
|
||||
"jquery.flot": "js/vendor/flot/jquery.flot.min",
|
||||
"jquery.fileupload": "js/vendor/jQuery-File-Upload/js/jquery.fileupload",
|
||||
"jquery.iframe-transport": "js/vendor/jQuery-File-Upload/js/jquery.iframe-transport",
|
||||
"jquery.inputnumber": "js/vendor/html5-input-polyfills/number-polyfill",
|
||||
"jquery.immediateDescendents": "coffee/src/jquery.immediateDescendents",
|
||||
"datepair": "js/vendor/timepicker/datepair",
|
||||
"date": "js/vendor/date",
|
||||
"tzAbbr": "js/vendor/tzAbbr",
|
||||
"underscore": "js/vendor/underscore-min",
|
||||
"underscore.string": "js/vendor/underscore.string.min",
|
||||
"backbone": "js/vendor/backbone-min",
|
||||
"backbone.associations": "js/vendor/backbone-associations-min",
|
||||
"tinymce": "js/vendor/tiny_mce/tiny_mce",
|
||||
"jquery.tinymce": "js/vendor/tiny_mce/jquery.tinymce",
|
||||
"xmodule": "/xmodule/xmodule",
|
||||
"xblock": "coffee/src/xblock",
|
||||
"utility": "js/src/utility",
|
||||
"accessibility": "js/src/accessibility_tools",
|
||||
"draggabilly": "js/vendor/draggabilly.pkgd",
|
||||
|
||||
// externally hosted files
|
||||
"tender": "//edxedge.tenderapp.com/tender_widget",
|
||||
"mathjax": "//edx-static.s3.amazonaws.com/mathjax-MathJax-727332c/MathJax.js?config=TeX-MML-AM_HTMLorMML-full&delayStartupUntil=configured",
|
||||
// youtube URL does not end in ".js". We add "?noext" to the path so
|
||||
// that require.js adds the ".js" to the query component of the URL,
|
||||
// and leaves the path component intact.
|
||||
"youtube": "//www.youtube.com/player_api?noext"
|
||||
},
|
||||
"date": {
|
||||
exports: "Date"
|
||||
},
|
||||
"jquery.ui": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.ui"
|
||||
},
|
||||
"jquery.form": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.ajaxForm"
|
||||
},
|
||||
"jquery.markitup": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.markitup"
|
||||
},
|
||||
"jquery.leanmodal": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.leanModal"
|
||||
},
|
||||
"jquery.ajaxQueue": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.ajaxQueue"
|
||||
},
|
||||
"jquery.smoothScroll": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.smoothScroll"
|
||||
},
|
||||
"jquery.cookie": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.cookie"
|
||||
},
|
||||
"jquery.qtip": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.qtip"
|
||||
},
|
||||
"jquery.scrollTo": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.scrollTo",
|
||||
},
|
||||
"jquery.flot": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.plot"
|
||||
},
|
||||
"jquery.maskedinput": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.mask"
|
||||
},
|
||||
"jquery.fileupload": {
|
||||
deps: ["jquery.iframe-transport"],
|
||||
exports: "jQuery.fn.fileupload"
|
||||
},
|
||||
"jquery.inputnumber": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.inputNumber"
|
||||
},
|
||||
"jquery.tinymce": {
|
||||
deps: ["jquery", "tinymce"],
|
||||
exports: "jQuery.fn.tinymce"
|
||||
},
|
||||
"datepair": {
|
||||
deps: ["jquery.ui", "jquery.timepicker"]
|
||||
},
|
||||
"underscore": {
|
||||
exports: "_"
|
||||
},
|
||||
"backbone": {
|
||||
deps: ["underscore", "jquery"],
|
||||
exports: "Backbone"
|
||||
},
|
||||
"backbone.associations": {
|
||||
deps: ["backbone"],
|
||||
exports: "Backbone.Associations"
|
||||
},
|
||||
"youtube": {
|
||||
exports: "YT"
|
||||
},
|
||||
"codemirror": {
|
||||
exports: "CodeMirror"
|
||||
},
|
||||
"codemirror/stex": {
|
||||
deps: ["codemirror"]
|
||||
},
|
||||
"tinymce": {
|
||||
exports: "tinymce"
|
||||
},
|
||||
"mathjax": {
|
||||
exports: "MathJax",
|
||||
init: function() {
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [
|
||||
["\\(","\\)"],
|
||||
['[mathjaxinline]','[/mathjaxinline]']
|
||||
],
|
||||
displayMath: [
|
||||
["\\[","\\]"],
|
||||
['[mathjax]','[/mathjax]']
|
||||
]
|
||||
shim: {
|
||||
"gettext": {
|
||||
exports: "gettext"
|
||||
},
|
||||
"date": {
|
||||
exports: "Date"
|
||||
},
|
||||
"jquery.ui": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.ui"
|
||||
},
|
||||
"jquery.form": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.ajaxForm"
|
||||
},
|
||||
"jquery.markitup": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.markitup"
|
||||
},
|
||||
"jquery.leanmodal": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.leanModal"
|
||||
},
|
||||
"jquery.ajaxQueue": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.ajaxQueue"
|
||||
},
|
||||
"jquery.smoothScroll": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.smoothScroll"
|
||||
},
|
||||
"jquery.cookie": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.cookie"
|
||||
},
|
||||
"jquery.qtip": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.qtip"
|
||||
},
|
||||
"jquery.scrollTo": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.scrollTo",
|
||||
},
|
||||
"jquery.flot": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.plot"
|
||||
},
|
||||
"jquery.fileupload": {
|
||||
deps: ["jquery.iframe-transport"],
|
||||
exports: "jQuery.fn.fileupload"
|
||||
},
|
||||
"jquery.inputnumber": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.inputNumber"
|
||||
},
|
||||
"jquery.tinymce": {
|
||||
deps: ["jquery", "tinymce"],
|
||||
exports: "jQuery.fn.tinymce"
|
||||
},
|
||||
"datepair": {
|
||||
deps: ["jquery.ui", "jquery.timepicker"]
|
||||
},
|
||||
"underscore": {
|
||||
exports: "_"
|
||||
},
|
||||
"backbone": {
|
||||
deps: ["underscore", "jquery"],
|
||||
exports: "Backbone"
|
||||
},
|
||||
"backbone.associations": {
|
||||
deps: ["backbone"],
|
||||
exports: "Backbone.Associations"
|
||||
},
|
||||
"youtube": {
|
||||
exports: "YT"
|
||||
},
|
||||
"codemirror": {
|
||||
exports: "CodeMirror"
|
||||
},
|
||||
"codemirror/stex": {
|
||||
deps: ["codemirror"]
|
||||
},
|
||||
"tinymce": {
|
||||
exports: "tinymce"
|
||||
},
|
||||
"mathjax": {
|
||||
exports: "MathJax",
|
||||
init: function() {
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [
|
||||
["\\(","\\)"],
|
||||
['[mathjaxinline]','[/mathjaxinline]']
|
||||
],
|
||||
displayMath: [
|
||||
["\\[","\\]"],
|
||||
['[mathjax]','[/mathjax]']
|
||||
]
|
||||
}
|
||||
});
|
||||
MathJax.Hub.Configured();
|
||||
}
|
||||
});
|
||||
MathJax.Hub.Configured();
|
||||
},
|
||||
"xblock/core": {
|
||||
exports: "XBlock",
|
||||
deps: ["jquery", "jquery.immediateDescendents"]
|
||||
},
|
||||
"xblock/runtime.v1": {
|
||||
exports: "XBlock",
|
||||
deps: ["xblock/core"]
|
||||
},
|
||||
|
||||
"coffee/src/main": {
|
||||
deps: ["coffee/src/ajax_prefix"]
|
||||
},
|
||||
"coffee/src/logger": {
|
||||
exports: "Logger",
|
||||
deps: ["coffee/src/ajax_prefix"]
|
||||
}
|
||||
},
|
||||
"xblock/core": {
|
||||
exports: "XBlock",
|
||||
deps: ["jquery", "jquery.immediateDescendents"]
|
||||
},
|
||||
"xblock/runtime.v1": {
|
||||
exports: "XBlock",
|
||||
deps: ["xblock/core"]
|
||||
},
|
||||
|
||||
"coffee/src/main": {
|
||||
deps: ["coffee/src/ajax_prefix"]
|
||||
},
|
||||
"coffee/src/logger": {
|
||||
exports: "Logger",
|
||||
deps: ["coffee/src/ajax_prefix"]
|
||||
// load jquery and gettext automatically
|
||||
deps: ["jquery", "gettext"],
|
||||
callback: function() {
|
||||
// load other scripts on every page, after jquery loads
|
||||
require(["js/base", "coffee/src/main", "coffee/src/logger", "datepair", "accessibility"]);
|
||||
// we need "datepair" because it dynamically modifies the page
|
||||
// when it is loaded -- yuck!
|
||||
}
|
||||
},
|
||||
// load jquery and gettext automatically
|
||||
deps: ["jquery", "gettext"],
|
||||
callback: function() {
|
||||
// load other scripts on every page, after jquery loads
|
||||
require(["js/base", "coffee/src/main", "coffee/src/logger", "datepair"]);
|
||||
// we need "datepair" because it dynamically modifies the page
|
||||
// when it is loaded -- yuck!
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="${static.url("js/vendor/require.js")}"></script>
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="${static.url("js/vendor/require.js")}"></script>
|
||||
|
||||
## js templates
|
||||
<script id="system-feedback-tpl" type="text/template">
|
||||
<%static:include path="js/system-feedback.underscore" />
|
||||
</script>
|
||||
## js templates
|
||||
<script id="system-feedback-tpl" type="text/template">
|
||||
<%static:include path="js/system-feedback.underscore" />
|
||||
</script>
|
||||
|
||||
|
||||
% if context_course:
|
||||
<script type="text/javascript">
|
||||
require(['js/models/course'], function(Course) {
|
||||
window.course = new Course({
|
||||
id: "${context_course.id}",
|
||||
name: "${context_course.display_name_with_default | h}",
|
||||
url_name: "${context_course.location.name | h}",
|
||||
org: "${context_course.location.org | h}",
|
||||
num: "${context_course.location.course | h}",
|
||||
revision: "${context_course.location.revision | h}"
|
||||
<script type="text/javascript">
|
||||
require(['js/models/course'], function(Course) {
|
||||
window.course = new Course({
|
||||
id: "${context_course.id}",
|
||||
name: "${context_course.display_name_with_default | h}",
|
||||
url_name: "${context_course.location.name | h}",
|
||||
org: "${context_course.location.org | h}",
|
||||
num: "${context_course.location.course | h}",
|
||||
revision: "${context_course.location.revision | h}"
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
% endif
|
||||
|
||||
<!-- view -->
|
||||
@@ -242,7 +241,9 @@ require(['js/models/course'], function(Course) {
|
||||
|
||||
<div id="page-alert"></div>
|
||||
|
||||
<div id="content">
|
||||
<%block name="content"></%block>
|
||||
</div>
|
||||
|
||||
% if user.is_authenticated():
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -109,3 +109,23 @@ var accessible_modal = function(trigger, closeButtonId, modalId, mainPageId) {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// NOTE: This is a gross hack to make the skip links work for Webkit browsers
|
||||
// see http://stackoverflow.com/questions/6280399/skip-links-not-working-in-chrome/12720183#12720183
|
||||
|
||||
// handle things properly for clicks
|
||||
$('.nav-skip').click(function() {
|
||||
var href = $(this).attr('href');
|
||||
if(href) {
|
||||
$(href).attr('tabIndex', -1).focus();
|
||||
}
|
||||
});
|
||||
// and for the enter key
|
||||
$('.nav-skip').keypress(function(e) {
|
||||
if(e.which == 13) {
|
||||
var href = $(this).attr('href');
|
||||
if(href) {
|
||||
$(href).attr('tabIndex', -1).focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -69,6 +69,6 @@ spec_paths:
|
||||
# You can access these within JavaScript code
|
||||
# at the URL: document.location.href + "/include/"
|
||||
# plus the path to the file (relative to this YAML file)
|
||||
#fixture_paths:
|
||||
# - path/to/fixture
|
||||
fixture_paths:
|
||||
- js/fixtures
|
||||
|
||||
|
||||
@@ -285,3 +285,23 @@ mark {
|
||||
#feedback_form textarea[name="details"] {
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
// ui - skipnav
|
||||
.nav-skip {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top:- ($baseline*30);
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
background: $white;
|
||||
border-bottom: 1px solid $border-color-4;
|
||||
padding: ($baseline*0.75) ($baseline/2);
|
||||
|
||||
&:focus, &:active {
|
||||
position: static;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,8 @@
|
||||
</head>
|
||||
|
||||
<body class="<%block name='bodyclass'/>">
|
||||
<a class="nav-skip" href="#content">${_("Skip to this view's content")}</a>
|
||||
|
||||
<%include file="mathjax_accessible.html" />
|
||||
|
||||
% if theme_enabled():
|
||||
@@ -86,7 +88,7 @@
|
||||
<%include file="navigation.html" />
|
||||
% endif
|
||||
|
||||
<section class="content-wrapper">
|
||||
<section class="content-wrapper" id="content">
|
||||
${self.body()}
|
||||
<%block name="bodyextra"/>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user