From c34bd1aa46600756c6d4cb34f3d12f76334d7ac4 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Wed, 2 Jun 2021 17:59:04 +1000 Subject: [PATCH 1/6] 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 Date: Wed, 2 Jun 2021 20:11:58 +1000 Subject: [PATCH 2/6] MDL-71672 atto_recordrtc: focus Atto button after hide --- .../moodle-atto_recordrtc-button-debug.js | 16 ++++++++++++---- .../moodle-atto_recordrtc-button-min.js | 2 +- .../moodle-atto_recordrtc-button.js | 16 ++++++++++++---- .../recordrtc/yui/src/button/js/button.js | 16 ++++++++++++---- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-debug.js b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-debug.js index e6fd0f403b2..b13c08e142d 100644 --- a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-debug.js +++ b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-debug.js @@ -184,7 +184,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @private */ _audio: function() { - var dialogue = this.getDialogue(); + var dialogue = this.getDialogue({ + focusAfterHide: 'audio' + }); dialogue.set('headerContent', M.util.get_string('audiortc', 'atto_recordrtc')); dialogue.set('bodyContent', this._createContent('audio')); @@ -201,7 +203,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @private */ _video: function() { - var dialogue = this.getDialogue(); + var dialogue = this.getDialogue({ + focusAfterHide: 'video' + }); dialogue.set('headerContent', M.util.get_string('videortc', 'atto_recordrtc')); dialogue.set('bodyContent', this._createContent('video')); @@ -249,7 +253,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @param {Object} scope The "this" context of the editor. */ closeDialogue: function(scope) { - scope.getDialogue().hide(); + scope.getDialogue().hide({ + focusAfterHide: null + }); scope.editor.focus(); }, @@ -262,7 +268,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @param {string} annotation The HTML link to the recording. */ setLink: function(scope, annotation) { - scope.getDialogue().hide(); + scope.getDialogue().hide({ + focusAfterHide: null + }); scope.editor.focus(); scope.get('host').insertContentAtFocusPoint(annotation); diff --git a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-min.js b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-min.js index 013087c2f2b..b4f3de302f6 100644 --- a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-min.js +++ b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button-min.js @@ -1 +1 @@ -YUI.add("moodle-atto_recordrtc-button",function(s,t){var n="atto_recordrtc";s.namespace("M.atto_recordrtc").Button=s.Base.create("button",s.M.editor_atto.EditorPlugin,[],{_lang:"en",initializer:function(){var t,e,i;if(this.get("host").canShowFilepicker("media")){if(e=!1,"both"!==(t=this.get("allowedtypes"))&&"audio"!==t||(this._addButton("audio",this._audio),e=!0),"both"!==t&&"video"!==t||(this._addButton("video",this._video),e=!0),!e)return;(i=this.getDialogue({width:1e3,focusAfterHide:null})).after("visibleChange",function(){var t=!i.get("visible"),e=M.atto_recordrtc.commonmodule;t&&(window.clearInterval(e.countdownTicker),e.mediaRecorder&&"inactive"!==e.mediaRecorder.state&&e.mediaRecorder.stop(),e.stream&&e.stream.getTracks().forEach(function(t){"ended"!==t.readyState&&t.stop()}),this.getDialogue().set("bodyContent",""))},this),i.on("click",function(){this.centered()}),window.require(["core/adapter"],function(t){window.adapter=t})}},_addButton:function(t,e){this.addButton({buttonName:t,icon:this.get(t+"rtcicon"),iconComponent:n,callback:e,title:t+"rtc",tags:t+"rtc",tagMatchRequiresAll:!1})},_audio:function(){var t=this.getDialogue();t.set("headerContent",M.util.get_string("audiortc","atto_recordrtc")),t.set("bodyContent",this._createContent("audio")),t.show(),M.atto_recordrtc.audiomodule.init(this)},_video:function(){var t=this.getDialogue();t.set("headerContent",M.util.get_string("videortc","atto_recordrtc")),t.set("bodyContent",this._createContent("video")),t.show(),M.atto_recordrtc.videomodule.init(this)},_createContent:function(t){var e="audio"===t,i="row",o="col-",r="alert-danger",a="btn btn-lg btn-outline-danger btn-block",d=s.Handlebars.compile('
{{insecurealert_title}} {{insecurealert}}
{{#if isAudio}}
{{else}}
{{/if}}
')({PLUGINNAME:n,isAudio:e,bs_row:i,bs_col:o,bs_al_dang:r,bs_ss_btn:a,insecurealert_title:M.util.get_string("insecurealert_title","atto_recordrtc"),insecurealert:M.util.get_string("insecurealert","atto_recordrtc"),startrecording:M.util.get_string("startrecording","atto_recordrtc"),attachrecording:M.util.get_string("attachrecording","atto_recordrtc")});return d},closeDialogue:function(t){t.getDialogue().hide(),t.editor.focus()},setLink:function(t,e){t.getDialogue().hide(),t.editor.focus(),t.get("host").insertContentAtFocusPoint(e),t.markUpdated()}},{ATTRS:{contextid:{value:null},sesskey:{value:null},allowedtypes:{value:null},audiobitrate:{value:null},videobitrate:{value:null},timelimit:{value:null},audiortcicon:{value:null},videortcicon:{value:null},maxrecsize:{value:null}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin","moodle-atto_recordrtc-recording"]}); \ No newline at end of file +YUI.add("moodle-atto_recordrtc-button",function(s,t){var n="atto_recordrtc";s.namespace("M.atto_recordrtc").Button=s.Base.create("button",s.M.editor_atto.EditorPlugin,[],{_lang:"en",initializer:function(){var t,e,i;if(this.get("host").canShowFilepicker("media")){if(e=!1,"both"!==(t=this.get("allowedtypes"))&&"audio"!==t||(this._addButton("audio",this._audio),e=!0),"both"!==t&&"video"!==t||(this._addButton("video",this._video),e=!0),!e)return;(i=this.getDialogue({width:1e3,focusAfterHide:null})).after("visibleChange",function(){var t=!i.get("visible"),e=M.atto_recordrtc.commonmodule;t&&(window.clearInterval(e.countdownTicker),e.mediaRecorder&&"inactive"!==e.mediaRecorder.state&&e.mediaRecorder.stop(),e.stream&&e.stream.getTracks().forEach(function(t){"ended"!==t.readyState&&t.stop()}),this.getDialogue().set("bodyContent",""))},this),i.on("click",function(){this.centered()}),window.require(["core/adapter"],function(t){window.adapter=t})}},_addButton:function(t,e){this.addButton({buttonName:t,icon:this.get(t+"rtcicon"),iconComponent:n,callback:e,title:t+"rtc",tags:t+"rtc",tagMatchRequiresAll:!1})},_audio:function(){var t=this.getDialogue({focusAfterHide:"audio"});t.set("headerContent",M.util.get_string("audiortc","atto_recordrtc")),t.set("bodyContent",this._createContent("audio")),t.show(),M.atto_recordrtc.audiomodule.init(this)},_video:function(){var t=this.getDialogue({focusAfterHide:"video"});t.set("headerContent",M.util.get_string("videortc","atto_recordrtc")),t.set("bodyContent",this._createContent("video")),t.show(),M.atto_recordrtc.videomodule.init(this)},_createContent:function(t){var e="audio"===t,i="row",o="col-",r="alert-danger",d="btn btn-lg btn-outline-danger btn-block",a=s.Handlebars.compile('
{{insecurealert_title}} {{insecurealert}}
{{#if isAudio}}
{{else}}
{{/if}}
')({PLUGINNAME:n,isAudio:e,bs_row:i,bs_col:o,bs_al_dang:r,bs_ss_btn:d,insecurealert_title:M.util.get_string("insecurealert_title","atto_recordrtc"),insecurealert:M.util.get_string("insecurealert","atto_recordrtc"),startrecording:M.util.get_string("startrecording","atto_recordrtc"),attachrecording:M.util.get_string("attachrecording","atto_recordrtc")});return a},closeDialogue:function(t){t.getDialogue().hide({focusAfterHide:null}),t.editor.focus()},setLink:function(t,e){t.getDialogue().hide({focusAfterHide:null}),t.editor.focus(),t.get("host").insertContentAtFocusPoint(e),t.markUpdated()}},{ATTRS:{contextid:{value:null},sesskey:{value:null},allowedtypes:{value:null},audiobitrate:{value:null},videobitrate:{value:null},timelimit:{value:null},audiortcicon:{value:null},videortcicon:{value:null},maxrecsize:{value:null}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin","moodle-atto_recordrtc-recording"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button.js b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button.js index e6fd0f403b2..b13c08e142d 100644 --- a/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button.js +++ b/lib/editor/atto/plugins/recordrtc/yui/build/moodle-atto_recordrtc-button/moodle-atto_recordrtc-button.js @@ -184,7 +184,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @private */ _audio: function() { - var dialogue = this.getDialogue(); + var dialogue = this.getDialogue({ + focusAfterHide: 'audio' + }); dialogue.set('headerContent', M.util.get_string('audiortc', 'atto_recordrtc')); dialogue.set('bodyContent', this._createContent('audio')); @@ -201,7 +203,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @private */ _video: function() { - var dialogue = this.getDialogue(); + var dialogue = this.getDialogue({ + focusAfterHide: 'video' + }); dialogue.set('headerContent', M.util.get_string('videortc', 'atto_recordrtc')); dialogue.set('bodyContent', this._createContent('video')); @@ -249,7 +253,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @param {Object} scope The "this" context of the editor. */ closeDialogue: function(scope) { - scope.getDialogue().hide(); + scope.getDialogue().hide({ + focusAfterHide: null + }); scope.editor.focus(); }, @@ -262,7 +268,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @param {string} annotation The HTML link to the recording. */ setLink: function(scope, annotation) { - scope.getDialogue().hide(); + scope.getDialogue().hide({ + focusAfterHide: null + }); scope.editor.focus(); scope.get('host').insertContentAtFocusPoint(annotation); diff --git a/lib/editor/atto/plugins/recordrtc/yui/src/button/js/button.js b/lib/editor/atto/plugins/recordrtc/yui/src/button/js/button.js index bba8d70e050..ab7081df907 100644 --- a/lib/editor/atto/plugins/recordrtc/yui/src/button/js/button.js +++ b/lib/editor/atto/plugins/recordrtc/yui/src/button/js/button.js @@ -182,7 +182,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @private */ _audio: function() { - var dialogue = this.getDialogue(); + var dialogue = this.getDialogue({ + focusAfterHide: 'audio' + }); dialogue.set('headerContent', M.util.get_string('audiortc', 'atto_recordrtc')); dialogue.set('bodyContent', this._createContent('audio')); @@ -199,7 +201,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @private */ _video: function() { - var dialogue = this.getDialogue(); + var dialogue = this.getDialogue({ + focusAfterHide: 'video' + }); dialogue.set('headerContent', M.util.get_string('videortc', 'atto_recordrtc')); dialogue.set('bodyContent', this._createContent('video')); @@ -247,7 +251,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @param {Object} scope The "this" context of the editor. */ closeDialogue: function(scope) { - scope.getDialogue().hide(); + scope.getDialogue().hide({ + focusAfterHide: null + }); scope.editor.focus(); }, @@ -260,7 +266,9 @@ Y.namespace('M.atto_recordrtc').Button = Y.Base.create('button', Y.M.editor_atto * @param {string} annotation The HTML link to the recording. */ setLink: function(scope, annotation) { - scope.getDialogue().hide(); + scope.getDialogue().hide({ + focusAfterHide: null + }); scope.editor.focus(); scope.get('host').insertContentAtFocusPoint(annotation); From a7c9576c20ab50aadb66d6945f4d999c13f16d51 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Mon, 7 Jun 2021 07:55:08 +1000 Subject: [PATCH 3/6] MDL-71672 atto_emojipicker: Focus the search bar initially --- .../moodle-atto_emojipicker-button-debug.js | 5 ++++- .../moodle-atto_emojipicker-button-min.js | 2 +- .../moodle-atto_emojipicker-button.js | 5 ++++- .../atto/plugins/emojipicker/yui/src/button/js/button.js | 5 ++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-debug.js b/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-debug.js index 059c96a1539..ba10edad2a6 100644 --- a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-debug.js +++ b/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-debug.js @@ -24,7 +24,9 @@ YUI.add('moodle-atto_emojipicker-button', function (Y, NAME) { /** * @module moodle-atto_emojipicker-button */ -var COMPONENTNAME = 'atto_emojipicker'; + +var COMPONENTNAME = 'atto_emojipicker', + EMOJI_PICKER_SEARCH_INPUT = '[data-region="search-input"]'; /** * Atto text editor emoji picker plugin. @@ -123,6 +125,7 @@ Y.namespace('M.atto_emojipicker').Button = Y.Base.create('button', Y.M.editor_at domNode.innerHTML = html; initialiseEmojiPicker(domNode, this._insertEmoji.bind(this)); this.getDialogue().centerDialogue(); + domNode.querySelector(EMOJI_PICKER_SEARCH_INPUT).focus(); }.bind(this)); }.bind(this)); diff --git a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-min.js b/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-min.js index 958709a7cf2..30de959d312 100644 --- a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-min.js +++ b/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button-min.js @@ -1 +1 @@ -YUI.add("moodle-atto_emojipicker-button",function(e,t){e.namespace("M.atto_emojipicker").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_currentSelection:null,initializer:function(){this.get("disabled")||this.addButton({icon:"e/emoticons",callback:this._displayDialogue})},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&this.getDialogue({headerContent:M.util.get_string("emojipicker","atto_emojipicker"),width:"auto",focusAfterHide:!0,additionalBaseClass:"emoji-picker-dialogue"},!0).set("bodyContent",this._getDialogueContent()).show()},_insertEmoji:function(e){var t=this.get("host");this.getDialogue({focusAfterHide:null}).hide(),t.setSelection(this._currentSelection),t.insertContentAtFocusPoint(e),this.markUpdated()},_getDialogueContent:function(){var o=e.Node.create("
");return require(["core/templates","core/emoji/picker"],function(e,i){e.render("core/emoji/picker",{}).then(function(e){var t=o.getDOMNode();t.innerHTML=e,i(t,this._insertEmoji.bind(this)),this.getDialogue().centerDialogue()}.bind(this))}.bind(this)),o}},{ATTRS:{disabled:{value:!0}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file +YUI.add("moodle-atto_emojipicker-button",function(e,t){e.namespace("M.atto_emojipicker").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_currentSelection:null,initializer:function(){this.get("disabled")||this.addButton({icon:"e/emoticons",callback:this._displayDialogue})},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&this.getDialogue({headerContent:M.util.get_string("emojipicker","atto_emojipicker"),width:"auto",focusAfterHide:!0,additionalBaseClass:"emoji-picker-dialogue"},!0).set("bodyContent",this._getDialogueContent()).show()},_insertEmoji:function(e){var t=this.get("host");this.getDialogue({focusAfterHide:null}).hide(),t.setSelection(this._currentSelection),t.insertContentAtFocusPoint(e),this.markUpdated()},_getDialogueContent:function(){var o=e.Node.create("
");return require(["core/templates","core/emoji/picker"],function(e,i){e.render("core/emoji/picker",{}).then(function(e){var t=o.getDOMNode();t.innerHTML=e,i(t,this._insertEmoji.bind(this)),this.getDialogue().centerDialogue(),t.querySelector('[data-region="search-input"]').focus()}.bind(this))}.bind(this)),o}},{ATTRS:{disabled:{value:!0}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button.js b/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button.js index 059c96a1539..ba10edad2a6 100644 --- a/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button.js +++ b/lib/editor/atto/plugins/emojipicker/yui/build/moodle-atto_emojipicker-button/moodle-atto_emojipicker-button.js @@ -24,7 +24,9 @@ YUI.add('moodle-atto_emojipicker-button', function (Y, NAME) { /** * @module moodle-atto_emojipicker-button */ -var COMPONENTNAME = 'atto_emojipicker'; + +var COMPONENTNAME = 'atto_emojipicker', + EMOJI_PICKER_SEARCH_INPUT = '[data-region="search-input"]'; /** * Atto text editor emoji picker plugin. @@ -123,6 +125,7 @@ Y.namespace('M.atto_emojipicker').Button = Y.Base.create('button', Y.M.editor_at domNode.innerHTML = html; initialiseEmojiPicker(domNode, this._insertEmoji.bind(this)); this.getDialogue().centerDialogue(); + domNode.querySelector(EMOJI_PICKER_SEARCH_INPUT).focus(); }.bind(this)); }.bind(this)); diff --git a/lib/editor/atto/plugins/emojipicker/yui/src/button/js/button.js b/lib/editor/atto/plugins/emojipicker/yui/src/button/js/button.js index be0c29ec6d3..88d7efdb7c4 100644 --- a/lib/editor/atto/plugins/emojipicker/yui/src/button/js/button.js +++ b/lib/editor/atto/plugins/emojipicker/yui/src/button/js/button.js @@ -22,7 +22,9 @@ /** * @module moodle-atto_emojipicker-button */ -var COMPONENTNAME = 'atto_emojipicker'; + +var COMPONENTNAME = 'atto_emojipicker', + EMOJI_PICKER_SEARCH_INPUT = '[data-region="search-input"]'; /** * Atto text editor emoji picker plugin. @@ -121,6 +123,7 @@ Y.namespace('M.atto_emojipicker').Button = Y.Base.create('button', Y.M.editor_at domNode.innerHTML = html; initialiseEmojiPicker(domNode, this._insertEmoji.bind(this)); this.getDialogue().centerDialogue(); + domNode.querySelector(EMOJI_PICKER_SEARCH_INPUT).focus(); }.bind(this)); }.bind(this)); From aa3a2a43ea8b2c493b25837a09a38f9cf4690c74 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Mon, 7 Jun 2021 12:37:11 +1000 Subject: [PATCH 4/6] MDL-71672 atto_managefiles: Focus the first file manager button --- .../moodle-atto_managefiles-button-debug.js | 20 ++++++++++++++++++- .../moodle-atto_managefiles-button-min.js | 2 +- .../moodle-atto_managefiles-button.js | 20 ++++++++++++++++++- .../managefiles/yui/src/button/js/button.js | 20 ++++++++++++++++++- 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-debug.js b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-debug.js index 59199a492cd..ff55e3d878e 100644 --- a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-debug.js +++ b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-debug.js @@ -33,7 +33,9 @@ YUI.add('moodle-atto_managefiles-button', function (Y, NAME) { * @extends M.editor_atto.EditorPlugin */ -var LOGNAME = 'atto_managefiles'; +var LOGNAME = 'atto_managefiles', + CAN_RECEIVE_FOCUS_SELECTOR = '.fp-navbar a:not([disabled])', + FILE_MANAGER_SELECTOR = '#fitem_id_files_filemanager'; Y.namespace('M.atto_managefiles').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { @@ -96,6 +98,22 @@ Y.namespace('M.atto_managefiles').Button = Y.Base.create('button', Y.M.editor_at }); iframe.setAttribute('src', this._getIframeURL()); + // Focus on the first focusable element of the file manager after it is fully loaded. + iframe.on('load', function(e, frame) { + var fileManager = frame.getDOMNode().contentDocument.querySelector(FILE_MANAGER_SELECTOR); + // The file manager component is loaded asynchronously after the page is loaded. + // We check for the presence of .fm-loaded every 200 ms to determine if the file manager is loaded yet. + var intervalId = setInterval(function() { + if (fileManager.querySelector('.fm-loaded')) { + var firstFocusableElement = fileManager.querySelector(CAN_RECEIVE_FOCUS_SELECTOR); + if (firstFocusableElement) { + firstFocusableElement.focus(); + } + clearInterval(intervalId); + } + }, 200); + }, this, iframe); + dialogue.set('bodyContent', iframe) .show(); diff --git a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-min.js b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-min.js index 16ab8ed38b2..60c6c8ffe29 100644 --- a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-min.js +++ b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button-min.js @@ -1 +1 @@ -YUI.add("moodle-atto_managefiles-button",function(a,e){a.namespace("M.atto_managefiles").Button=a.Base.create("button",a.M.editor_atto.EditorPlugin,[],{_currentSelection:null,initializer:function(){if(!this.get("disabled")){var e=this.get("host"),t=this.get("area"),i=e.get("filepickeroptions");i.image&&i.image.itemid&&(t.itemid=i.image.itemid,this.set("area",t),this.addButton({icon:"e/manage_files",callback:this._displayDialogue}))}},_displayDialogue:function(e){var t,i;e.preventDefault(),t=this.getDialogue({headerContent:M.util.get_string("managefiles","atto_managefiles"),width:"800px",focusAfterHide:!0}),(i=a.Node.create("")).setStyles({height:"700px",border:"none",width:"100%"}),i.setAttribute("src",this._getIframeURL()),t.set("bodyContent",i).show(),this.markUpdated()},_getIframeURL:function(){var e=a.mix({elementid:this.get("host").get("elementid")},this.get("area"));return M.cfg.wwwroot+"/lib/editor/atto/plugins/managefiles/manage.php?"+a.QueryString.stringify(e)}},{ATTRS:{disabled:{value:!0},area:{value:{}}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file +YUI.add("moodle-atto_managefiles-button",function(a,e){a.namespace("M.atto_managefiles").Button=a.Base.create("button",a.M.editor_atto.EditorPlugin,[],{_currentSelection:null,initializer:function(){if(!this.get("disabled")){var e=this.get("host"),t=this.get("area"),i=e.get("filepickeroptions");i.image&&i.image.itemid&&(t.itemid=i.image.itemid,this.set("area",t),this.addButton({icon:"e/manage_files",callback:this._displayDialogue}))}},_displayDialogue:function(e){var t,i;e.preventDefault(),t=this.getDialogue({headerContent:M.util.get_string("managefiles","atto_managefiles"),width:"800px",focusAfterHide:!0}),(i=a.Node.create("")).setStyles({height:"700px",border:"none",width:"100%"}),i.setAttribute("src",this._getIframeURL()),i.on("load",function(e,t){var i=t.getDOMNode().contentDocument.querySelector("#fitem_id_files_filemanager"),a=setInterval(function(){if(i.querySelector(".fm-loaded")){var e=i.querySelector(".fp-navbar a:not([disabled])");e&&e.focus(),clearInterval(a)}},200)},this,i),t.set("bodyContent",i).show(),this.markUpdated()},_getIframeURL:function(){var e=a.mix({elementid:this.get("host").get("elementid")},this.get("area"));return M.cfg.wwwroot+"/lib/editor/atto/plugins/managefiles/manage.php?"+a.QueryString.stringify(e)}},{ATTRS:{disabled:{value:!0},area:{value:{}}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button.js b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button.js index 1434a96e9df..7dbc265997e 100644 --- a/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button.js +++ b/lib/editor/atto/plugins/managefiles/yui/build/moodle-atto_managefiles-button/moodle-atto_managefiles-button.js @@ -33,7 +33,9 @@ YUI.add('moodle-atto_managefiles-button', function (Y, NAME) { * @extends M.editor_atto.EditorPlugin */ -var LOGNAME = 'atto_managefiles'; +var LOGNAME = 'atto_managefiles', + CAN_RECEIVE_FOCUS_SELECTOR = '.fp-navbar a:not([disabled])', + FILE_MANAGER_SELECTOR = '#fitem_id_files_filemanager'; Y.namespace('M.atto_managefiles').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { @@ -94,6 +96,22 @@ Y.namespace('M.atto_managefiles').Button = Y.Base.create('button', Y.M.editor_at }); iframe.setAttribute('src', this._getIframeURL()); + // Focus on the first focusable element of the file manager after it is fully loaded. + iframe.on('load', function(e, frame) { + var fileManager = frame.getDOMNode().contentDocument.querySelector(FILE_MANAGER_SELECTOR); + // The file manager component is loaded asynchronously after the page is loaded. + // We check for the presence of .fm-loaded every 200 ms to determine if the file manager is loaded yet. + var intervalId = setInterval(function() { + if (fileManager.querySelector('.fm-loaded')) { + var firstFocusableElement = fileManager.querySelector(CAN_RECEIVE_FOCUS_SELECTOR); + if (firstFocusableElement) { + firstFocusableElement.focus(); + } + clearInterval(intervalId); + } + }, 200); + }, this, iframe); + dialogue.set('bodyContent', iframe) .show(); diff --git a/lib/editor/atto/plugins/managefiles/yui/src/button/js/button.js b/lib/editor/atto/plugins/managefiles/yui/src/button/js/button.js index 3ba25e56f79..abf0012e3bf 100644 --- a/lib/editor/atto/plugins/managefiles/yui/src/button/js/button.js +++ b/lib/editor/atto/plugins/managefiles/yui/src/button/js/button.js @@ -31,7 +31,9 @@ * @extends M.editor_atto.EditorPlugin */ -var LOGNAME = 'atto_managefiles'; +var LOGNAME = 'atto_managefiles', + CAN_RECEIVE_FOCUS_SELECTOR = '.fp-navbar a:not([disabled])', + FILE_MANAGER_SELECTOR = '#fitem_id_files_filemanager'; Y.namespace('M.atto_managefiles').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { @@ -94,6 +96,22 @@ Y.namespace('M.atto_managefiles').Button = Y.Base.create('button', Y.M.editor_at }); iframe.setAttribute('src', this._getIframeURL()); + // Focus on the first focusable element of the file manager after it is fully loaded. + iframe.on('load', function(e, frame) { + var fileManager = frame.getDOMNode().contentDocument.querySelector(FILE_MANAGER_SELECTOR); + // The file manager component is loaded asynchronously after the page is loaded. + // We check for the presence of .fm-loaded every 200 ms to determine if the file manager is loaded yet. + var intervalId = setInterval(function() { + if (fileManager.querySelector('.fm-loaded')) { + var firstFocusableElement = fileManager.querySelector(CAN_RECEIVE_FOCUS_SELECTOR); + if (firstFocusableElement) { + firstFocusableElement.focus(); + } + clearInterval(intervalId); + } + }, 200); + }, this, iframe); + dialogue.set('bodyContent', iframe) .show(); From 2bafc9195230fa402a918b8c95d5ad38bcfef0b4 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Sat, 19 Jun 2021 06:59:45 +1000 Subject: [PATCH 5/6] MDL-71672 atto_equation: Fix the markup and the initial focused element The initial focused element should be the first operator button. This commit also fixes the accessibility issues that previously were wrongly fixed by a redundant click on the first tab using javascript. --- lib/editor/atto/plugins/equation/lib.php | 1 + .../moodle-atto_equation-button-debug.js | 11 ++++++----- .../moodle-atto_equation-button-min.js | 4 ++-- .../moodle-atto_equation-button.js | 11 ++++++----- .../atto/plugins/equation/yui/src/button/js/button.js | 11 ++++++----- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/lib/editor/atto/plugins/equation/lib.php b/lib/editor/atto/plugins/equation/lib.php index eaba74794de..c3f0a7d0edf 100644 --- a/lib/editor/atto/plugins/equation/lib.php +++ b/lib/editor/atto/plugins/equation/lib.php @@ -68,6 +68,7 @@ function atto_equation_params_for_js($elementid, $options, $fpoptions) { 'group1' => array( 'groupname' => 'librarygroup1', 'elements' => get_config('atto_equation', 'librarygroup1'), + 'active' => true, ), 'group2' => array( 'groupname' => 'librarygroup2', diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js index 9b920826db3..26506612b8e 100644 --- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js +++ b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js @@ -75,7 +75,10 @@ var COMPONENTNAME = 'atto_equation', '' + '
' + '{{#each library}}' + - '
' + '
' + '{{#split "\n" elements}}' + @@ -222,14 +225,12 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. headerContent: M.util.get_string('pluginname', COMPONENTNAME), focusAfterHide: true, width: 600, - focusOnShowSelector: SELECTORS.EQUATION_TEXT + focusOnShowSelector: SELECTORS.LIBRARY_BUTTON }); var content = this._getDialogueContent(); dialogue.set('bodyContent', content); - content.one('.nav-item:first-child .nav-link').getDOMNode().click(); - dialogue.show(); // Notify the filters about the modified nodes. require(['core/event'], function(event) { diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js index 4fb26ebdf5a..9978c135056 100644 --- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js +++ b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js @@ -1,2 +1,2 @@ -YUI.add("moodle-atto_equation-button",function(r,t){var a="atto_equation",l={EQUATION_TEXT:"atto_equation_equation",EQUATION_PREVIEW:"atto_equation_preview",SUBMIT:"atto_equation_submit",LIBRARY:"atto_equation_library",LIBRARY_GROUPS:"atto_equation_groups",LIBRARY_GROUP_PREFIX:"atto_equation_group"},u={LIBRARY:"."+l.LIBRARY,LIBRARY_GROUP:"."+l.LIBRARY_GROUPS+" > div > div",EQUATION_TEXT:"."+l.EQUATION_TEXT,EQUATION_PREVIEW:"."+l.EQUATION_PREVIEW,SUBMIT:"."+l.SUBMIT,LIBRARY_BUTTON:"."+l.LIBRARY+" button"},c={START:"\\(",END:"\\)"},i='
{{{library}}}
{{get_string "cursorinfo" component}}

',h='
{{#each library}}
{{#split "\n" elements}}{{/split}}
{{/each}}
';r.namespace("M.atto_equation").Button=r.Base.create("button",r.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_lastCursorPos:0,_content:null,_sourceEquation:null,_groupFocus:null,_equationPatterns:[/\$\$([\S\s]+?)\$\$/,/\\\(([\S\s]+?)\\\)/,/\\\[([\S\s]+?)\\\]/,/\[tex\]([\S\s]+?)\[\/tex\]/],initializer:function(){this._groupFocus={},this.get("texfilteractive")&&(this.addButton({icon:"e/math",callback:this._displayDialogue}),this.get("host").on("atto:selectionchanged",function(){this._resolveEquation()?this.highlightButtons():this.unHighlightButtons()},this),this.editor.all("tex").each(function(t){var e=r.Node.create(""+c.START+" "+t.get("text")+" "+c.END+"");t.replace(e)}))},_displayDialogue:function(){var t,e,n;this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&(t=this._resolveEquation(),e=this.getDialogue({headerContent:M.util.get_string("pluginname",a),focusAfterHide:!0,width:600,focusOnShowSelector:u.EQUATION_TEXT}),n=this._getDialogueContent(),e.set("bodyContent",n),n.one(".nav-item:first-child .nav-link").getDOMNode().click(),e.show(),require(["core/event"],function(t){t.notifyFilterContentUpdated(e.get("boundingBox").getDOMNode())}),t&&n.one(u.EQUATION_TEXT).set("text",t),this._updatePreview(!1))},_resolveEquation:function(){var c,t=this.get("host").getSelectionParentNode(),h=this.get("host").getSelection(),d=!1;return!!this.get("host").isActive()&&(!!t&&(!(!h||0===h.length)&&(this.sourceEquation=null,h=h[0],c=r.one(t).get("text"),r.Array.find(this._equationPatterns,function(u){var t=c.match(new RegExp(u.source,"g"));if(t&&t.length)return r.Array.find(t,function(t){for(var e,n,i,o,s,a,r,l=0;-1!==c.indexOf(t,l);){if(n=(e=c.indexOf(t,l))+t.length,i=h.startOffset>=e&&h.startOffsete,i&&o&&(s=t.match(u))&&s.length)return r=(a=c.indexOf(s[1],e))+s[1].length,d=s[1],this.sourceEquation={startOuterPosition:e,endOuterPosition:n,outerMatch:t,startInnerPosition:a,endInnerPosition:r,innerMatch:s},!0;l=n}},this)},this),!1!==d&&(d=d.trim()),d)))},_setEquation:function(t){var e,n,i,o,s;o=this.get("host"),t.preventDefault(),this.getDialogue({focusAfterHide:null}).hide(),""!==(i=t.currentTarget.ancestor(".atto_form").one("textarea").get("value"))&&(o.setSelection(this._currentSelection),this.sourceEquation?(i=" "+i+" ",s=(n=(e=r.one(o.getSelectionParentNode())).get("text")).slice(0,this.sourceEquation.startInnerPosition)+i+n.slice(this.sourceEquation.endInnerPosition),e.set("text",s)):(i=c.START+" "+i+" "+c.END,o.insertContentAtFocusPoint(i)),this.markUpdated())},_throttle:function(n,i){var o=null;return function(){var t=this,e=arguments;clearTimeout(o),o=setTimeout(function(){n.apply(t,e)},i)}},_updatePreview:function(t){var e,n,i,o=this._content.one(u.EQUATION_TEXT),s=o.get("value"),a=o.get("selectionStart");for(t&&t.preventDefault(),a=a||0;"\\"===s.charAt(a)&&0<=a;)--a;if(n=/[a-zA-Z\{]/,0!==a&&"{"!=s.charAt(a-1))for(;n.test(s.charAt(a))&&a=o.size()&&(a=0),e=o.item(a),this._setGroupTabFocus(i,e),e.focus()},_setGroupTabFocus:function(t,e){var n=t.generateID();"undefined"!=typeof this._groupFocus[n]&&this._groupFocus[n].setAttribute("tabindex","-1"),(this._groupFocus[n]=e).setAttribute("tabindex",0),t.setAttribute("aria-activedescendant",e.generateID())},_selectLibraryItem:function(t){var e,n,i,o,s,a=t.currentTarget.getAttribute("data-tex"),r=0;t.preventDefault(),this._setGroupTabFocus(t.currentTarget.get("parentNode"),t.currentTarget)," "!==(n=(e=(i=t.currentTarget.ancestor(".atto_form").one("textarea")).get("value")).substring(0,this._lastCursorPos)).charAt(n.length-1)&&(n+=" "),r=(n+=a).length," "!==e.charAt(this._lastCursorPos)&&(n+=" "),n+=e.substring(this._lastCursorPos,e.length),i.set("value",n),i.focus(),"number"==typeof(o=i.getDOMNode()).selectionStart?o.selectionStart=o.selectionEnd=r:"undefined"!=typeof o.createTextRange&&((s=o.createTextRange()).moveToPoint(r),s.select()),this._updatePreview(!1)},_getLibraryContent:function(){var t,e,n,i=r.Handlebars.compile(h),o=this.get("library"),s="";return r.Handlebars.registerHelper("split",function(t,e,n){var i,o,s;if(void 0===t||void 0===e)return"";for(s="",i=e.trim().split(t);0 div > div",EQUATION_TEXT:"."+l.EQUATION_TEXT,EQUATION_PREVIEW:"."+l.EQUATION_PREVIEW,SUBMIT:"."+l.SUBMIT,LIBRARY_BUTTON:"."+l.LIBRARY+" button"},c={START:"\\(",END:"\\)"},n='
{{{library}}}
{{get_string "cursorinfo" component}}

',d='
{{#each library}}
{{#split "\n" elements}}{{/split}}
{{/each}}
';r.namespace("M.atto_equation").Button=r.Base.create("button",r.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_lastCursorPos:0,_content:null,_sourceEquation:null,_groupFocus:null,_equationPatterns:[/\$\$([\S\s]+?)\$\$/,/\\\(([\S\s]+?)\\\)/,/\\\[([\S\s]+?)\\\]/,/\[tex\]([\S\s]+?)\[\/tex\]/],initializer:function(){this._groupFocus={},this.get("texfilteractive")&&(this.addButton({icon:"e/math",callback:this._displayDialogue}),this.get("host").on("atto:selectionchanged",function(){this._resolveEquation()?this.highlightButtons():this.unHighlightButtons()},this),this.editor.all("tex").each(function(t){var e=r.Node.create(""+c.START+" "+t.get("text")+" "+c.END+"");t.replace(e)}))},_displayDialogue:function(){var t,e,i;this._currentSelection=this.get("host").getSelection(),!1!==this._currentSelection&&(t=this._resolveEquation(),e=this.getDialogue({headerContent:M.util.get_string("pluginname",s),focusAfterHide:!0,width:600,focusOnShowSelector:u.LIBRARY_BUTTON}),i=this._getDialogueContent(),e.set("bodyContent",i),e.show(),require(["core/event"],function(t){t.notifyFilterContentUpdated(e.get("boundingBox").getDOMNode())}),t&&i.one(u.EQUATION_TEXT).set("text",t),this._updatePreview(!1))},_resolveEquation:function(){var c,t=this.get("host").getSelectionParentNode(),d=this.get("host").getSelection(),h=!1;return!!this.get("host").isActive()&&(!!t&&(!(!d||0===d.length)&&(this.sourceEquation=null,d=d[0],c=r.one(t).get("text"),r.Array.find(this._equationPatterns,function(u){var t=c.match(new RegExp(u.source,"g"));if(t&&t.length)return r.Array.find(t,function(t){for(var e,i,n,o,a,s,r,l=0;-1!==c.indexOf(t,l);){if(i=(e=c.indexOf(t,l))+t.length,n=d.startOffset>=e&&d.startOffsete,n&&o&&(a=t.match(u))&&a.length)return r=(s=c.indexOf(a[1],e))+a[1].length,h=a[1],this.sourceEquation={startOuterPosition:e,endOuterPosition:i,outerMatch:t,startInnerPosition:s,endInnerPosition:r,innerMatch:a},!0;l=i}},this)},this),!1!==h&&(h=h.trim()),h)))},_setEquation:function(t){var e,i,n,o,a;o=this.get("host"),t.preventDefault(),this.getDialogue({focusAfterHide:null}).hide(),""!==(n=t.currentTarget.ancestor(".atto_form").one("textarea").get("value"))&&(o.setSelection(this._currentSelection),this.sourceEquation?(n=" "+n+" ",a=(i=(e=r.one(o.getSelectionParentNode())).get("text")).slice(0,this.sourceEquation.startInnerPosition)+n+i.slice(this.sourceEquation.endInnerPosition),e.set("text",a)):(n=c.START+" "+n+" "+c.END,o.insertContentAtFocusPoint(n)),this.markUpdated())},_throttle:function(i,n){var o=null;return function(){var t=this,e=arguments;clearTimeout(o),o=setTimeout(function(){i.apply(t,e)},n)}},_updatePreview:function(t){var e,i,n,o=this._content.one(u.EQUATION_TEXT),a=o.get("value"),s=o.get("selectionStart");for(t&&t.preventDefault(),s=s||0;"\\"===a.charAt(s)&&0<=s;)--s;if(i=/[a-zA-Z\{]/,0!==s&&"{"!=a.charAt(s-1))for(;i.test(a.charAt(s))&&s=o.size()&&(s=0),e=o.item(s),this._setGroupTabFocus(n,e),e.focus()},_setGroupTabFocus:function(t,e){var i=t.generateID();"undefined"!=typeof this._groupFocus[i]&&this._groupFocus[i].setAttribute("tabindex","-1"),(this._groupFocus[i]=e).setAttribute("tabindex",0),t.setAttribute("aria-activedescendant",e.generateID())},_selectLibraryItem:function(t){var e,i,n,o,a,s=t.currentTarget.getAttribute("data-tex"),r=0;t.preventDefault(),this._setGroupTabFocus(t.currentTarget.get("parentNode"),t.currentTarget)," "!==(i=(e=(n=t.currentTarget.ancestor(".atto_form").one("textarea")).get("value")).substring(0,this._lastCursorPos)).charAt(i.length-1)&&(i+=" "),r=(i+=s).length," "!==e.charAt(this._lastCursorPos)&&(i+=" "),i+=e.substring(this._lastCursorPos,e.length),n.set("value",i),n.focus(),"number"==typeof(o=n.getDOMNode()).selectionStart?o.selectionStart=o.selectionEnd=r:"undefined"!=typeof o.createTextRange&&((a=o.createTextRange()).moveToPoint(r),a.select()),this._updatePreview(!1)},_getLibraryContent:function(){var t,e,i,n=r.Handlebars.compile(d),o=this.get("library"),a="";return r.Handlebars.registerHelper("split",function(t,e,i){var n,o,a;if(void 0===t||void 0===e)return"";for(a="",n=e.trim().split(t);0' + '{{#each library}}' + '