I'm making a vertical bar that counts the number of rows as the rows are created. There are 2 ways to count rows: The first way is to press a key (addEventListener("keydown") to create a row. This happens correctly. The other way, which is what i need for the question, is to directly display all the line numbers as soon as i open the web page.
PROBLEM. The problem is that the number of rows is not displayed as soon as i open the web page. For example, if i have the text in 3 lines, as soon as i open the web page only 1 line is detected. Instead, I would like it to be displayed directly when I open the web page that there are 3 rows. The problem looks like this:
WHAT I WOULD LIKE. I would like to achieve this while also being able to count the rows by pressing a button (as I already do in the code), but I don't want to encounter a conflict between the two ways. I would like to get this as soon as i open the web page (without pressing any buttons):
How can i achieve this? I'm using this, but it doesn't work (I'm new to Javascript, sorry):
//VIEW DIRECTLY (WITHOUT PRESSING A BUTTON)
const start2 = textarea.selectionStart;
const end2 = textarea.selectionEnd;
textarea.value =
textarea.value.substring(0, start2) +
"\t" +
textarea.value.substring(end2);
Complete code:
const textarea = document.querySelector("textarea");
const numbers = document.querySelector(".numbers");
//WHEN I PRESS KEY
textarea.addEventListener("keyup", (e) => {
const num = e.target.value.split("\n").length;
numbers.innerHTML = Array(num).fill("<span></span>").join("");
});
textarea.addEventListener("keydown", (event) => {
if (event.key === "Tab") {
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
textarea.value =
textarea.value.substring(0, start) +
"\t" +
textarea.value.substring(end);
event.preventDefault();
}
})
//VIEW DIRECTLY (WITHOUT PRESSING A BUTTON)
const start2 = textarea.selectionStart;
const end2 = textarea.selectionEnd;
textarea.value =
textarea.value.substring(0, start2) +
"\t" +
textarea.value.substring(end2);
.editor {
display: inline-grid;
grid-template-columns: 3em auto;
gap: 10px;
line-height: 21px;
border-radius: 2px;
overflow-y: auto;
width: 100%; 3 schermateeeeeeeeeeeeeeee */
}
.editor>* {
padding-top: 10px;
padding-bottom: 10px;
}
.numbers {
text-align: right;
background: #333;
padding-right: 5px;
height: 150px;
}
.numbers span {
counter-increment: linenumber;
}
.numbers span::before {
content: counter(linenumber);
display: block;
color: #888;
}
textarea {
line-height: 21px;
border: 0;
background: transparent;
color: #fff;
min-width: 500px;
outline: none;
resize: none;
padding-right: 10px;
}
textarea::placeholder{
color: red;
}
textarea{
background-color: black;
color: green;
}
<div class="code-area editor">
<div class="numbers">
<span></span>
</div>
<textarea id="htmlCode" placeholder="HTML" placeholder="PROVA" wrap="off">Test 1
Test 2
Test 3</textarea>
</div>
</div>
Here's a better suggestion
There's three functions that you need to use accordingly for every editable parent element, the updateLineNumbers
, tabToSpaces
and updateTextareaHeight
functions.
The line numbers should also adjust if you rezize the app window.
Also, see the improved CSS styles
const updateLineNumbers = (elEditor) => {
const elNumbers = elEditor.querySelector(".numbers");
const elTextarea = elEditor.querySelector(".textarea");
const scrollHeight = elTextarea.offsetHeight;
const lineHeight = parseFloat(getComputedStyle(elTextarea).lineHeight);
const totLines = Math.floor(scrollHeight / lineHeight);
elNumbers.innerHTML = "<span></span>".repeat(totLines);
};
const tabToSpaces = (evt) => {
if (evt.key !== "Tab") return;
evt.preventDefault(); // this will prevent us from tabbing out of the editor
const spaces = " ".repeat(4);
document.execCommand("insertHTML", false, spaces);
};
const updateTextareaHeight = (elTextarea) => {
elTextarea.style.height = 0;
elTextarea.style.height = elTextarea.scrollHeight + "px";
};
const makeEditor = (elEditor) => {
const elTextarea = elEditor.querySelector(".textarea");
elTextarea.addEventListener("keydown", (evt) => {
tabToSpaces(evt);
});
elTextarea.addEventListener("input", (evt) => {
updateTextareaHeight(elTextarea);
updateLineNumbers(elEditor);
});
addEventListener("resize", () => {
updateTextareaHeight(elTextarea);
updateLineNumbers(elEditor);
}, true);
updateTextareaHeight(elTextarea);
updateLineNumbers(elEditor);
};
// Init for multiple .editor elements!
document.querySelectorAll("[data-editor]").forEach(makeEditor);
*,
*::after,
*::before {
margin: 0;
box-sizing: border-box;
}
body {
font: 1em/1.4 sans-serif;
}
[data-editor] {
display: flex;
grid-template-columns: 3em auto;
overflow-y: auto;
height: 6rem;
background: hsl(200 20% 10%);
white-space: pre-wrap;
font: normal normal 14px/1.4 monospace;
.textarea,
.numbers {
/* inherit font size from parent */
display: inline-block;
font: inherit;
height: max-content;
padding: 0.5rem;
border: 0;
outline: 0;
background: #0000;
overflow: hidden;
resize: none;
}
.textarea {
flex: 1;
[data-editor="html"] & {
color: hsl(200 70% 60%);
}
[data-editor="css"] & {
color: hsl(070 70% 60%);
}
}
.numbers {
text-align: right;
display: flex;
flex-direction: column;
border-right: 1px solid hsl(200 90% 90% / 0.2);
min-height: 100%;
}
.numbers span {
counter-increment: linenumber;
&::before {
content: counter(linenumber);
color: hsl(200 70% 90%);
}
}
}
<h3>HTML</h3>
<div data-editor="html">
<pre class="numbers"></pre>
<textarea class="textarea" spellcheck="false" autocorrect="off" autocapitalize="off"><h1 class="heading" title="test this" data-some='foo bar'>This is a Heading</h1>
<p>This is a paragraph.</p></textarea>
</div>
<h3>CSS</h3>
<div data-editor="css">
<pre class="numbers"></pre>
<textarea class="textarea" spellcheck="false" autocorrect="off" autocapitalize="off">body {
background: gold;
}</textarea>
</div>