From d227e72aa43cd016774315cc5ebf954145188850 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Wed, 2 Jun 2021 17:59:04 +1000 Subject: [PATCH] MDL-71672 javascript: Fix the issue of focusOnShowSelector being ignored When focusOnShowSelector is not present, as a fallback, focus the first focusable element in YUI dialogues Ref: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role --- ...moodle-core-notification-dialogue-debug.js | 34 +++++++++++-------- .../moodle-core-notification-dialogue-min.js | 4 +-- .../moodle-core-notification-dialogue.js | 34 +++++++++++-------- lib/yui/src/notification/js/dialogue.js | 34 +++++++++++-------- 4 files changed, 62 insertions(+), 44 deletions(-) diff --git a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js index 65516231eea..751d9fc2d60 100644 --- a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js +++ b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js @@ -43,7 +43,12 @@ var DIALOGUE_NAME = 'Moodle dialogue', MENUBAR_SELECTOR = '[role=menubar]', DOT = '.', HAS_ZINDEX = 'moodle-has-zindex', - CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]', + CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]):not([disabled]):not([tabindex^="-"]),' + + 'a[href]:not([disabled]):not([tabindex^="-"]),' + + 'button:not([disabled]):not([tabindex^="-"]),' + + 'textarea:not([disabled]):not([tabindex^="-"]),' + + 'select:not([disabled]):not([tabindex^="-"]),' + + '[tabindex]:not([disabled]):not([tabindex^="-"])', FORM_SELECTOR = 'form'; /** @@ -316,10 +321,6 @@ Y.extend(DIALOGUE, Y.Panel, { Y.one(titlebar).setStyle('cursor', 'move'); } } - require(['core/local/aria/focuslock'], function(FocusLockManager) { - // Trap focus to the current bounding box. - FocusLockManager.trapFocus(this.get('boundingBox').getDOMNode()); - }.bind(this)); // Only do accessibility hiding for modals because the ARIA spec // says that all ARIA dialogues should be modal. @@ -410,9 +411,12 @@ Y.extend(DIALOGUE, Y.Panel, { Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth'); }, + _focus: function() { + this.focus(); + }, + show: function() { var result = null, - header = this.headerNode, content = this.bodyNode, focusSelector = this.get('focusOnShowSelector'), focusNode = null; @@ -429,16 +433,18 @@ Y.extend(DIALOGUE, Y.Panel, { focusNode = this.get('boundingBox').one(focusSelector); } if (!focusNode) { - // Fall back to the header or the content if no focus node was found yet. - if (header && header !== '') { - focusNode = header; - } else if (content && content !== '') { - focusNode = content; + // Fall back to the first focusable element in the body of the dialogue if no focus node was found yet. + if (content && content !== '') { + focusNode = content.one(CAN_RECEIVE_FOCUS_SELECTOR); } } - if (focusNode) { - focusNode.focus(); - } + require(['core/local/aria/focuslock'], function(FocusLockManager) { + // Trap focus to the current bounding box. + FocusLockManager.trapFocus(this.get('boundingBox').getDOMNode()); + if (focusNode) { + focusNode.focus(); + } + }.bind(this)); return result; }, diff --git a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js index 56cfc98f8fa..4a2bcf5ca20 100644 --- a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js +++ b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js @@ -1,2 +1,2 @@ -YUI.add("moodle-core-notification-dialogue",function(n,e){var t,a,i,s,l,d,r,u,h,o,c,g="moodle-dialogue",f="notificationBase",v={BASE:"moodle-dialogue-base",WRAP:"moodle-dialogue-wrap",HEADER:"moodle-dialogue-hd",BODY:"moodle-dialogue-bd",CONTENT:"moodle-dialogue-content",FOOTER:"moodle-dialogue-ft",HIDDEN:"hidden",LIGHTBOX:"moodle-dialogue-lightbox"};M.core=M.core||{},t="Moodle dialogue",i=g+"-fullscreen",s=g+"-hidden",l=" [role=dialog]",d="[role=menubar]",r=".",u="moodle-has-zindex",h='input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]',o="form",a=function(e){var t="moodle-dialogue-"+n.stamp(this)+"-wrap";e.notificationBase=n.Node.create('
').append(n.Node.create('').append(n.Node.create('
')).append(n.Node.create('
')).append(n.Node.create('
'))),n.one(document.body).append(e.notificationBase),e.srcNode="#"+t,delete e.buttons,a.superclass.constructor.apply(this,[e])},n.extend(a,n.Panel,{_resizeevent:null,_orientationevent:null,_calculatedzindex:!1,_currentMaskNodeId:null,_originalPosition:null,_hiddenSiblings:null,hideIfNotForm:function(){null===this.get("boundingBox").one(o)&&this.hide()},initializer:function(){var e,t,i,o;!1!==this.get("closeButton")&&(t=this.get("closeButtonTitle"),this.get("buttons").header[0].setAttribute("title",t),this.get("buttons").header[0].setAttribute("aria-label",t)),this._hiddenSiblings=[],this.get("render")&&this.render(),this.after("visibleChange",this.visibilityChanged,this),this.get("center")&&this.centerDialogue(),this.get("modal")&&(this.get(f).set("aria-hidden","true"),this.plug(n.M.core.LockScroll)),this.set("focusOn",n.Array(this.get("focusOn")).filter(function(e){return"focusoutside"!==e.eventName})),(e=this.get("boundingBox")).addClass(u),n.Array.each(this.get("extraClasses"),e.addClass,e),this.get("visible")&&this.applyZIndex(),this.on("maskShow",this.applyZIndex),this.on("maskShow",function(){var e,t=n.one(n.config.win),i=this.get("boundingBox");this.get("center")||(this._originalPosition=i.getXY()),e=this.get("maskNode"),this._currentMaskNodeId!==e.get("_yuid")&&(this._currentMaskNodeId=e.get("_yuid"),e.on("click",this.hideIfNotForm,this)),"fixed"!==i.getStyle("position")&&i.setStyles({top:t.get("scrollTop"),left:t.get("scrollLeft")})},this),i=this.get("notificationBase"),""!==(o=this.get("additionalBaseClass"))&&i.addClass(o),this.after("destroyedChange",function(){this.get(f).remove(!0)},this)},applyZIndex:function(){var i=1040,e=1,t=this.get("boundingBox"),o=this.get("maskNode"),s=this.get("zIndex");0===s||this._calculatedzindex?(n.all(l+", "+d+", "+r+u).each(function(e){var t=this.findZIndex(e);i').append(s.Node.create('').append(s.Node.create('
')).append(s.Node.create('
')).append(s.Node.create('
'))),s.one(document.body).append(e.notificationBase),e.srcNode="#"+t,delete e.buttons,n.superclass.constructor.apply(this,[e])},s.extend(n,s.Panel,{_resizeevent:null,_orientationevent:null,_calculatedzindex:!1,_currentMaskNodeId:null,_originalPosition:null,_hiddenSiblings:null,hideIfNotForm:function(){null===this.get("boundingBox").one(o)&&this.hide()},initializer:function(){var e,t,i,o;!1!==this.get("closeButton")&&(t=this.get("closeButtonTitle"),this.get("buttons").header[0].setAttribute("title",t),this.get("buttons").header[0].setAttribute("aria-label",t)),this._hiddenSiblings=[],this.get("render")&&this.render(),this.after("visibleChange",this.visibilityChanged,this),this.get("center")&&this.centerDialogue(),this.get("modal")&&(this.get(f).set("aria-hidden","true"),this.plug(s.M.core.LockScroll)),this.set("focusOn",s.Array(this.get("focusOn")).filter(function(e){return"focusoutside"!==e.eventName})),(e=this.get("boundingBox")).addClass(u),s.Array.each(this.get("extraClasses"),e.addClass,e),this.get("visible")&&this.applyZIndex(),this.on("maskShow",this.applyZIndex),this.on("maskShow",function(){var e,t=s.one(s.config.win),i=this.get("boundingBox");this.get("center")||(this._originalPosition=i.getXY()),e=this.get("maskNode"),this._currentMaskNodeId!==e.get("_yuid")&&(this._currentMaskNodeId=e.get("_yuid"),e.on("click",this.hideIfNotForm,this)),"fixed"!==i.getStyle("position")&&i.setStyles({top:t.get("scrollTop"),left:t.get("scrollLeft")})},this),i=this.get("notificationBase"),""!==(o=this.get("additionalBaseClass"))&&i.addClass(o),this.after("destroyedChange",function(){this.get(f).remove(!0)},this)},applyZIndex:function(){var i=1040,e=1,t=this.get("boundingBox"),o=this.get("maskNode"),n=this.get("zIndex");0===n||this._calculatedzindex?(s.all(l+", "+d+", "+r+u).each(function(e){var t=this.findZIndex(e);i