Keydown function runs before character is printed to screen? - javascript

I have an element that sits above 3 elements with the same class. When I type into one of the content editable divs, it expands the element if the width goes beyond its original. I want to set the above element to equal the same width as the other 3.The issue I am running into is that when I run the keydown() function, it runs before the actual character is printed to the screen, thus the width is always one character too large, or small. If I run the keyup() function then it is delayed and is clunky because the character is printed to the screen before my finger unpresses the key. How do I remedy this? Is there a way to run the function when the key is printed?
$(".tr1").keydown(function() {
var elements = document.getElementsByClassName('tr1');
var totalWidth = 0;
for (var i = 0; i < elements.length; i++) {
totalWidth += elements[i].offsetWidth;
}
document.getElementById("qa-checklist").style.width=''+totalWidth+'px';
});
I added a stackblitz:
https://js-ic8uy7.stackblitz.io

The oninput event seems to not have this issue.
<label for="test">Using oninput:</label>
<input type="text" id="test" oninput="console.log(this.value)"></input>
EDIT: To do this in your example, replace "keydown" with "input":
document.addEventListener('input', function(event) {
console.log("change");
var elements = document.getElementsByClassName('tr1');
var totalWidth = 0;
for (var i = 0; i < elements.length; i++) {
totalWidth += elements[i].offsetWidth;
}
console.log(totalWidth);
document.getElementById("qa-checklist").style.width=''+totalWidth+'px';
});
* {
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
.rowcell {
outline: grey;
border: 1px solid black;
min-width: 50px;
}
#qa-checklist {
display: inline-block;
width: 1px;
border-bottom: 50px solid black;
}
<div id="qa-checklist"></div>
<div style="display:flex;">
<div class="rowcell tr1" contenteditable="true"></div>
<div class="rowcell tr1" contenteditable="true"></div>
<div class="rowcell tr1" contenteditable="true"></div>
</div>

Related

How to add background color to text inside textbox?

I do not know how to ask this question correctly and I do not know how to find solutions in google because it leads me to how to add entire background color to a textbox which I am not looking for. I am trying to achieve such results like image below:
I want to add background to each text(of course characters) inside a input tag except spaces. User will start typing stuff inside input tag and will apply background color but spaced text won't color.
I do not have any code because I do not know how to do it using css or JS if neccesary. I just have a
<input type="text">
I think it might use only JS but I do not know how to(of course I know JS). How do I achieve that?
You can use div with contentEditable and use little js to append text as span
<div contentEditable></div>
CSS
span {
background-color: red;
margin-right: 2px;
}
div {
border: 1px solid black;
}
var el = document.querySelector("div");
el.addEventListener("blur", () => {
var content = el.textContent;
var contents = content.split(" ");
el.innerHTML = "";
contents.forEach((item) => {
el.innerHTML += `<span>${item}</span>`;
});
});
Something like this
Another method is to overlap the input box with a "mirroring" element. The overlap must be precise, both in layout and text characteristics. Here is a minimal example:
var input = document.getElementById("input"),
mirror = document.getElementById("input-mirror");
input.addEventListener("keyup", function() {
var words = input.value.split(" ").map(function(a) {
var span = document.createElement("span");
span.textContent = a;
return span;
});
mirror.innerHTML = "";
for (let i = 0; i < words.length; i++) {
mirror.append(words[i], " ");
}
});
.container {
display: grid;
}
#input,
#input-mirror {
font: inherit;
box-sizing: border-box;
margin: 0;
border: 1px solid;
padding: 0;
grid-row: 1;
grid-column: 1;
}
#input {
background: transparent;
}
#input-mirror > span {
background: #0f0;
}
<div class="container">
<span id="input-mirror"></span>
<input id="input" type="text" />
</div>

How to display row number next to each row on contenteditable div

I have a contenteditable div and I want the site to count each row of text the user has in the div similar to many coding IDEs. (Example image below to show what I mean:)
How would I go about doing this?
You can accomplish this with two container elements and a little bit of scripting:
$(document).ready(function(){
$('#edit').css('min-height', $('#edit').height());
$('#edit').html('');
var currentHeight = $('#edit').height();
var lineHeight = currentHeight;
$('#edit').keyup(function(){
if($(this).height()!=currentHeight){
currentHeight = $(this).height();
var lines = currentHeight/lineHeight;
$('#nums').html('')
for (i = 1; i < lines+1; i++) {
$('#nums').append('<span>'+i+'</span>')
}
}
});
});
#container{
border: 2px solid gray;
display: flex;
width: 200px;
}
#nums{
width: 25px;
background-color: lightgrey;
}
#nums span{
width: 100%;
display: block;
text-align: center;
}
#edit{
display: inline-block;
width: 100%;
}
#editwrapper{
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div id="nums">
<span>1</span>
</div>
<div id="editwrapper">
<div id="edit" contenteditable="true">
filler
</div>
</div>
</div>
That's not so simple, actually. If a user typed in your div and the text wrapped, JavaScript doesn't know that it wrapped; there's no row to count!
This solution is super specific, and I'll leave showing the line numbers to you:
<div contenteditable="true" id="myDiv" style="width:300px;font-family:monospace" onchange="myHandler()"></div>
<script>
const limit = 40 // number of monospace chars to fill a row
let count = 0
function myHandler (e) {
let lines = Math.ceil(e.target.value.length / limit)
if (lines !== count) {
showlines(lines) // your function to display the line #s
count = lines
}
}
</script>
Takeaway: your div should be a fixed width and you should count how many monospace chars fit within that width. Then display those lines.

Style is being added to the last child among a set of elements, instead of the last child of the selected element

var NavLinks = document.querySelectorAll('.nav-link');
var circuses = document.querySelectorAll('.circle');
for (var i = 0; i < NavLinks.length; i++) {
var navLink = NavLinks[i];
navLink.addEventListener('click', function () {
for (var i = 0; i < circuses.length; i++) {
var circle = circuses[i];
circle.style.display='none';
}
var theLastChild = navLink.lastChild;
theLastChild.style.display='block';
}
);
}
.nav-container{
height: 10px;
background: white;
padding: 30px 0px 40px 0px;
margin-left: 18%;
margin-right: 18%;
}
.nav-body ul{
text-align: right;
}
.nav-body ul li{
display: inline- block;
float: left;
margin-right: 30px;
}
#logo{
margin-right: 0px;
}
.nav-body ul li{
line-height: 0.6;
}
#logo{
margin-top: -10px;
}
#logo-light-blue{
color: #5dc5ef;
font-weight: 900;
}
#logo-dark-blue{
color: #1885c8;
font-weight: 900;
}
.circle {
display: none;
width: 8px;
height: 8px;
background: #5dc5ef;
/* -moz-border-radius: 50px;
-webkit-border-radius: 50px; */
border-radius: 4px;
margin: auto;
margin-top: 7px;
}
<header class="nav-container">
<nav class="nav-body">
<ul>
<li class="nav-link">צור קשר
<div class="circle"></div></li>
<li class="nav-link">המלצות ומאמרים
<div class="circle"></div></li>
<li class="nav-link">שאלות נפוצות
<div class="circle"></div></li>
<li class="nav-link">אודות ד"ר שי מרון אלדר
<div class="circle"></div></li>
<li class="nav-link">אודות ההליכים
<div class="circle"></div></li>
<li class="nav-link">ראשי
<div class="circle"></div></li>
<li id="logo"> <h3> <span id="logo-light-blue"> ד"ר </span><span id="logo-dark-blue"> שי מרון אלדר </span></h3><br>
<h6> פתרונות כירורגיים להשמנת יתר וניתוחים זעיר פולשניים</h6></li>
</ul>
</nav>
</header>
I need to make a blue circle under that category menu, which I pressed. But now blue circle added only to last menu category. Doesn't matter which one was pressed.
I looking for the last child of that menu category which was pressed. But it shows me every time last child of all menu categories.
What is wrong?
>
You have errors in HTML. Span tags need to be closed.
<li id="logo">
<h3>
<span id="logo-light-blue"> ד"ר </span>
<span id="logo-dark-blue"> שי מרון אלדר </span>
</h3>
<br>
<h6> פתרונות כירורגיים להשמנת יתר וניתוחים זעיר פולשניים</h6>
</li>
And Id attributes should be unique to the element, you are repeating the circle as an Id all over the place.
<div id="circle"></div></li>
It this doesn't solve it, try explaining the question better since even in the demo you have put result is all over the place. Are we missing some CSS or a style lib?
EDIT: I think I know what you wanna, is it this? Have a look at fiddle:
fiddle here
Do you need circle removed from other elements once you click your element?
If you need the circle to be only on 1 element, it needs to be removed from others.
Here is a fiddle showing that:
fiddle with only 1 circle
Difference is in:
var NavLinks = document.querySelectorAll('.nav-link');
for (var i = 0; i < NavLinks.length; i++) {
var navLink = NavLinks[i];
navLink.addEventListener('click', function (event) {
var allNavs = document.querySelectorAll('.nav-link div');
for (var it = 0; it < allNavs.length; it++){
console.log(allNavs[it]);
allNavs[it].classList.add('invisible');
allNavs[it].classList.remove('circleVisible');
}
console.log(allNavs);
var targetElement = event.target || event.srcElement;
var circleDiv = targetElement.parentNode.querySelectorAll('div');
console.log(circleDiv[0]);
circleDiv[0].classList.add('circleVisible');
circleDiv[0].classList.remove('invisible');
console.log(circleDiv[0]);
}
);
}
I have left console.logs, so you see how it works, remove them when running the code for real :)
The first big problem I see is you have nested for loops but are using the same iterator variable of i. If you are going to next the loops, you need the inner loop to have a different variable. In situations like this, I will often use ii just because it's easy.
Furthermore, you seem to be doing this in a roundabout way. I'm not entirely sure what you need, but if it is as it appears, then this solution is simpler.
CSS
.circle {
display: none;
... other attributes
}
.active-menu-item > .circle {
display: block;
}
JavaScript
var NavLinks = document.querySelectorAll('.nav-link');
for (var i = 0; i < NavLinks.length; i++) {
var navLink = NavLinks[i];
navLink.addEventListener('click', function () {
for (var ii = 0; ii < NavLinks.length; ii++) {
NavLinks[ii].classList.remove("active-menu-item");
}
navLink.classList.add("active-menu-item");
});
}

Line up generated divs horizontally

I'm creating a map generator that lets a user enter the number of rows and columns in the map, and then create that map (as divs). Everything works correctly, except the divs, instead of being in rows and columns, it's all in one big column. It does have the correct amount of tiles (for example, it has 6 if you enter 3 and 2, or 25 if you enter 5 and 5). The kicker is that if I enter divs in the regular html file, they line up like they're supposed to.
Here's my javascript function:
function createMap(rows, columns) {
var $div = $('<div></div>');
var k = 0;
while (k < rows) {
for (i = 0; i < columns; i++) {
$div.append('<div></div>');
}
$div.append('<br>');
k++;
}
$('body').empty();
$('body').append($div);
}
Here's my CSS:
div {
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
}
The generated divs are reading the CSS fine - they have the proper height, width, and border. It seems that they're just creating a new line for every one. Can anyone tell me why?
You gave ALL your divs a width of 100px. You have divs in a div. So you need to change your styles to only target the children
You want only the children divs to have the width of 100px.
function createMap(rows, columns) {
var $div = $('<div></div>');
var k = 0;
while (k < rows) {
for (i = 0; i < columns; i++) {
$div.append('<div></div>');
}
$div.append('<br>');
k++;
}
$('body').empty();
$('body').append($div);
}
createMap(2,3)
div > div {
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Float your divs
div {
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
float: left;
}

javascript chatbox / messenger script

I'm trying to write a facebook like chatbox, but i've encountered a small problem.
I'm using the following code (it's only test code, so it's not really clean):
css code:
#messenger {
position: fixed;
bottom: 0px;
right: 10px;
width: 200px;
height: 300px;
z-index: 4;
background-color: #ECECEC;
border: 1px solid #000;
}
#messenger.p {
text-align: right;
}
#contacts {
margin: 5px 5px 5px 5px;
}
#chatspace {
position: fixed;
bottom: 0px;
right: 240px;
height: 20px;
left: 20px;
background-color: #ECECEC;
border: 1px solid #000;
z-index: 4;
}
.chatbox {
position: absolute;
bottom: 0px;
width: 200px;
height: 200px;
z-index: 4;
background-color: #ECECEC;
border: 1px solid #000;
}
html/javascript code:
<script type="text/javascript">
var i = 0;
function oc_chatbox() {
if (i == 0) {
document.getElementById('contacts').style.visibility = 'hidden';
document.getElementById('messenger').style.height = '20px';
i = 1;
}
else {
document.getElementById('contacts').style.visibility = 'visible';
document.getElementById('messenger').style.height = '300px';
i = 0;
}
}
function new_chat(userid) {
var new_right;
new_right = document.getElementById('messenger').style.right;
//alert('old value: '+ new_right);
new_right += 20;
//alert('New value of right: '+ new_right);
document.getElementById('chatspace').innerHTML = '<div id="'+userid+'" class="chatbox" style="right: '+new_right+'px;"></div>';
//document.write('<div id="'+userid+'" class="chatbox" style="right: '+new_right+'px;"></div>');
}
</script>
<div id="chatspace"></div>
<div id="messenger">
<p>Collapse</p>
<div id="contacts">
<ul>
<li>contact A</li>
</ul>
</div>
</div>
the problem is, that when I try to add new chats to the chatbar, i can't seem the place them next to each other.
anyone who can help ?
EDIT:
so i changed to javascript code to:
var last = null;
function new_chat(userid) {
if(userid==null)
userid = "user666";
var new_right;
var margin = 10;
var messenger = window.last==null?document.getElementById('messenger'):window.last; //Take the messenger or the last added chat
new_right = document.body.clientWidth-messenger.offsetLeft; //Compute the window size
console.log(new_right); //Log the number
new_right += margin; //keep spaces between divs
var newChat = document.createElement("div"); //DOM create DIV
newChat.id = userid;
newChat.className = "chatbox shadow";
newChat.style.right = new_right+"px";
newChat.innerHTML = '<p>'+userid+'</p><p><textarea></textarea></p>';
window.last = newChat; //Remember whichever is last
document.body.appendChild(newChat);
}
and now it works, thanks !
You cannot get an element right offset using its style, unlest the style is set and valid. Instead you must get element.offsetLeft and size of window area and do this:
new_right = windowSize()[0]-messenger.offsetLeft;
Where window size is this function.
Here is my, working, version of your function:
var last = null;
function new_chat(userid) {
if(userid==null)
userid = "user666";
var new_right;
var margin = 20;
var messenger = window.last==null?document.getElementById('messenger'):window.last; //Take the messenger or the last added chat
new_right = windowSize()[0]-messenger.offsetLeft; //Compute the window size
console.log(new_right); //Log the number
new_right += margin; //keep spaces between divs
var newChat = document.createElement("div"); //DOM create DIV
newChat.id = userid;
newChat.className = "chatbox";
newChat.style.right = new_right+"px";
window.last = newChat; //Remember whichever is last
document.body.appendChild(newChat);
}
You may get errors if console is not defined in your brouwser. But in such case you should take a better browser. Normally, the if(console!=null) is put in code.
And here is the link.
You should try adding a float style.
.chatbox {
float: right;
}
Add that to your chatbox styles. You may need to mess around a bit to make sure the float doesn't mess with your other elements. You may need a better container for them.
If you want to get really fun, you can add .draggable() from jQuery, and you can have them snap to your chat bar. You can then change the order of your chats.

Categories