Capturing return key in contenteditable div - javascript

I'm building a programmable calculator that uses a contenteditable div as a place to enter the expression you need evaluated. The div listens for the user to strike the return key, then passes its text content to the calculator engine, clears itself, and then displays the result of the expression.
Everything works as expected on desktop browsers, but under mobile browsers, there is some strange behaviour when the return key is pressed when the caret is not at the end of the text. Sometimes hitting the return key will insert a space or newline, sometimes it will submit and clear everything before the caret, and under Chrome it seems to create a new div element. Any ideas what I'm doing wrong?
I have successfully tested the code in Firefox 59.0.2 and Chromium 65.0.3325.181 running on Ubuntu 17.10, and Firefox 59.0.2 running on Windows 7. I have unsuccessfully tested the code in Firefox 59.0.2 and Chrome 65.0.3325.109 running on Android 8.1.0.
window.addEventListener("load", function () {
"use strict";
var i = document.getElementById("i");
var o = document.getElementById("o");
i.addEventListener("keypress", function (e) {
if (e.key === "Enter") {
e.preventDefault();
o.textContent = i.textContent;
i.textContent = "";
return false;
}
return true;
});
});
div {
font-size: 24px;
padding: 1em;
border: 1px solid black;
min-height: 1em;
box-sizing: content-box;
margin: 1em;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=0">
<title>Test</title>
</head>
<body>
<div id="i" contenteditable="true"></div>
<div id="o"></div>
</body>
</html>
EDIT:
After some work, I've made an alternate method of detecting input, copying the text, and clearing the box. It no longer listens for keystrokes but watches for changes in the box itself. It works on desktop but fails in similar ways on mobile. It also has the added problem that it will crash Firefox mobile if you type too quickly. I've tested the code on the same browsers as before.
window.addEventListener("load", function () {
"use strict";
var i = document.getElementById("i");
var o = document.getElementById("o");
var getText;
var input;
getText = function (e) {
var s = [];
e.childNodes.forEach(function (n) { // get every child
switch (n.nodeType) {
case 1: // element, so recurse
s.push(getText(n));
break;
case 3: // text
s.push(n.nodeValue);
break;
}
});
return s.join("");
};
input = function (e) {
if (i.childNodes.length > 1 || (i.firstChild && i.firstChild.nodeType != 3)) { // checking for added <br />
e.preventDefault();
o.textContent = getText(i);
while (i.firstChild) { // clear element
i.removeChild(i.firstChild);
}
// add and remove listener to prevent event from firing on clear
i.removeEventListener("input", input);
setTimeout(function () {
i.addEventListener("input", input, true);
}, 100);
return false;
}
return true;
};
i.addEventListener("input", input, true);
});
div {
font-size: 24px;
padding: 1em;
border: 1px solid black;
min-height: 1em;
box-sizing: content-box;
margin: 1em;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=0">
<title>Test</title>
</head>
<body>
<div id="i" contenteditable="true"></div>
<div id="o"></div>
</body>
</html>
EDIT 2 (with workaround):
After some thinking, I realized I don't need to use a contenteditable div, so I've re-worked it to use a styled text input field which works properly.
window.addEventListener("load", function () {
"use strict";
var f = document.getElementById("f");
var i = document.getElementById("i");
var o = document.getElementById("o");
f.addEventListener("submit", function (e) {
e.preventDefault();
o.textContent = i.value;
i.value = "";
return false;
});
});
input[type="text"] {
display: block;
width: 100%;
overflow: auto;
outline: none;
border: none;
border-radius: 0;
box-shadow: none;
box-sizing: content-box;
}
#i, div {
width: calc(100% - 4em - 2px);
min-height: 1em;
font-size: 24px;
padding: 1em;
border: 1px solid black;
min-height: 1em;
margin: 1em;
color: black;
font-family: serif;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=0">
<title>Test</title>
</head>
<body>
<form id="f" name="f">
<input id="i" name="i" type="text" >
</form>
<div id="o"></div>
</body>
</html>

Related

Localstorage - rewrite from JS to Jquery

I'm working on a portfolio project - which should use jquery - part of the task is to set and get text via localstorage - which I can do in Javascript but I breaks when attempting to refactor in jquery.
I found an elegantly simple javascript codepen, which has all the features I want. But when I refactor into jquery it loses funtionality - I can't save the text to local storage (I get null) and I can't copy the text to a different Div.
This is the HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Local Test</title>
</head>
<body>
<div class="content-output"></div>
<textarea class="content-input" placeholder="Your text here"></textarea>
<button class="save-button">Save</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="./script.js"></script>
</body>
</html>
This is simple CSS from the JS code pen:
* {
font-size: 16px;
font-family: sans-serif;
}
body {
padding: 1rem;
font-family: sans-serif;
}
.content-output {
float: left;
box-sizing: border-box;
background: #f9f9f9;
padding: 0.5rem;
width: calc(50% - 1rem);
height: 10rem;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
color: #202020;
}
.content-input {
float: left;
box-sizing: border-box;
margin-left: 2rem;
padding: 0.5rem;
width: calc(50% - 1rem);
height: 10rem;
border: 1px solid #505050;
resize: none;
}
.save-button {
/* -webkit-appearance: none; */
border: 0;
background: #0088ff;
padding: 0.5rem 1rem;
border-radius: 3px;
color: #fff;
margin-top: 1rem;
float: right;
cursor: pointer;
}
Here is the JS which works:
var input_textarea = document.querySelector(".content-input");
var output_div = document.querySelector(".content-output");
var save_button = document.querySelector(".save-button");
save_button.addEventListener("click", updateOutput);
output = localStorage.getItem("content");
input = localStorage.getItem("content");
console.log(output);
output_div.textContent = output;
function updateOutput() {
console.log("clicked button");
localStorage.setItem("content", input_textarea.value);
output_div.textContent = input_textarea.value;
}
And here is the jquery which doesn't work:
var input_textarea = $(".content-input");
var output_div = $(".content-output");
var save_button = $(".save-button");
save_button.on("click", updateOutput);
output_div.textContent = localStorage.getItem("content");
input_textarea.value = localStorage.getItem(("content"));
function updateOutput(event) {
event.preventDefault();
localStorage.setItem("content", input_textarea.value);
output_div.textContent = input_textarea.value;
}
I'm running out of ideas and searches - probably a typo but I cant find it . I've tried text() which was the advice 6 years ago. JSON.stringify and parse don't help because it's just a string.
I'm hoping someone has done some refactoring and spots the differences - I've even run this in the console but I can only add the text to localstorage manually: localstorage.setItem('content', 'help')
Thanks in advance
The problem is that you are trying to select a array, get the value of that array, and output to another array. I think jquery does that when you select a class, (because there could be more than one of them). Simple solution to this..
var input_textarea = $(".content-input")[0];
console.log(input_textarea)
var output_div = $(".content-output")[0];
var save_button = $(".save-button");
save_button.on("click", updateOutput);
output_div.textContent = localStorage.getItem("content");
input_textarea.value = localStorage.getItem(("content"));
function updateOutput(event) {
console.log('hello')
event.preventDefault();
localStorage.setItem("content", input_textarea.value);
output_div.textContent = input_textarea.value;
}
Found it: val() to set and text() to get.
var input_textarea = $(".content-input");
var output_div = $(".content-output");
var save_button = $(".save-button");
save_button.on("click", updateOutput);
// input_textarea.value = localStorage.getItem(("content"));
function updateOutput(event) {
event.preventDefault();
localStorage.setItem("content", input_textarea.val());
output_div.text(localStorage.getItem("content"));
}
this post helped: How to save the value of textarea to localstorage then display it in the same textarea

How to show and hide text on click of a button using JS event listener

const faqData = [
{
id: 1,
question: "Who are we?",
answer:
"We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators.",
}
];
let accordianBody = document.querySelector('h1');
function createFaq() {
// creating & adding all the FAQ's
let firstQuery = document.createElement('h3');
firstQuery.textContent = faqData[0].question;
accordianBody.appendChild(firstQuery).className = "faq";
// creating "+" sign to the FAQ header
let plusOne = document.createElement('span');
// adding plus sign to the FAQ header
plusOne.textContent = "+";
firstQuery.appendChild(plusOne).className = "show_btn";
// Adding addEventListener & displaying the answers.
plusOne.addEventListener('click', answerFirst);
function answerFirst() {
let ans1 = document.createElement('p');
ans1.textContent = faqData[0].answer;
plusOne.appendChild(ans1);
}
}
createFaq();
.faq {
width: 100%;
background-color: #4caf50;
border-radius: 8px;
margin: 0em 0em 1.4em;
padding: 0.7em 1.4em;
}
.faq .show_btn {
width: 24px;
height: 24px;
background-color: black;
outline: none;
box-shadow: none;
border: none;
color: white;
margin: 0em;
border-radius: 120px;
cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Accordion</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="accordian_body">
<h1>MY FAQ's</h1>
</div>
<script id="faq-js" src="faq.js"></script>
</body>
</html>
I am new to Javascript development so please excuse me for the beginner-level question.
I want to show some text on the click of the button and hide it on the next click and keep toggling it as many times a user clicks it without changing my HTML.
Below is my code. I have achieved how to show the text but on the next click instead of hiding it the text is keep on adding.
const faqData = [
{
id: 1,
question: "Who are we?",
answer:
"We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators.",
}
];
let accordianBody = document.querySelector('h1');
function createFaq() {
// creating & adding all the FAQ's
let firstQuery = document.createElement('h3');
firstQuery.textContent = faqData[0].question;
accordianBody.appendChild(firstQuery).className = "faq";
// creating "+" sign to the FAQ header
let plusOne = document.createElement('span');
// adding plus sign to the FAQ header
plusOne.textContent = "+";
firstQuery.appendChild(plusOne).className = "show_btn";
// Adding addEventListener & displaying the answers.
plusOne.addEventListener('click', answerFirst);
function answerFirst() {
let ans1 = document.createElement('p');
ans1.textContent = faqData[0].answer;
plusOne.appendChild(ans1);
}
}
createFaq();
const faqData = [
{
id: 1,
question: "Who are we?",
answer:
"We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators.",
}
];
let accordianBody = document.querySelector('h1');
function createFaq() {
// creating & adding all the FAQ's
let firstQuery = document.createElement('h3');
firstQuery.textContent = faqData[0].question;
accordianBody.appendChild(firstQuery).className = "faq";
// creating "+" sign to the FAQ header
let plusOne = document.createElement('span');
// adding plus sign to the FAQ header
plusOne.textContent = "+";
firstQuery.appendChild(plusOne).className = "show_btn";
// Adding addEventListener & displaying the answers.
plusOne.addEventListener('click', answerFirst);
function answerFirst() {
let ans1 = document.createElement('p');
ans1.textContent = faqData[0].answer;
plusOne.appendChild(ans1);
}
}
createFaq();
.faq {
width: 100%;
background-color: #4caf50;
border-radius: 8px;
margin: 0em 0em 1.4em;
padding: 0.7em 1.4em;
}
.faq .show_btn {
width: 24px;
height: 24px;
background-color: black;
outline: none;
box-shadow: none;
border: none;
color: white;
margin: 0em;
border-radius: 120px;
cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Accordion</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="accordian_body">
<h1>MY FAQ's</h1>
</div>
<script id="faq-js" src="faq.js"></script>
</body>
</html>
And below is my small HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Accordion</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="accordian_body">
<h1>MY FAQ's</h1>
</div>
<script id="faq-js" src="faq.js"></script>
</body>
</html>
Please help me out and thanks in advance.
What you did wrong?
you added the answer in a span instead of next after to the question. (create problem when you want to change the content of hide show button + to -)
You added the answer to the DOM (HTML) by dynamically.
you had put your question and answer in <h1> tag.
you added your firstAnswer() function in the createFaq() function.
In faqData[] there is no need for an id in each question because the index of array can be used as their ids.
What's the logic?
The accordion adds the question and answer to the DOM (HTML) at same time not when user click to show the answer. The difference is only that the answers are hidden by adding style display: none to the <p> element as default. And when user clicked on button to show the answer the class active with styling display: block is added to the element <p>. That's all about accordion.
I had just fixed "adding more answers instead of hiding it on a click". I don't recommend you use this code. But this one is for your understanding. So, this snippet had same logic for only one question.
const faqData = [{
id: 1,
question: "Who are we?",
answer: "We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators."
}];
let accordianBody = document.querySelector('h1');
function createFaq() {
// creating & adding all the FAQ's
let firstQuery = document.createElement('h3');
firstQuery.textContent = faqData[0].question;
accordianBody.appendChild(firstQuery).className = "faq";
// creating "+" sign to the FAQ header
let plusOne = document.createElement('span');
// adding plus sign to the FAQ header
plusOne.textContent = "+";
firstQuery.appendChild(plusOne).className = "show_btn";
// Adding addEventListener & displaying the answers.
//plusOne.addEventListener('click', answerFirst);
//function answerFirst() {
let ans1 = document.createElement('p');
ans1.textContent = faqData[0].answer;
plusOne.appendChild(ans1);
//}
}
createFaq();
const showHideBtn = document.querySelector(".show_btn");
showHideBtn.addEventListener('click', showHideAnswer);
function showHideAnswer() {
const question = document.querySelector(".faq span.show_btn p");
question.classList.toggle("active");
}
.faq {
width: 100%;
background-color: #4caf50;
border-radius: 8px;
margin: 0em 0em 1.4em;
padding: 0.7em 1.4em;
}
.faq .show_btn {
width: 24px;
height: 24px;
background-color: black;
outline: none;
box-shadow: none;
border: none;
color: white;
margin: 0em;
border-radius: 120px;
cursor: pointer;
}
.show_btn p{
display: none;
}
.show_btn .active {
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Accordion</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="accordian_body">
<h1>MY FAQ's</h1>
</div>
<script id="faq-js" src="faq.js"></script>
</body>
</html>
For multiple FAQ
I rearranged the code by renaming the variables and fixing wrong append of the elements such as answer to the <span> tag. I recommend you use this code not above because it have almost all issues discussed above. In this code you just have to add questions and answers to the faqData[]
const faqData = [
{
question: "Who are we?",
answer: "We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators."
},
{
question: "Lorem Ipsum?",
answer: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed elementum malesuada tortor, in pharetra nisl gravida at."
}
]
// We are not adding question and answer into this heading any more.
let accordianBody = document.querySelector('h1');
function createFaq(question, answer) {
// Edited - Renaming firstQuery to faqQuestion, ans1 to faqAnswer, plusOne to showHideBtn
// Edited - Now appending faqQuestion, and faqAnswer to faqContainer
let faqContainer = document.createElement('div');
faqContainer.className = "faq-container"
// creating & adding all the FAQ's
let faqQuestion = document.createElement('h3');
faqQuestion.textContent = question;
faqContainer.appendChild(faqQuestion).className = "faq";
// creating "+" sign to the FAQ header
let showHideBtn = document.createElement('span');
// adding plus sign to the FAQ header
showHideBtn.textContent = "+";
faqQuestion.appendChild(showHideBtn).className = "show_btn";
// Adding addEventListener & displaying the answers.
//plusOne.addEventListener('click', answerFirst);
//function answerFirst() {
let faqAnswer = document.createElement('p');
faqAnswer.textContent = answer;
faqContainer.appendChild(faqAnswer);
//}
// Edited - append faq question next after to the heading not inside it
let accordionBody = document.querySelector(".accordian_body");
accordionBody.appendChild(faqContainer);
}
for (let i = 0; i < faqData.length; i++) {
// Passing values to the function to display the FAQs
createFaq(faqData[i].question, faqData[i].answer)
}
// This one can also be done with forEach or for-of loop like that
// for (const iterator of faqData) {
// createFaq(faqData[i].question, faqData[i].answer)
// }
const showHideBtn = document.querySelectorAll(".faq-container .show_btn");
// This will ahow and hide the specific answer;
for (let i = 0; i < showHideBtn.length; i++) {
const btn = showHideBtn[i];
// You can also a seprate function like another but there is only two lines of code we want for this function
btn.addEventListener("click", function () {
let answer = document.querySelectorAll(".faq-container p");
// This will add/remove the class to hide/show the answer
answer[i].classList.toggle("active");
// This one is for changing the content of hide show button
if (answer[i].classList.contains("active")) {
btn.textContent = "-";
}
else {
btn.textContent = "+";
}
});
};
.faq-container {
width: 100%;
background-color: #4caf50;
border-radius: 8px;
margin: 0em 0em 1.4em;
padding: 0.7em 1.4em;
}
.faq-container .show_btn {
padding: 5px 10px;
width: 24px;
height: 24px;
background-color: black;
outline: none;
box-shadow: none;
border: none;
color: white;
margin: 0em;
border-radius: 120px;
cursor: pointer;
}
.faq-container p {
display: none;
}
.faq-container .active {
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Accordion</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="accordian_body">
<h1>MY FAQ's</h1>
</div>
<script id="faq-js" src="faq.js"></script>
</body>
</html>
I think you can add extra data of boolean type to event listener which changes on each click that will solve your issue.
Like:
onClick(if(b is true)
{let x = hide;
then b = false;
return;
}
else if(b is false){
let x = show;
then b =true;
return;
}
This way toggling will be ensured.
It works for me.

Trying to make a light bulb using HTML & CSS & JS

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3 Circle</title>
<style>
body {background: black;}
.container {display: flex;}
.circle {
width: 500px;
height: 500px;
-webkit-border-radius: 250px;
-moz-border-radius: 250px;
border-radius: 250px;
background: white;
}
.active {
background: yellow !important;
color: red;
}
</style>
</head>
<body>
<section class="container">
<button class="circle circle1">Circle1</button>
<button class="circle circle2">Circle2</button>
<button class="circle circle3">Circle3</button>
</section>
<script>
let cir1 = document.querySelector('.circle1')
let cir2 = document.querySelector('.circle2')
let cir3 = document.querySelector('.circle3')
let allCircle = document.querySelectorAll('.circle');
cir1.addEventListener('onClick', onButton1Click);
cir2.addEventListener('onClick', onButton2Click);
cir3.addEventListener('onClick', onButton3Click);
function onButton1Click() {
if (cir1.classList.contains("active")) {
allCircle.classList.remove('active');
} else {
allCircle.classList.remove('active');
cir1.classList.add('active');
}
}
function onButton2Click() {
if (cir2.classList.contains("active")) {
allCircle.classList.remove('active');
} else {
allCircle.classList.remove('active');
cir2.classList.add('active');
}
}
function onButton3Click() {
if (cir3.classList.contains("active")) {
allCircle.classList.remove('active');
} else {
allCircle.classList.remove('active');
cir3.classList.add('active');
}
}
</script>
</body>
</html>
I am trying to make 3 light bulbs represented by circles using HTML & CSS.
So if I turn one light bulb on using the button, the other ones should turn off using the addeventlistener. I can't find ways to make the light bulb turn yellow. Is there anything I am doing wrong? I looked for typos but I can't find any.
A few small things need to changed here.
The event type to be passed to the addEventListener is 'click' rather than 'onClick'.
The variable allCircle returns a list of dom nodes and not a single dom node. So it is essentially a []. Hence properties and methods that are available on a dom node are not accessible on the variable. What you can rather do is write a loop to access each element of the array and then modify their classes one by one
Might also suggest you to put debugger inside your code to see what is happening line by line. This article by Google should help you on using the Chrome dev tools.
This is my first answer on Stack Overflow.
let cir1 = document.querySelector('.circle1')
let cir2 = document.querySelector('.circle2')
let cir3 = document.querySelector('.circle3')
cir1.addEventListener('click', onButton1Click);
cir2.addEventListener('click', onButton2Click);
cir3.addEventListener('click', onButton3Click);
function removeActive() {
cir1.classList.remove('active');
cir2.classList.remove('active');
cir3.classList.remove('active');
}
function onButton1Click() {
removeActive();
cir1.classList.add('active');
}
function onButton2Click() {
removeActive();
cir2.classList.add('active');
}
function onButton3Click() {
removeActive();
cir3.classList.add('active');
}
body {
background: black;
}
.container {
display: flex;
align-items: flex-start;
}
.circle {
width: 100px;
height: 100px;
max-height: 100px;
-webkit-border-radius: 250px;
-moz-border-radius: 250px;
border-radius: 250px;
background: white;
}
.active {
background: yellow !important;
color: red;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3 Circle</title>
</head>
<body>
<section class="container">
<button class="circle circle1">Circle1</button>
<button class="circle circle2">Circle2</button>
<button class="circle circle3">Circle3</button>
</section>
</body>
</html>
There seem to be two issues here.
When adding an event listener for a click event, it must be called with click that is to be passed as the first parameter to the listener, but you've added onClick
querySelectorAll returns a HTMLCollection. So classList will not be a valid property on it. You might want to loop through the elements from allCircles to remove the class.
I've modified the listener and corrected the classist related fix for the first button here https://jsfiddle.net/gr33nw1zard/y7f5wnda/
should be click event, not 'onClick'.
cir1.addEventListener('click', onButton1Click);
Created one common function for all 3 buttons. onClick event is not available in plain javascript, it's the click that is the correct keyword here. Also, you have to iterate over allCircle's object or use getElementsByClass. This will work for you!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3 Circle</title>
<style>
body {
background: black;
}
.container {
display: flex;
}
.circle {
width: 500px;
height: 500px;
-webkit-border-radius: 250px;
-moz-border-radius: 250px;
border-radius: 250px;
background: white;
}
.active {
background: yellow !important;
color: red;
}
</style>
</head>
<body>
<section class="container">
<button class="circle circle1">Circle1</button>
<button class="circle circle2">Circle2</button>
<button class="circle circle3">Circle3</button>
</section>
<script>
let cir1 = document.querySelector('.circle1')
let cir2 = document.querySelector('.circle2')
let cir3 = document.querySelector('.circle3')
let allCircle = document.querySelectorAll('.circle');
cir1.addEventListener('click', onButtonClick);
cir2.addEventListener('click', onButtonClick);
cir3.addEventListener('click', onButtonClick);
function onButtonClick(e) {
const cir = e.toElement;
if (cir.classList.contains("active")) {
Object.keys(allCircle).map(circle => allCircle[circle].classList.remove('active'));
} else {
Object.keys(allCircle).map(circle => allCircle[circle].classList.remove('active'));
cir.classList.add('active');
}
}
</script>
</body>
</html>
The onClick should be edited to click

Why is my Writable Div InnerHTML length wrong on Safari?

I have been developing a chat room User Interface and I have a question.
In my UI I am using a div as my textbox and have a max message length of 500. There is a counter to show how many characters you have left, like '245/500'. On Google, this works fine but on safari, if you type one letter then delete it the counter goes from 1 to 4 and not 1 to 0. This also breaks my placeholder for the div.
Your help is much appreciated.
Here is some example code, clone it, then run it in Safari then try Google.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<title>HTML Stuff</title>
<style>
#text-div {
width: 200px;
padding: 10px;
max-height: 50px;
background-color: rgb(197, 226, 252);
overflow-y: scroll;
overflow-x: hidden;
}
#text-div:empty:before {
content: attr(data-placeholder);
color: rgb(102, 101, 101);
}
#counter {
font-weight: bolder;
font-size: 50px;
}
</style>
</head>
<body>
<div id="text-div" contenteditable="true" data-placeholder="This is a Placeholder"></div>
<div id="counter">0</div>
</body>
<script>
var text = document.getElementById('text-div')
var counter = document.getElementById('counter')
$('#text-div').on('input', () => {
counter.innerHTML = text.innerHTML.length
})
</script>
</html>
Using element.innerHTML will return the contents + the characters "&", "<", ">" as HTML entities "&", "<" and ">" - MDN
Use element.innerText.length to get consistent results about the length of ONLY the contents!
var text = document.getElementById('text-div')
var counter = document.getElementById('counter')
$('#text-div').on('input', () => {
counter.innerText = text.innerText.length - 1
})
Check the documentation!

material refresh click event not working

i use this plugin material-refresh to refresh page it's working fine but when the page is scrolled at the top "TOP = 0" click wont fire and when i scroll it down by 1px it's work normally here an image enplane the problem better
Here the test code
var opts_stream = {
nav: '.page_header',
scrollEl: '.page_content',
onBegin: function() {
console.log("start");
},
onEnd: function() {
console.log("Done");
}
};
mRefresh(opts_stream);
.page_header {
width: 100%;
height: 100px;
background-color: red;
text-align: center;
}
.page_content {
width: 100%;
height: 1200px;
background-color: rgb(190, 190, 190);
text-align: center;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>sdasd</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<link href="https://github.com/lightningtgc/material-refresh/blob/master/src/css/material-refresh.styl">
<script src="https://raw.githubusercontent.com/lightningtgc/material-refresh/master/src/js/main.js"></script>
</head>
<body>
<div class="page_header">
Header
</div>
<div class="page_content">
<button type="button" name="button" onclick="alert('test');">Test Button</button>
</div>
</body>
</html>
NOTE : You need to run browser in mobile mood from chrome console to get this plugin to run
in line 304 in touchEnd function in material-refresh.js remove e.preventDefault();
:)

Categories