HTML/CSS/Javascript Command Line-Like Interface - javascript

I would like to create a command-line interface but I am stumped on finding the right ray to get input. I need to not allow multi-line commands but wrap the text to a newline when it reaches the end of a page. Right now I have a textarea set up to only be one line and use word-wrap and stuff, and whenever the user presses enter it sets the value of the textarea to nothing and adds the old value of the textarea to a paragraph
So basically:
What i want
User can enter as much text as they want
User can not enter multi-line text
Once user presses enter, the text gets added to a paragraph and textarea is cleared
My problem
When user presses enter the textarea gets set to no text but then
adds a newline(which i do not want)
When text is added to paragraph there is a space and newline(???) being added(maybe related to how textarea adds newline)
Maybe there is another way to do this that is better or can I just fix what I have already done?
Here is my code:
HTML
<!DOCTYPE html>
<html>
<head>
<link rel = "stylesheet" type = "text/css" href = "brdstyle.css" />
<title>BrD</title>
</head>
<script src = "brdapp.js"></script>
<body>
<div id = "background">
<div id = "console">
<p id = "consoletext">
Ispum dolor ugin hegar<br/>
dank daniel for life
</p>
<textarea rows = "1" id = "textinput" onkeydown = "checkInput();"></textarea>
</div>
</div>
</body>
</html>
CSS
* {
margin: 0px;
padding: 0px;
}
body {
background-color: rgb(0, 0, 0);
}
#background {
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
width: 100%;
height: 100%;
background-color: black;
margin: 0px;
padding: 0px;
}
#console {
margin: 0px;
padding: 0px;
}
#consoletext {
color: rgb(255, 255, 255);
font-family: Monospace;
margin: 10px 0px 0px 10px;
}
#textinput {
resize: none;
margin: 0px 0px 10px 10px;
border: none;
outline: none;
background-color: rgb(0, 0, 0);
color: rgb(255, 255, 255);
font-family: Monospace;
width: calc(100% - 20px);
overflow: hidden;
}
Javascript
function checkInput () {
var event = window.event || event.which;
if (event.keyCode == 13) {
addLine(document.getElementById("textinput").value);
document.getElementById("textinput").value = "";
}
document.getElementById("textinput").style.height = (document.getElementById("textinput").scrollHeight) + "px";
}
function addLine (line) {
var textNode = document.createTextNode(line);
document.getElementById("consoletext").appendChild(textNode);
}
If you answer this question, thank you for your help! :)

Alright, as you had multiple problems, I will break this into 2 parts:
1. Newline being added after text field is cleared. You can stop this by calling event.preventDefault() under where it recognizes the "enter" key being pressed.
function checkInput() {
var event = window.event || event.which;
if (event.keyCode == 13) {
event.preventDefault();
addLine(document.getElementById("textinput").value);
document.getElementById("textinput").value = "";
}
document.getElementById("textinput").style.height = (document.getElementById("textinput").scrollHeight) + "px";
}
function addLine(line) {
var textNode = document.createTextNode(line);
document.getElementById("consoletext").appendChild(textNode);
}
2. I was not able to replicate your newline/space error, however it may have something to do with the event not cancelling like above.
Here is the code snippet to try yourself:
function checkInput() {
var event = window.event || event.which;
if (event.keyCode == 13) {
event.preventDefault();
addLine(document.getElementById("textinput").value);
document.getElementById("textinput").value = "";
}
document.getElementById("textinput").style.height = (document.getElementById("textinput").scrollHeight) + "px";
}
function addLine(line) {
var textNode = document.createTextNode(line);
document.getElementById("consoletext").appendChild(textNode);
}
* {
margin: 0px;
padding: 0px;
}
body {
background-color: rgb(0, 0, 0);
}
#background {
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
width: 100%;
height: 100%;
background-color: black;
margin: 0px;
padding: 0px;
}
#console {
margin: 0px;
padding: 0px;
}
#consoletext {
color: rgb(255, 255, 255);
font-family: Monospace;
margin: 10px 0px 0px 10px;
}
#textinput {
resize: none;
margin: 0px 0px 10px 10px;
border: none;
outline: none;
background-color: rgb(0, 0, 0);
color: rgb(255, 255, 255);
font-family: Monospace;
width: calc(100% - 20px);
overflow: hidden;
}
<div id = "background">
<div id = "console">
<p id = "consoletext">
Ispum dolor ugin hegar<br/>
dank daniel for life
</p>
<textarea rows = "1" id = "textinput" onkeydown = "checkInput();"></textarea>
</div>
</div>

You should change the textarea element to a text input
<input type="text" id="textinput" onkeydown="checkInput();">
This should get rid of the weird newline and spaces. You should also note that there is automatically a space at the end of your original paragraph due to you adding a newline after "dank daniel for life" :).
P.S I'm still a little confused as to why you don't want the text appended on a new line because it's a terminal but good luck with whatever your doing
Hope this helps!

To prevent the newline from being added you need to call event.preventDefault() just after resetting the textarea.

Related

How to set textarea height using min-height?

I am trying to create a message input field, using textarea. The reason I am using textarea is to be able to dynamically change the height.
To be able to dynamically change the height of the textarea and the parent divs, I have implemented this code.
The code works, just fine. To be able to use this JavaScript code I have to use min-height on the textarea. The problem is that I want to set the height of the textarea to 10px but it simply doesn't want to work, when using min-height. I does somehow work when I use height, but then the JavaScript won't work.
UPDATE:
I am just trying to create a field where the user can write a message and then post it.
Currently the textarea is too tall in my opinion, there is no reason for it to be taller than needed. So i want the height to initially be 20px, and then be able to expand as the user types.
UPDATE UPDATE:
I want to know how to set the height of the textarea to 10px or 20px, but still be able to dynamically change the height when the user types, using the javascript code i have provided
Any ideas on how to solve this? Btw, I'm not very well versed in CSS.
var areaName = "finder__input";
var textarea = document.getElementById(areaName);
textarea.addEventListener("input", function() {
const textarea = document.querySelector("textarea");
const textareaHeight = textarea.clientHeight;
textarea.style.height = "auto";
textarea.style.height = textarea.scrollHeight + "px";
});
body {
color: #292929;
background-color: #616f91
}
.container {
display: flex;
flex-direction: row;
justify-content: center;
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding-bottom: 100px;
}
.finder {
border: 1px solid #fff;
background-color: #f6f5f0;
border-radius: 5px;
/* width: 722px; */
padding: 3px;
box-shadow: 2px 2px 1px black, -1px -1px 1px white;
}
.finder__outer {
position: relative;
/* width: 700px; */
border-radius: 5px;
min-height: 1px;
padding: 8px;
background-color: transparent;
box-shadow: inset 2px 2px 5px -2px black, inset -10px -10px 5px -7px white;
}
.finder__input {
border: none;
resize: none;
background-color: red;
outline: none;
font-size: 15px;
letter-spacing: 1px;
width: 100%;
font-weight: bold;
min-height: 10px;
max-height: 90px;
}
<div class="container">
<div class="finder">
<div class="finder__outer" id="finder__outer">
<textarea id="finder__input" class="finder__input" type="text" name="q" placeholder="Write a message..."></textarea>
</div>
</div>
</div>
Resize textarea height on input
This is basically similar to this jQuery related question: Resize Textarea on Input.
Here's a rewrite in vanilla JavaScript
const textareaResize = (elTextarea) => {
elTextarea.style.height = "auto";
const h = elTextarea.scrollHeight;
elTextarea.style.height = `${h}px`;
};
document.querySelectorAll(".flexheight").forEach((elTextarea) => {
elTextarea.addEventListener("input", textareaResize); // on input
textareaResize(elTextarea); // on init
});
textarea.flexheight {
resize: none;
width: 100%;
box-sizing: border-box;
font: inherit;
height: 1rem;
}
Starts small and increment height as user types: <br>
<textarea class="flexheight" placeholder="Write a message..."></textarea>
<br>
<textarea class="flexheight" placeholder="Write about yourself..."></textarea>
var areaName = "finder__input";
var textarea = document.getElementById(areaName);
textarea.addEventListener("input", function() {
const textarea = document.querySelector("textarea");
const textareaHeight = textarea.clientHeight;
//textarea.style.height = "10px";
textarea.style.minHeight = textarea.scrollHeight + "px";
});
try using minHeight

How to submit an list when one of the list item is selected

hello i am creating a search bar that has auto complete feature can someone tell how to auto submit when one of the option is selected
some other possible solutions are autosubmit when the input field contains $
{i will add a $ swmbol in each of the array}
you can check the whole program on codepen by clicking here
https://codepen.io/simplyrajatgupta/pen/wvmXPJv
here is the codes
let suggestions = [
"Channel",
"CodingLab",
"CodingNepal",
"YouTube",
"YouTuber",
"YouTube Channel",
"Blogger",
"Bollywood",
"Vlogger",
"Vechiles",
"Facebook",
"Freelancer",
"Facebook Page",
"Designer",
"Developer",
"Web Designer",
"Web Developer",
"Login Form in HTML & CSS",
"How to learn HTML & CSS",
"How to learn JavaScript",
"How to become Freelancer",
"How to become Web Designer",
"How to start Gaming Channel",
"How to start YouTube Channel",
"What does HTML stands for?",
"What does CSS stands for?",
];
// getting all required elements
const searchWrapper = document.querySelector(".search-input");
const inputBox = searchWrapper.querySelector("input");
const suggBox = searchWrapper.querySelector(".autocom-box");
const icon = searchWrapper.querySelector(".icon");
let linkTag = searchWrapper.querySelector("a");
let webLink;
// if user press any key and release
inputBox.onkeyup = (e)=>{
let userData = e.target.value; //user enetered data
let emptyArray = [];
if(userData){
icon.onclick = ()=>{
webLink = `https://www.google.com/search?q=${userData}`;
linkTag.setAttribute("href", webLink);
linkTag.click();
}
emptyArray = suggestions.filter((data)=>{
//filtering array value and user characters to lowercase and return only those words which are start with user enetered chars
return data.toLocaleLowerCase().startsWith(userData.toLocaleLowerCase());
});
emptyArray = emptyArray.map((data)=>{
// passing return data inside li tag
return data = `<li>${data}</li>`;
});
searchWrapper.classList.add("active"); //show autocomplete box
showSuggestions(emptyArray);
let allList = suggBox.querySelectorAll("li");
for (let i = 0; i < allList.length; i++) {
//adding onclick attribute in all li tag
allList[i].setAttribute("onclick", "select(this)");
}
}else{
searchWrapper.classList.remove("active"); //hide autocomplete box
}
}
function select(element){
let selectData = element.textContent;
inputBox.value = selectData;
icon.onclick = ()=>{
webLink = `https://www.google.com/search?q=${selectData}`;
linkTag.setAttribute("href", webLink);
linkTag.click();
}
searchWrapper.classList.remove("active");
}
function showSuggestions(list){
let listData;
if(!list.length){
userValue = inputBox.value;
listData = `<li>${userValue}</li>`;
}else{
listData = list.join('');
}
suggBox.innerHTML = listData;
}
#import url('https://fonts.googleapis.com/css2?family=Poppins:wght#200;300;400;500;600;700&display=swap');
*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body{
background: #644bff;
padding: 0 20px;
}
::selection{
color: #fff;
background: #664AFF;
}
.wrapper{
max-width: 450px;
margin: 150px auto;
}
.wrapper .search-input{
background: #fff;
width: 100%;
border-radius: 5px;
position: relative;
box-shadow: 0px 1px 5px 3px rgba(0,0,0,0.12);
}
.search-input input{
height: 55px;
width: 100%;
outline: none;
border: none;
border-radius: 5px;
padding: 0 60px 0 20px;
font-size: 18px;
box-shadow: 0px 1px 5px rgba(0,0,0,0.1);
}
.search-input.active input{
border-radius: 5px 5px 0 0;
}
.search-input .autocom-box{
padding: 0;
opacity: 0;
pointer-events: none;
max-height: 280px;
overflow-y: auto;
}
.search-input.active .autocom-box{
padding: 10px 8px;
opacity: 1;
pointer-events: auto;
}
.autocom-box li{
list-style: none;
padding: 8px 12px;
display: none;
width: 100%;
cursor: default;
border-radius: 3px;
}
.search-input.active .autocom-box li{
display: block;
}
.autocom-box li:hover{
background: #1bb361;
color: white;
}
.search-input .icon{
position: absolute;
right: 0px;
top: 0px;
height: 45px;
;
width: 45px;
text-align: center;
line-height: 45px;
font-size: 20px;
color: white;
cursor: pointer;
background: #1a74f2;
right: 5px;
top: 5px;
bottom: 5px;
border-radius: 5px;
}
.search-input
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Autocomplete Search Box | CodingNepal</title>
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"/>
</head>
<body>
<form action="https://www.google.com/search?q=">
<div class="wrapper">
<div class="search-input">
<a href="" target="_blank" hidden></a>
<input type="text" id="ra"placeholder="Enter question or chapter...">
<div class="autocom-box">
<!-- here list are inserted from javascript -->
</div>
<div class="icon" id="ca"type="submit"><i class="fas fa-search"></i></div>
</div>
</div>
</form>
<script src="js/suggestions.js"></script>
<script src="js/script.js"></script>
<script>
var input = document.getElementById("ra");
input.addEventListener("keypress", function(event) {
if (event.key === "Enter") {
event.preventDefault();
document.getElementsByClassName("ca").click();
}
});
</script>
</body>
</html>
Instead write code for clicking search button, you can just call window.open('http://url-goes-here.com').
inputBox.onkeydown = (e) => {
let firstSuggestion = suggestions.filter(el =>
el.toLowerCase().includes(e.target.value.toLowerCase()))[0];
if((e.keyCode == 13) && firstSuggestion)
e.preventDefault();
window.open(`https://www.google.com/search?q=${firstSuggestion}`)
}
}
This function make input that matched with first suggestion auto-submitted when enter key pressed. If you wanna use this function, make sure you delete another function that also record enter key in input.
.onkeydown make any key pressed in inputBox will be 'record'. If the key pressed is enter (enter keycode = 13) and first suggestion exist (not null), so you will be redirect to google url + first suggestion query.
firstSuggestion in here, defined as filtered suggestion list, which only include suggestion that contains character of your search query.

How do I add an X tag in a search bar

I am trying to code a website that has a search bar. Currently, I am polishing it up and adding some features to the site. One feature I want to add is an X every time someone types something into the search box and I want it to clear the text in the input. Technically I have achieved this but it does not feel so nice. I want it to act as the X at reverb.com.
Here is my version:
function deleteButton() {
var deletebtn = document.getElementById("deletebtn");
var input = document.getElementById("inputbar");
if (input.value.length >= 1) {
deletebtn.style.visibility = "visible";
deletebtn.style.cursor = "pointer";
}
}
function clearSearch() {
var input = document.getElementById("inputbar");
var deletebtn = document.getElementById("deletebtn");
deletebtn.style.visibility = "hidden";
input.value = "";
}
.exitbtn {
margin-top: 39px;
display: inline-block;
border: 1px solid rgba(0, 0, 0, 0.5);
border-left: none !important;
border-right: 1px solid rgba(0, 0, 0, 0.5) !important;
color: rgba(0, 0, 0, 0.5);
font-size: 16px;
background: none;
outline: none;
transition: 0.3s;
}
.exitbtn img {
visibility: hidden;
}
.exitbtn img:hover {
transition: 0.3s;
opacity: 1;
content: url("images/orange-delete-sign.png");
}
.delete-sign {
height: 31px;
opacity: 0.7;
display: inline-block;
}
<input type="text" name="search" value="" onkeyup="enterSearch(); deleteButton();" autocomplete="off" id="inputbar" class="searchbar" autocorrect="off" autocapitalize="off" tabindex="0">
<button onclick="clearSearch()" class="exitbtn extspacer"><img id="deletebtn" class="delete-sign" src="images/grey-delete-sign.png"></button>
I am showing my code just in case you are wanting it.
Here are some images of it working:
If you are wondering why I don't like this method, it is because when you hover over the button,
it is still there and the Reverb version completely disappears and acts like a normal text box.
Try input type="search". It is an inbuilt input type in HTML which creates a cross as soon as a character is entered in the input field.
Here's an example for the ease of understanding:
input { /* You could use a class name/id as well */
border-radius: 5px;
}
.Search-icon {
border-style: outset;
}
<input type="search" class="search" placeholder="some text"><span class="Search-icon">search</span>
If you want an 'X' you can use
×
(I would have commented this but I do not have enough SO reputation to comment)
You can easily do it with jQuery!
To form the jQuery code in a sentence:
If Input not empty = show "X".
If click on "X" input value = empty
$(".clearable").each(function() {
const $inp = $(this).find("input:text"),
$cle = $(this).find(".clearable__clear");
$inp.on("input", function(){
$cle.toggle(!!this.value);
});
$cle.on("touchstart click", function(e) {
e.preventDefault();
$inp.val("").trigger("input");
});
});
.clearable{
position: relative;
display: inline-block;
}
.clearable input[type=text]{
padding-right: 1em;
box-sizing: border-box;
}
.clearable__clear{
display: none;
position: absolute;
right:0; top:0;
padding: 0 8px;
font-style: normal;
user-select: none;
cursor: pointer;
}
.clearable input::-ms-clear { /* Remove IE default X */
display: none;
}
/*
Font Size
*/
input {
font-size: 30px;
}
.clearable__clear {
font-size: 40px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<span class="clearable">
<input type="text" placeholder="Search...">
<i class="clearable__clear">×</i>
</span>

Question on element alignment and how cursor is able to stay flush with the text in this editable code textarea?

Looking at this codepen, most of it I grok. But a couple of things I don't understand:
How does the <code> element stay perfectly on top of the <textarea>? I would expect it to be below the textarea looking at the HTML code.
How is the cursor staying so well-aligned with the text such that it functions like the type of cursor in a word document? The cursor even aligns well with the text when I copy and paste the text. Is it the emmet dependency that's helping?
Here is the code:
HTML
<div class="editor-holder">
<ul class="toolbar">
<li><i class="fa fa-indent"></i></li>
<li><i class="fa fa-expand"></i></li>
</ul>
<div class="scroller">
<textarea class="editor allow-tabs"><div class="Editable Textarea">
<h1>This is a fully editable textarea which auto highlights syntax.</h1>
<p>Type or paste any code in here...</p>
<div>
<?php
var simple = "coding";
?>
<script>
with = "Tab or double space functionality";
</script></textarea>
<pre><code class="syntax-highight html"></code></pre>
</div>
</div>
(S)CSS
html, body{
margin: 0;
padding: 0;
height: 100%;
width: 100%;
position: relative;
background: rgb(114, 195, 195);
}
.editor-holder{
width: 800px;
height: 500px;
margin-top: 50px;
border-radius: 3px;
position: relative;
top: 0;
margin-left: -400px;
left: 50%;
background: #1f1f1f !important;
overflow: auto;
box-shadow: 5px 5px 10px 0px rgba(0, 0, 0, 0.4);
transition: all 0.5s ease-in-out;
&.fullscreen{
width: 100%;
height: 100%;
margin: 0;
left: 0;
}
.toolbar{
width: 100%;
list-style: none;
position: absolute;
top: -2px;
margin: 0;
left: 0;
z-index: 3;
padding: 8px;
background: #afafaf;
li{
display: inline-block;
}
a{
line-height: 20px;
background: rgba(144, 144, 144, 0.6);
color: grey;
box-shadow: inset -1px -1px 1px 0px rgba(0,0,0,0.28);
display: block;
border-radius: 3px;
cursor: pointer;
&:hover{
background: rgba(144, 144, 144, 0.8);
}
&.active{
background: rgba(144, 144, 144, 0.8);
box-shadow: none;
}
}
i{
color: #565656;
padding: 8px;
}
}
textarea, code{
width: 100%;
height: auto;
min-height: 450px;
font-size: 14px;
border: 0;
margin: 0;
top: 46px;
left: 0;
padding: 20px !important;
line-height: 21px;
position: absolute;
font-family: Consolas,Liberation Mono,Courier,monospace;
overflow: visible;
transition: all 0.5s ease-in-out;
}
textarea{
background: transparent !important;
z-index: 2;
height: auto;
resize: none;
color: #fff;
text-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
text-fill-color: transparent;
-webkit-text-fill-color: transparent;
&::-webkit-input-placeholder{
color: rgba(255, 255, 255, 1);
}
&:focus{
outline: 0;
border: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
}
code{
z-index: 1;
}
}
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
code{
background: #1f1f1f !important;
color: #adadad;
.hljs {
color: #a9b7c6;
background: #282b2e;
display: block;
overflow-x: auto;
padding: 0.5em
}
.hljs-number,
.hljs-literal,
.hljs-symbol,
.hljs-bullet {
color: #6897BB
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-deletion {
color: #cc7832
}
.hljs-variable,
.hljs-template-variable,
.hljs-link {
color: #629755
}
.hljs-comment,
.hljs-quote {
color: #808080
}
.hljs-meta {
color: #bbb529
}
.hljs-string,
.hljs-attribute,
.hljs-addition {
color: #6A8759
}
.hljs-section,
.hljs-title,
.hljs-type {
color: #ffc66d
}
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #e8bf6a
}
.hljs-emphasis {
font-style: italic
}
.hljs-strong {
font-weight: bold
}
}
}
JavaScript
var tabCharacter = " ";
var tabOffset = 2;
$(document).on('click', '#indent', function(e){
e.preventDefault();
var self = $(this);
self.toggleClass('active');
if(self.hasClass('active'))
{
tabCharacter = "\t";
tabOffset = 1;
}
else
{
tabCharacter = " ";
tabOffset = 2;
}
})
$(document).on('click', '#fullscreen', function(e){
e.preventDefault();
var self = $(this);
self.toggleClass('active');
self.parents('.editor-holder').toggleClass('fullscreen');
});
/*------------------------------------------
Render existing code
------------------------------------------*/
$(document).on('ready', function(){
hightlightSyntax();
emmet.require('textarea').setup({
pretty_break: true,
use_tab: true
});
});
/*------------------------------------------
Capture text updates
------------------------------------------*/
$(document).on('ready load keyup keydown change', '.editor', function(){
correctTextareaHight(this);
hightlightSyntax();
});
/*------------------------------------------
Resize textarea based on content
------------------------------------------*/
function correctTextareaHight(element)
{
var self = $(element),
outerHeight = self.outerHeight(),
innerHeight = self.prop('scrollHeight'),
borderTop = parseFloat(self.css("borderTopWidth")),
borderBottom = parseFloat(self.css("borderBottomWidth")),
combinedScrollHeight = innerHeight + borderTop + borderBottom;
if(outerHeight < combinedScrollHeight )
{
self.height(combinedScrollHeight);
}
}
// function correctTextareaHight(element){
// while($(element).outerHeight() < element.scrollHeight + parseFloat($(element).css("borderTopWidth")) + parseFloat($(element).css("borderBottomWidth"))) {
// $(element).height($(element).height()+1);
// };
// }
/*------------------------------------------
Run syntax hightlighter
------------------------------------------*/
function hightlightSyntax(){
var me = $('.editor');
var content = me.val();
var codeHolder = $('code');
var escaped = escapeHtml(content);
codeHolder.html(escaped);
$('.syntax-highight').each(function(i, block) {
hljs.highlightBlock(block);
});
}
/*------------------------------------------
String html characters
------------------------------------------*/
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
/*------------------------------------------
Enable tabs in textarea
------------------------------------------*/
$(document).delegate('.allow-tabs', 'keydown', function(e) {
var keyCode = e.keyCode || e.which;
if (keyCode == 9) {
e.preventDefault();
var start = $(this).get(0).selectionStart;
var end = $(this).get(0).selectionEnd;
// set textarea value to: text before caret + tab + text after caret
$(this).val($(this).val().substring(0, start)
+ tabCharacter
+ $(this).val().substring(end));
// put caret at right position again
$(this).get(0).selectionStart =
$(this).get(0).selectionEnd = start + tabOffset;
}
});
How does code and textarea elements stay aligned?
They are aligned because in the CSS they both use the same style which outlines the positioning of both elements. They both use position: absolute and the same top and left properties so stay in the same position.
See here https://www.w3schools.com/css/css_positioning.asp
In terms of the z-axis you can see that code has a z-index of 1 while textarea has 2 so text area stays on top.
How is the cursor staying aligned with the text?
There is no javascript acting on the cursor here. If you were to have any textarea in html the cursor would align with the text.

Binding an event to a <label> without the event then firing twice

I have a <label> with an ::after pseudo-element attached to it, to which I would like to bind a click event.
<label for="my-input">
<input id="my-input" />
</label>
Since pseudo-elements are not part of the DOM, I obviously can't do that, so I have bound the click event to the <label> instead.
But... we all know what a <label> does, right? Yes, it re-focuses the cursor on the <input>.
So, well done if you've already guessed what happens - the event fires twice.
Why? Because it fires once when the user clicks on the <label> and then the browser auto-clicks on the <input> (to re-position the cursor) and that ends up firing the event a second time.
I'd be intrigued to know if there is any creative way around this.
Normally, you'd stop the event firing during the bubbling phase by changing the useCapture boolean flag at the end of .addEventListener() from false to true - but in this case that's not going to stop the event (bound to the <label>) from firing a second time, when the browser auto-clicks on the <input>.
Working Example:
var myInput = document.querySelector('label[for="my-input"]');
var clickNumber = 1;
function clickDetected(event) {
console.log('Click ' + clickNumber + ' detected');
clickNumber++;
}
myInput.addEventListener('click', clickDetected, false);
label {
position: relative;
top: 48px;
width: 200px;
height: 100px;
margin: 24px 6px;
padding: 24px;
background-color: rgb(255, 0, 0);
}
label[for="my-input"]::after {
content: '+';
position: absolute;
display: block;
top: -26px;
right: 4px;
width: 22px;
height: 22px;
color: rgb(255, 255, 255);
font-size: 21px;
line-height: 22px;
font-weight: bold;
text-align: center;
background-color: rgb(255, 0, 0);
border-radius: 2px;
box-shadow: 3px 3px 3px rgba(0, 75, 165, 0.4);
cursor: pointer;
}
<label for="my-input">
<input id="my-input" type="text" />
</label>
Do it like this:
var myInput = document.querySelector('label[for="my-input"]');
var clickNumber = 1;
function clickDetected(e) {
}
myInput.onclick = function (e) {
if (e.target.getAttribute('id') === 'label') {
console.log('Click ' + clickNumber + ' detected');
clickNumber++;
}
}
label {
position: relative;
top: 24px;
width: 200px;
height: 100px;
margin: 24px 6px;
padding: 24px;
background-color: rgb(255, 0, 0);
}
<label for="my-input" id="label">
<input id="my-input" type="text" />
</label>

Categories

Resources