Skip to content

Commit dd1fc54

Browse files
committed
Started speeding up updates using requestAnimationFrame; Ctrl+F fix still iffy
1 parent 897eb60 commit dd1fc54

File tree

5 files changed

+66
-77
lines changed

5 files changed

+66
-77
lines changed

code-input.css

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ code-input {
99
top: 0;
1010
left: 0;
1111
display: block;
12-
/* Only scroll inside elems */
13-
overflow: hidden;
12+
overflow: auto;
1413

1514
/* Normal inline styles */
1615
margin: 8px;
@@ -24,22 +23,33 @@ code-input {
2423
caret-color: darkgrey;
2524
white-space: pre;
2625
padding: 0!important; /* Use --padding */
26+
27+
display: grid;
28+
grid-template-columns: auto;
29+
grid-template-rows: auto;
2730
}
2831

29-
code-input textarea, code-input:not(.code-input_pre-element-styled) pre code, code-input.code-input_pre-element-styled pre {
30-
/* Both elements need the same text and space styling so they are directly on top of each other */
32+
33+
code-input:not(.code-input_loaded) {
3134
margin: 0px!important;
35+
margin-bottom: calc(-1 * var(--padding, 16px))!important;
3236
padding: var(--padding, 16px)!important;
3337
border: 0;
34-
width: calc(100% - var(--padding, 16px) * 2);
35-
height: calc(100% - var(--padding, 16px) * 2);
3638
}
3739

38-
code-input:not(.code-input_loaded) {
40+
code-input textarea, code-input:not(.code-input_pre-element-styled) pre code, code-input.code-input_pre-element-styled pre {
41+
/* Both elements need the same text and space styling so they are directly on top of each other */
3942
margin: 0px!important;
40-
margin-bottom: calc(-1 * var(--padding, 16px))!important;
4143
padding: var(--padding, 16px)!important;
4244
border: 0;
45+
width: calc(100% - var(--padding, 16px) * 2);
46+
min-height: calc(100% - var(--padding, 16px) * 2);
47+
48+
overflow: hidden;
49+
resize: none;
50+
51+
grid-row: 1 2;
52+
grid-column: 1 2;
4353
}
4454

4555
code-input:not(.code-input_pre-element-styled) pre, code-input.code-input_pre-element-styled pre code {
@@ -96,8 +106,6 @@ code-input textarea::placeholder {
96106

97107
/* Can be scrolled */
98108
code-input textarea, code-input pre {
99-
overflow: auto!important;
100-
101109
white-space: inherit;
102110
word-spacing: normal;
103111
word-break: normal;

code-input.js

Lines changed: 43 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -513,30 +513,49 @@ var codeInput = {
513513
* the result (pre code) element, then use the template object
514514
* to syntax-highlight it. */
515515

516-
/** Update the text value to the result element, after the textarea contents have changed.
517-
* @param {string} value - The text value of the code-input element
518-
* @param {boolean} originalUpdate - Whether this update originates from the textarea's content; if so, run it first so custom updates override it.
516+
needsHighlight = false; // Just inputted
517+
needsDisableDuplicateSearching = false; // Just highlighted
518+
519+
/**
520+
* Highlight the code ASAP
519521
*/
520-
update(value) {
521-
// Prevent this from running multiple times on the same input when "value" attribute is changed,
522-
// by not running when value is already equal to the input of this (implying update has already
523-
// been run). Thank you to peterprvy for this.
524-
if (this.ignoreValueUpdate) return;
525-
526-
if(this.textareaElement == null) {
527-
this.addEventListener("code-input_load", () => { this.update(value) }); // Only run when fully loaded
528-
return;
522+
scheduleHighlight() {
523+
this.needsHighlight = true;
524+
}
525+
526+
/**
527+
* Call an animation frame
528+
*/
529+
animateFrame() {
530+
// Sync size
531+
this.textareaElement.style.height = getComputedStyle(this.preElement).height;
532+
this.textareaElement.style.width = getComputedStyle(this.preElement).width;
533+
534+
// Sync content
535+
if(this.needsHighlight) {
536+
console.log("Update");
537+
this.update();
538+
this.needsHighlight = false;
539+
this.needsDisableDuplicateSearching = true;
540+
}
541+
if(this.needsDisableDuplicateSearching && this.codeElement.querySelector("*") != null) {
542+
// Has been highlighted
543+
this.resultElementDisableSearching();
544+
this.needsDisableDuplicateSearching = false;
529545
}
530546

531-
this.ignoreValueUpdate = true;
532-
this.value = value;
533-
this.ignoreValueUpdate = false;
534-
if (this.textareaElement.value != value) this.textareaElement.value = value;
547+
window.requestAnimationFrame(this.animateFrame.bind(this));
548+
}
535549

550+
/**
551+
* Update the text value to the result element, after the textarea contents have changed.
552+
*/
553+
update() {
536554
let resultElement = this.codeElement;
555+
let value = this.value;
537556

538557
// Handle final newlines
539-
if (value[value.length - 1] == "\n") {
558+
if (value[value.length - 1] == "\n" || value.length == 0) {
540559
value += " ";
541560
}
542561

@@ -549,37 +568,6 @@ var codeInput = {
549568
else this.template.highlight(resultElement);
550569

551570
this.pluginEvt("afterHighlight");
552-
553-
if(this.template.autoDisableDuplicateSearching) {
554-
if(this.codeElement.querySelector("*") === null) {
555-
// Fix for tries-to-disable-searching-before-highlighting-possible bug:
556-
// Wait until user interaction so can expect
557-
// highlight before disabling searching
558-
let listenerKeydown = window.addEventListener("keydown", () => {
559-
this.resultElementDisableSearching();
560-
window.removeEventListener("keydown", listenerKeydown);
561-
window.removeEventListener("mousemove", listenerMousemove);
562-
});
563-
let listenerMousemove = window.addEventListener("mousemove", () => {
564-
this.resultElementDisableSearching();
565-
window.removeEventListener("keydown", listenerKeydown);
566-
window.removeEventListener("mousemove", listenerMousemove);
567-
});
568-
} else {
569-
this.resultElementDisableSearching();
570-
}
571-
}
572-
}
573-
574-
/**
575-
* Synchronise the scrolling of the textarea to the result element.
576-
*/
577-
syncScroll() {
578-
let inputElement = this.textareaElement;
579-
let resultElement = this.template.preElementStyled ? this.preElement : this.codeElement;
580-
581-
resultElement.scrollTop = inputElement.scrollTop;
582-
resultElement.scrollLeft = inputElement.scrollLeft;
583571
}
584572

585573
/**
@@ -694,8 +682,7 @@ var codeInput = {
694682
}
695683
});
696684

697-
textarea.addEventListener('input', (evt) => { textarea.parentElement.update(textarea.value); textarea.parentElement.sync_scroll(); });
698-
textarea.addEventListener('scroll', (evt) => textarea.parentElement.sync_scroll());
685+
textarea.addEventListener('input', (evt) => { this.value = this.textareaElement.value; });
699686

700687
// Save element internally
701688
this.textareaElement = textarea;
@@ -720,16 +707,10 @@ var codeInput = {
720707

721708
this.pluginEvt("afterElementsAdded");
722709

723-
this.update(value);
724-
725710
this.dispatchEvent(new CustomEvent("code-input_load"));
726-
}
727711

728-
/**
729-
* @deprecated Please use `codeInput.CodeInput.syncScroll`
730-
*/
731-
sync_scroll() {
732-
this.syncScroll();
712+
this.value = value;
713+
this.animateFrame();
733714
}
734715

735716
/**
@@ -822,7 +803,7 @@ var codeInput = {
822803
if (this.template.preElementStyled) this.classList.add("code-input_pre-element-styled");
823804
else this.classList.remove("code-input_pre-element-styled");
824805
// Syntax Highlight
825-
this.update(this.value);
806+
this.needsHighlight = true;
826807

827808
break;
828809

@@ -854,7 +835,7 @@ var codeInput = {
854835

855836
if (mainTextarea.placeholder == oldValue) mainTextarea.placeholder = newValue;
856837

857-
this.update(this.value);
838+
this.needsHighlight = true;
858839

859840
break;
860841
default:
@@ -954,7 +935,7 @@ var codeInput = {
954935
val = "";
955936
}
956937
this._value = val;
957-
this.update(val);
938+
this.needsHighlight = true;
958939
return val;
959940
}
960941

@@ -1032,7 +1013,7 @@ var codeInput = {
10321013
* Update value on form reset
10331014
*/
10341015
formResetCallback() {
1035-
this.update(this.initialValue);
1016+
this.value = this.initialValue;
10361017
};
10371018
},
10381019

plugins/debounce-update.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ codeInput.plugins.DebounceUpdate = class extends codeInput.Plugin {
2929

3030
this.debounceTimeout = window.setTimeout(() => {
3131
// Closure arrow function can take in variables like `text`
32-
this.update(text);
32+
codeInput.value = text;
3333
}, this.delayMs);
3434
}
3535

plugins/indent.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ codeInput.plugins.Indent = class extends codeInput.Plugin {
9797
inputElement.selectionEnd = selectionEndI;
9898
}
9999

100-
codeInput.update(inputElement.value);
100+
codeInput.value = inputElement.value;
101101
}
102102

103103
checkEnter(codeInput, event) {
@@ -196,10 +196,10 @@ codeInput.plugins.Indent = class extends codeInput.Plugin {
196196
let lineHeight = Number(getComputedStyle(inputElement).lineHeight.replace("px", ""));
197197
let inputHeight = Number(getComputedStyle(inputElement).height.replace("px", ""));
198198
if(currentLineI*lineHeight + lineHeight*2 + paddingTop >= inputElement.scrollTop + inputHeight) { // Cursor too far down
199-
inputElement.scrollBy(0, Number(getComputedStyle(inputElement).lineHeight.replace("px", "")))
199+
codeInput.scrollBy(0, Number(getComputedStyle(inputElement).lineHeight.replace("px", "")));
200200
}
201201

202-
codeInput.update(inputElement.value);
202+
codeInput.value = inputElement.value;
203203
}
204204

205205
checkBackspace(codeInput, event) {

plugins/special-chars.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ codeInput.plugins.SpecialChars = class extends codeInput.Plugin {
3939
/* Runs after elements are added into a `code-input` (useful for adding events to the textarea); Params: codeInput element) */
4040
afterElementsAdded(codeInput) {
4141
// For some reason, special chars aren't synced the first time - TODO is there a cleaner way to do this?
42-
setTimeout(() => { codeInput.update(codeInput.value); }, 100);
42+
setTimeout(() => { codeInput.value = codeInput.value + ""; }, 100);
4343
}
4444

4545
/* Runs after code is highlighted; Params: codeInput element) */

0 commit comments

Comments
 (0)