Skip to content

Commit 63f4b4b

Browse files
committed
Make events transferred to handlers that were trusted in the past still trusted; Allow textarea
events to sync to fallback textarea for graceful degradation
1 parent 5f013a6 commit 63f4b4b

File tree

1 file changed

+119
-6
lines changed

1 file changed

+119
-6
lines changed

code-input.js

Lines changed: 119 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)