Skip to content

Commit 9b3cddd

Browse files
committed
Sync selection+scroll position and focus state; Make fallback textarea be absent during beforeElementsAdded pluginEvent for backwards compatibility
1 parent 778376c commit 9b3cddd

File tree

1 file changed

+35
-2
lines changed

1 file changed

+35
-2
lines changed

code-input.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,26 @@ var codeInput = {
620620
this.classList.add("code-input_registered"); // Remove register message
621621
if (this.templateObject.preElementStyled) this.classList.add("code-input_pre-element-styled");
622622

623-
this.pluginEvt("beforeElementsAdded");
624-
625623
const fallbackTextarea = this.querySelector("textarea[data-code-input-fallback]");
624+
let fallbackFocused = false;
625+
let fallbackSelectionStart = undefined;
626+
let fallbackSelectionEnd = undefined;
627+
let fallbackSelectionDirection = undefined;
628+
let fallbackScrollLeft = undefined;
629+
let fallbackScrollTop = undefined;
630+
if(fallbackTextarea) {
631+
// Move some attributes to new textarea so typing during
632+
// slow load not interrupted
633+
if(fallbackTextarea === document.activeElement) { // Thanks to https://stackoverflow.com/a/36430896
634+
fallbackFocused = true;
635+
}
636+
fallbackSelectionStart = fallbackTextarea.selectionStart;
637+
fallbackSelectionEnd = fallbackTextarea.selectionEnd;
638+
fallbackSelectionDirection = fallbackTextarea.selectionDirection;
639+
fallbackScrollLeft = fallbackTextarea.scrollLeft;
640+
fallbackScrollTop = fallbackTextarea.scrollTop;
641+
}
642+
626643
let value;
627644
if(fallbackTextarea) {
628645
// Fallback textarea exists
@@ -638,11 +655,15 @@ var codeInput = {
638655
}
639656
// Sync value
640657
value = fallbackTextarea.value;
658+
// Backwards compatibility with plugins
659+
this.innerHTML = this.escapeHtml(value);
641660
} else {
642661
value = this.unescapeHtml(this.innerHTML);
643662
}
644663
value = value || this.getAttribute("value") || "";
645664

665+
this.pluginEvt("beforeElementsAdded");
666+
646667
// First-time attribute sync
647668
const lang = this.getAttribute("language") || this.getAttribute("lang");
648669
const placeholder = this.getAttribute("placeholder") || lang || "";
@@ -740,6 +761,18 @@ var codeInput = {
740761
this.dispatchEvent(new CustomEvent("code-input_load"));
741762

742763
this.value = value;
764+
765+
// Update with fallback textarea's state so can keep editing
766+
// if loaded slowly
767+
if(fallbackSelectionStart !== undefined) {
768+
console.log("sel", fallbackSelectionStart, fallbackSelectionEnd, fallbackSelectionDirection, "scr", fallbackScrollTop, fallbackScrollLeft, "foc", fallbackFocused);
769+
textarea.setSelectionRange(fallbackSelectionStart, fallbackSelectionEnd, fallbackSelectionDirection);
770+
textarea.scrollTo(fallbackScrollTop, fallbackScrollLeft);
771+
}
772+
if(fallbackFocused) {
773+
textarea.focus();
774+
}
775+
743776
this.animateFrame();
744777

745778
const resizeObserver = new ResizeObserver((elements) => {

0 commit comments

Comments
 (0)