@@ -727,7 +727,7 @@ var codeInput = {
727727 // Save element internally
728728 this . textareaElement = textarea ;
729729 this . append ( textarea ) ;
730- this . setupTextareaSyncEvents ( ) ;
730+ this . setupTextareaSyncEvents ( this . textareaElement ) ;
731731
732732 // Create result element
733733 let code = document . createElement ( "code" ) ;
@@ -839,7 +839,24 @@ var codeInput = {
839839 } else {
840840 this . setup ( ) ;
841841 }
842- }
842+ }
843+
844+ // Graceful degradation: make events still work without template being
845+ // registered
846+ if ( document . readyState === 'loading' ) {
847+ // Children not yet present - wait until they are
848+ window . addEventListener ( "DOMContentLoaded" , ( ) => {
849+ const fallbackTextarea = this . querySelector ( "textarea[data-code-input-fallback]" ) ;
850+ if ( fallbackTextarea ) {
851+ this . setupTextareaSyncEvents ( fallbackTextarea ) ;
852+ }
853+ } )
854+ } else {
855+ const fallbackTextarea = this . querySelector ( "textarea[data-code-input-fallback]" ) ;
856+ if ( fallbackTextarea ) {
857+ this . setupTextareaSyncEvents ( fallbackTextarea ) ;
858+ }
859+ }
843860 }
844861
845862 mutationObserverCallback ( mutationList , observer ) {
@@ -959,20 +976,116 @@ var codeInput = {
959976 // Event listener added to pass to code-input element
960977
961978 /**
962- * Capture all events from textareaSyncEvents triggered on the textarea element
963- * and pass them to the code-input element.
979+ * Capture all events from textareaSyncEvents triggered on the given textarea
980+ * element and pass them to the code-input element.
964981 */
965- setupTextareaSyncEvents ( ) {
982+ setupTextareaSyncEvents ( textarea ) {
966983 for ( let i = 0 ; i < codeInput . textareaSyncEvents . length ; i ++ ) {
967984 const evtName = codeInput . textareaSyncEvents [ i ] ;
968- this . textareaElement . addEventListener ( evtName , ( evt ) => {
985+ textarea . addEventListener ( evtName , ( evt ) => {
969986 if ( ! evt . bubbles ) { // Don't duplicate the callback
970987 this . dispatchEvent ( new evt . constructor ( evt . type , evt ) ) ; // Thanks to
971988 }
972989 } ) ;
973990 }
974991 }
975992
993+ // addEventListener and removeEventListener overrides are still used
994+ // for backwards compatibility - unlike the solution above, they keep
995+ // the event's isTrusted as true.
996+ /**
997+ * @override
998+ */
999+ addEventListener ( type , listener , options = undefined ) {
1000+ // Save a copy of the callback where `this` refers to the code-input element.
1001+ let boundCallback = function ( evt ) {
1002+ if ( typeof listener === 'function' ) {
1003+ listener ( evt ) ;
1004+ } else if ( listener && listener . handleEvent ) {
1005+ listener . handleEvent ( evt ) ;
1006+ }
1007+ } . bind ( this ) ;
1008+ this . boundEventCallbacks [ listener ] = boundCallback ;
1009+
1010+ if ( codeInput . textareaSyncEvents . includes ( type ) ) {
1011+ // Synchronise with textarea
1012+ this . boundEventCallbacks [ listener ] = boundCallback ;
1013+
1014+ if ( options === undefined ) {
1015+ if ( this . textareaElement == null ) {
1016+ // Unregistered
1017+ const fallbackTextarea = this . querySelector ( "textarea[data-code-input-fallback]" ) ;
1018+ if ( fallbackTextarea ) {
1019+ fallbackTextarea . addEventListener ( type , boundCallback ) ;
1020+ }
1021+ this . addEventListener ( "code-input_load" , ( ) => { this . textareaElement . addEventListener ( type , boundCallback ) ; } ) ;
1022+ } else {
1023+ this . textareaElement . addEventListener ( type , boundCallback ) ;
1024+ }
1025+ } else {
1026+ if ( this . textareaElement == null ) {
1027+ // Unregistered
1028+ const fallbackTextarea = this . querySelector ( "textarea[data-code-input-fallback]" ) ;
1029+ if ( fallbackTextarea ) {
1030+ fallbackTextarea . addEventListener ( type , boundCallback , options ) ;
1031+ }
1032+ this . addEventListener ( "code-input_load" , ( ) => { this . textareaElement . addEventListener ( type , boundCallback , options ) ; } ) ;
1033+ } else {
1034+ this . textareaElement . addEventListener ( type , boundCallback , options ) ;
1035+ }
1036+ }
1037+ } else {
1038+ // Synchronise with code-input element
1039+ if ( options === undefined ) {
1040+ super . addEventListener ( type , boundCallback ) ;
1041+ } else {
1042+ super . addEventListener ( type , boundCallback , options ) ;
1043+ }
1044+ }
1045+ }
1046+
1047+ /**
1048+ * @override
1049+ */
1050+ removeEventListener ( type , listener , options = undefined ) {
1051+ // Save a copy of the callback where `this` refers to the code-input element
1052+ let boundCallback = this . boundEventCallbacks [ listener ] ;
1053+
1054+ if ( codeInput . textareaSyncEvents . includes ( type ) ) {
1055+ // Synchronise with textarea
1056+ if ( options === undefined ) {
1057+ if ( this . textareaElement == null ) {
1058+ // Unregistered
1059+ const fallbackTextarea = this . querySelector ( "textarea[data-code-input-fallback]" ) ;
1060+ if ( fallbackTextarea ) {
1061+ fallbackTextarea . removeEventListener ( type , boundCallback ) ;
1062+ }
1063+ this . addEventListener ( "code-input_load" , ( ) => { this . textareaElement . removeEventListener ( type , boundCallback ) ; } ) ;
1064+ } else {
1065+ this . textareaElement . removeEventListener ( type , boundCallback ) ;
1066+ }
1067+ } else {
1068+ if ( this . textareaElement == null ) {
1069+ // Unregistered
1070+ const fallbackTextarea = this . querySelector ( "textarea[data-code-input-fallback]" ) ;
1071+ if ( fallbackTextarea ) {
1072+ fallbackTextarea . removeEventListener ( type , boundCallback , options ) ;
1073+ }
1074+ this . addEventListener ( "code-input_load" , ( ) => { this . textareaElement . removeEventListener ( type , boundCallback , options ) ; } ) ;
1075+ } else {
1076+ this . textareaElement . removeEventListener ( type , boundCallback , options ) ;
1077+ }
1078+ }
1079+ } else {
1080+ // Synchronise with code-input element
1081+ if ( options === undefined ) {
1082+ super . removeEventListener ( type , boundCallback ) ;
1083+ } else {
1084+ super . removeEventListener ( type , boundCallback , options ) ;
1085+ }
1086+ }
1087+ }
1088+
9761089 /**
9771090 * Get the JavaScript property from the internal textarea
9781091 * element, given its name and a defaultValue to return
0 commit comments