Commit 6ab95917 by Tim Krones

Add dialog that provides information about keyboard shortcuts that are

available.

Allow users to bring up the dialog by clicking a link or pressing the
"?" key.
parent 06ce47dd
...@@ -263,7 +263,6 @@ ...@@ -263,7 +263,6 @@
/*** FEEDBACK ***/ /*** FEEDBACK ***/
.xblock--drag-and-drop .feedback { .xblock--drag-and-drop .feedback {
margin-top: 20px;
border-top: solid 1px #bdbdbd; border-top: solid 1px #bdbdbd;
} }
...@@ -301,10 +300,59 @@ ...@@ -301,10 +300,59 @@
font-size: 18pt; font-size: 18pt;
} }
.xblock--drag-and-drop .keyboard-help {
margin-top: 3px;
margin-bottom: 6px;
}
.xblock--drag-and-drop .modal-window-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
opacity: 0.5;
z-index: 1500;
}
.xblock--drag-and-drop .modal-window {
display: none;
position: absolute;
top: 45%;
width: 50%;
box-sizing: border-box;
box-shadow: 0 0 7px rgba(0,0,0,0.4);
border-radius: 4px;
padding: 7px;
background-color: #e5e5e5;
text-align: left;
direction: ltr;
z-index: 1500;
}
.xblock--drag-and-drop .modal-content {
border-radius: 5px;
background: white;
margin-bottom: 5px;
padding: 5px;
}
.xblock--drag-and-drop .modal-content li {
margin-left: 2%;
}
.xblock--drag-and-drop .keyboard-help-button,
.xblock--drag-and-drop .reset-button { .xblock--drag-and-drop .reset-button {
cursor: pointer; cursor: pointer;
float: right;
color: #2d74b3; color: #2d74b3;
}
.xblock--drag-and-drop .reset-button {
float: right;
margin-top: 3px; margin-top: 3px;
} }
......
...@@ -19,10 +19,12 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -19,10 +19,12 @@ function DragAndDropBlock(runtime, element, configuration) {
var SPC = 32; var SPC = 32;
var TAB = 9; var TAB = 9;
var M = 77; var M = 77;
var QUESTION_MARK = 63;
var ctrlDown = false; var ctrlDown = false;
var placementMode = false; var placementMode = false;
var $selectedItem; var $selectedItem;
var $focusedElement;
var init = function() { var init = function() {
// Load the current user state, and load the image, then render the block. // Load the current user state, and load the image, then render the block.
...@@ -35,24 +37,91 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -35,24 +37,91 @@ function DragAndDropBlock(runtime, element, configuration) {
$.ajax(runtime.handlerUrl(element, 'get_user_state'), {dataType: 'json'}), $.ajax(runtime.handlerUrl(element, 'get_user_state'), {dataType: 'json'}),
loadBackgroundImage() loadBackgroundImage()
).done(function(stateResult, bgImg){ ).done(function(stateResult, bgImg){
// Render exercise
configuration.zones.forEach(function (zone) { configuration.zones.forEach(function (zone) {
computeZoneDimension(zone, bgImg.width, bgImg.height); computeZoneDimension(zone, bgImg.width, bgImg.height);
}); });
state = stateResult[0]; // stateResult is an array of [data, statusText, jqXHR] state = stateResult[0]; // stateResult is an array of [data, statusText, jqXHR]
migrateState(bgImg.width, bgImg.height); migrateState(bgImg.width, bgImg.height);
applyState(); applyState();
// Set up event handlers
initDroppable(); initDroppable();
$(document).on('keydown mousedown touchstart', closePopup); $(document).on('keydown mousedown touchstart', closePopup);
$(document).on('keypress', function(evt) {
if (evt.which === QUESTION_MARK) {
showKeyboardHelp(evt);
}
});
$element.on('click', '.keyboard-help-button', showKeyboardHelp);
$element.on('keydown', '.keyboard-help-button', function(evt) {
if (evt.which === RET) {
showKeyboardHelp(evt);
}
});
$element.on('click', '.reset-button', resetExercise); $element.on('click', '.reset-button', resetExercise);
$element.on('click', '.submit-input', submitInput); $element.on('click', '.submit-input', submitInput);
// Indicate that exercise is done loading
publishEvent({event_type: 'xblock.drag-and-drop-v2.loaded'}); publishEvent({event_type: 'xblock.drag-and-drop-v2.loaded'});
}).fail(function() { }).fail(function() {
$root.text(gettext("An error occurred. Unable to load drag and drop exercise.")); $root.text(gettext("An error occurred. Unable to load drag and drop exercise."));
}); });
}; };
var keyboardEventDispatcher = function(evt) {
if (evt.which === TAB) {
trapFocus(evt);
} else if (evt.which === ESC) {
hideKeyboardHelp(evt);
}
};
var trapFocus = function(evt) {
if (evt.which === TAB) {
evt.preventDefault();
focusModalButton();
}
};
var focusModalButton = function() {
$root.find('.keyboard-help-dialog .dismiss-modal-button ').focus();
};
var showKeyboardHelp = function(evt) {
evt.preventDefault();
// Show dialog
var $keyboardHelpDialog = $root.find('.keyboard-help-dialog');
$keyboardHelpDialog.find('.modal-window-overlay').show();
$keyboardHelpDialog.find('.modal-window').show();
// Handle focus
$focusedElement = $(':focus');
focusModalButton();
// Set up event handlers
$(document).on('keydown', keyboardEventDispatcher);
$keyboardHelpDialog.find('.dismiss-modal-button').on('click', hideKeyboardHelp);
};
var hideKeyboardHelp = function(evt) {
evt.preventDefault();
// Hide dialog
var $keyboardHelpDialog = $root.find('.keyboard-help-dialog');
$keyboardHelpDialog.find('.modal-window-overlay').hide();
$keyboardHelpDialog.find('.modal-window').hide();
// Handle focus
$focusedElement.focus();
// Remove event handlers
$(document).off('keydown', keyboardEventDispatcher);
$keyboardHelpDialog.find('.dismiss-modal-button').off();
};
/** Asynchronously load the main background image used for this block. */ /** Asynchronously load the main background image used for this block. */
var loadBackgroundImage = function() { var loadBackgroundImage = function() {
var promise = $.Deferred(); var promise = $.Deferred();
......
...@@ -155,6 +155,35 @@ ...@@ -155,6 +155,35 @@
); );
}; };
var keyboardHelpTemplate = function(ctx) {
var dialog_attributes = { role: 'dialog', 'aria-labelledby': 'modal-window-title' };
var dialog_style = {};
return (
h('div.keyboard-help-dialog', [
h('div.modal-window-overlay'),
h('div.modal-window', { attributes: dialog_attributes, style: dialog_style }, [
h('div.modal-header', [
h('h2.modal-window-title', gettext('Keyboard Help'))
]),
h('div.modal-content', [
h('p', gettext('You can complete this exercise using only your keyboard.')),
h('ul', [
h('li', gettext('Use "Tab" and "Shift-Tab" to navigate between items and zones.')),
h('li', gettext('Press "Enter" or "Space" on an item to select it for dropping, then navigate to the zone you want to drop it on.')),
h('li', gettext('Press "Enter" or "Space" to drop the item on the current zone.')),
h('li', gettext('Press "Escape" if you want to cancel the drop operation (e.g. because you would like to select a different item).')),
h('li', gettext('Press "?" at any time to bring up this dialog.')),
])
]),
h('div.modal-actions', [
h('h3.sr', gettext('Actions')),
h('button.dismiss-modal-button', gettext("OK"))
])
])
])
);
};
var mainTemplate = function(ctx) { var mainTemplate = function(ctx) {
var problemHeader = ctx.show_title ? h('h2.problem-header', {innerHTML: ctx.header_html}) : null; var problemHeader = ctx.show_title ? h('h2.problem-header', {innerHTML: ctx.header_html}) : null;
var questionHeader = ctx.show_question_header ? h('h3.title1', gettext('Question')) : null; var questionHeader = ctx.show_question_header ? h('h3.title1', gettext('Question')) : null;
...@@ -189,6 +218,10 @@ ...@@ -189,6 +218,10 @@
renderCollection(itemTemplate, items_placed, ctx), renderCollection(itemTemplate, items_placed, ctx),
]), ]),
]), ]),
h('section.keyboard-help', [
h('a.keyboard-help-button', { attributes: { tabindex: 0 } }, gettext('Keyboard Help'))
]),
keyboardHelpTemplate(ctx),
feedbackTemplate(ctx), feedbackTemplate(ctx),
]) ])
); );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment