@@ -482,7 +482,8 @@ var codeInput = {
482482 * to syntax-highlight it. */
483483
484484 needsHighlight = false ; // Just inputted
485- passEventsToTextarea = true ; // Turn to false when unusual internal events are called on the textarea
485+ handleEventsFromTextarea = true ; // Turn to false when unusual internal events are called on the textarea
486+ originalAriaDescription ;
486487
487488 /**
488489 * Highlight the code as soon as possible
@@ -510,6 +511,7 @@ var codeInput = {
510511 update ( ) {
511512 let resultElement = this . codeElement ;
512513 let value = this . value ;
514+ value += "\n" ; // Placeholder for next line
513515
514516 // Update code
515517 resultElement . innerHTML = this . escapeHtml ( value ) ;
@@ -523,17 +525,17 @@ var codeInput = {
523525
524526 // If editing here, scroll to the caret by focusing, though this shouldn't count as a focus event
525527 if ( this . textareaElement === document . activeElement ) {
526- this . passEventsToTextarea = false ;
528+ this . handleEventsFromTextarea = false ;
527529 this . textareaElement . blur ( ) ;
528530 this . textareaElement . focus ( ) ;
529- this . passEventsToTextarea = true ;
531+ this . handleEventsFromTextarea = true ;
530532 }
531533
532534 this . pluginEvt ( "afterHighlight" ) ;
533535 }
534536
535537 /**
536- * Set the size of the pre/code element to the size of the textarea element.
538+ * Set the size of the textarea element to the size of the pre/code element.
537539 */
538540 syncSize ( ) {
539541 // Synchronise the size of the pre/code and textarea elements
@@ -551,10 +553,15 @@ var codeInput = {
551553 /**
552554 * Show some instructions to the user only if they are using keyboard navigation - for example, a prompt on how to navigate with the keyboard if Tab is repurposed.
553555 * @param {string } instructions The instructions to display only if keyboard navigation is being used. If it's blank, no instructions will be shown.
556+ * @param {boolean } includeAriaDescriptionFirst Whether to include the aria-description of the code-input element before the keyboard navigation instructions for a screenreader. Keep this as true when the textarea is first focused.
554557 */
555- setKeyboardNavInstructions ( instructions ) {
558+ setKeyboardNavInstructions ( instructions , includeAriaDescriptionFirst ) {
556559 this . dialogContainerElement . querySelector ( ".code-input_keyboard-navigation-instructions" ) . innerText = instructions ;
557- this . setAttribute ( "aria-description" , "code-input. " + instructions ) ;
560+ if ( includeAriaDescriptionFirst ) {
561+ this . textareaElement . setAttribute ( "aria-description" , this . originalAriaDescription + ". " + instructions ) ;
562+ } else {
563+ this . textareaElement . setAttribute ( "aria-description" , instructions ) ;
564+ }
558565 }
559566
560567 /**
@@ -619,9 +626,6 @@ var codeInput = {
619626
620627 this . initialValue = value ; // For form reset
621628
622- // Disable focusing on the code-input element - only allow the textarea to be focusable
623- this . setAttribute ( "tabindex" , - 1 ) ;
624-
625629 // Create textarea
626630 let textarea = document . createElement ( "textarea" ) ;
627631 textarea . placeholder = placeholder ;
@@ -630,13 +634,19 @@ var codeInput = {
630634 }
631635 textarea . innerHTML = this . innerHTML ;
632636 textarea . setAttribute ( "spellcheck" , "false" ) ;
637+
638+ // Disable focusing on the code-input element - only allow the textarea to be focusable
639+ textarea . setAttribute ( "tabindex" , this . getAttribute ( "tabindex" ) || 0 ) ;
640+ this . setAttribute ( "tabindex" , - 1 ) ;
641+ // Save aria-description so keyboard navigation guidance can be added.
642+ this . originalAriaDescription = this . getAttribute ( "aria-description" ) || "Code input field" ;
633643
634644 // Accessibility - detect when mouse focus to remove focus outline + keyboard navigation guidance that could irritate users.
635- textarea . addEventListener ( "mousedown" , ( ) => {
645+ this . addEventListener ( "mousedown" , ( ) => {
636646 this . classList . add ( "code-input_mouse-focused" ) ;
637647 } ) ;
638648 textarea . addEventListener ( "blur" , ( ) => {
639- if ( this . passEventsToTextarea ) {
649+ if ( this . handleEventsFromTextarea ) {
640650 this . classList . remove ( "code-input_mouse-focused" ) ;
641651 }
642652 } ) ;
@@ -854,12 +864,15 @@ var codeInput = {
854864 */
855865 addEventListener ( type , listener , options = undefined ) {
856866 // Save a copy of the callback where `this` refers to the code-input element.
857- // This callback is modified to only run when the passEventsToTextarea is set.
858- let boundCallback = function ( evt ) { if ( this . passEventsToTextarea ) listener ( evt ) ; } . bind ( this ) ;
867+ // This callback is modified to only run when the handleEventsFromTextarea is set.
868+ let boundCallback = function ( evt ) { listener ( evt ) ; } . bind ( this ) ;
859869 this . boundEventCallbacks [ listener ] = boundCallback ;
860870
861871 if ( codeInput . textareaSyncEvents . includes ( type ) ) {
862- // Synchronise with textarea
872+ // Synchronise with textarea, only when handleEventsFromTextarea is true
873+ let boundCallback = function ( evt ) { if ( this . handleEventsFromTextarea ) listener ( evt ) ; } . bind ( this ) ;
874+ this . boundEventCallbacks [ listener ] = boundCallback ;
875+
863876 if ( options === undefined ) {
864877 if ( this . textareaElement == null ) {
865878 this . addEventListener ( "code-input_load" , ( ) => { this . textareaElement . addEventListener ( type , boundCallback ) ; } ) ;
0 commit comments