DIALOGUE_FULLSCREEN_CLASS = DIALOGUE_PREFIX + '-fullscreen',
DIALOGUE_HIDDEN_CLASS = DIALOGUE_PREFIX + '-hidden',
DIALOGUE_SELECTOR =' [role=dialog]',
- MENUBAR_SELECTOR = '[role=menubar]';
+ MENUBAR_SELECTOR = '[role=menubar]',
+ CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]';
/**
* A re-usable dialogue box with Moodle classes applied.
// been positioned it will scroll back to the top of the page.
if (config.visible) {
this.show();
+ this.keyDelegation();
}
},
* @return void
*/
visibilityChanged : function(e) {
- var titlebar;
+ var titlebar, bb;
if (e.attrName === 'visible') {
this.get('maskNode').addClass(CSS.LIGHTBOX);
if (e.prevVal && !e.newVal) {
+ bb = this.get('boundingBox');
if (this._resizeevent) {
this._resizeevent.detach();
this._resizeevent = null;
this._orientationevent.detach();
this._orientationevent = null;
}
+ bb.detach('key', this.keyDelegation);
}
if (!e.prevVal && e.newVal) {
// This needs to be done each time the dialog is shown as new dialogs may have been opened.
Y.one(titlebar).setStyle('cursor', 'move');
}
}
+ this.keyDelegation();
}
if (this.get('center') && !e.prevVal && e.newVal) {
this.centerDialogue();
content.focus();
}
return result;
+ },
+ /**
+ * Setup key delegation to keep tabbing within the open dialogue.
+ *
+ * @method keyDelegation
+ */
+ keyDelegation : function() {
+ var bb = this.get('boundingBox');
+ bb.delegate('key', function(e){
+ var target = e.target;
+ var direction = 'forward';
+ if (e.shiftKey) {
+ direction = 'backward';
+ }
+ if (this.trapFocus(target, direction)) {
+ e.preventDefault();
+ }
+ }, 'down:9', CAN_RECEIVE_FOCUS_SELECTOR, this);
+ },
+ /**
+ * Trap the tab focus within the open modal.
+ *
+ * @param string target the element target
+ * @param string direction tab key for forward and tab+shift for backward
+ * @returns bool
+ */
+ trapFocus : function(target, direction) {
+ var bb = this.get('boundingBox'),
+ firstitem = bb.one(CAN_RECEIVE_FOCUS_SELECTOR),
+ lastitem = bb.all(CAN_RECEIVE_FOCUS_SELECTOR).pop();
+
+ if (target === lastitem && direction === 'forward') { // Tab key.
+ return firstitem.focus();
+ } else if (target === firstitem && direction === 'backward') { // Tab+shift key.
+ return lastitem.focus();
+ }
}
}, {
NAME : DIALOGUE_NAME,