Weird behavior in displaying textContent when there's overflow - javascript

I am making a Calculator App and there I am noticing a weird glitch. When I enter "1-1111...." and the moment it overflows the display div width, the text in the div element jumps down to only "1-", whereas if I inspect the textContent for div element its still "1-1111....".
To see for yourself just enter 1 then minus sign and then keep entering 1's untill the display overflows. You will see what I am taking about. View in FullScreen
Also this happens only with minus sign try inserting plus sign instead of minus it will work fine.
//Selectors
let numbers = document.querySelectorAll(".numbers")
let operators = document.querySelectorAll(".operators")
let equalto = document.querySelector(".equalto")
let clear = document.querySelector(".clear")
let backspace = document.querySelector(".backspace")
let plusMinus = document.querySelector(".plus-minus")
let dot = document.querySelector(".dot")
let display = document.querySelector(".display")
let output = document.querySelector(".output")
let equaltoPressed = false;
//Event Listeners
for(let i=0; i<numbers.length; i++){
numbers[i].addEventListener("click", function(){
if (equaltoPressed){
display.textContent = "";
equaltoPressed = false;
}
//if condition so that if the display has "Infinity" on it, we don't append digits
if ("0123456789.+-×÷".includes(display.textContent[display.textContent.length-1]) || display.textContent == "")
display.textContent += this.textContent;
evaluate();
})
}
for(let i=0; i<operators.length; i++){
operators[i].addEventListener("click", function(){
equaltoPressed = false;
if ("+-×÷".includes(display.textContent[display.textContent.length-1]))
display.textContent = display.textContent.substring(0,display.textContent.length-1) + this.textContent;
else
display.textContent += this.textContent;
})
}
equalto.addEventListener("click", function(){
if (output.textContent !== ""){
display.textContent = output.textContent;
output.textContent = "";
equaltoPressed = true;
}
});
clear.addEventListener("click", function(){
equaltoPressed = false;
display.textContent = "";
output.textContent = "";
})
backspace.addEventListener("click", function(){
equaltoPressed = false;
display.textContent = display.textContent.substr(0,display.textContent.length-1);
evaluate();
})
plusMinus.addEventListener("click", function(){
equaltoPressed = false;
let expression = display.textContent;
let flag = true;
for (let i=expression.length-1; i>=0; i--){
if ("+-×÷".includes(expression[i])){
if (expression[i] !== "-")
expression = expression.substring(0,i+1) + "-" + expression.substring(i+1,expression.length);
else if ("+-×÷".includes(expression[i-1]) || i-1<0)
expression = expression.substring(0,i) + expression.substring(i+1,expression.length);
else
expression = expression.substring(0,i) + "+" + expression.substring(i+1,expression.length);
flag = false;
break;
}
}
if (flag)
expression = "-"+expression;
display.textContent = expression;
evaluate();
})
dot.addEventListener("click", function(){
if (equaltoPressed)
display.textContent = "";
let start = 0;
for (let i=display.textContent.length-1; i>=0; i--){
if("+-×÷".includes(display.textContent[i])){
start = i+1;
break;
}
}
if (!display.textContent.substring(start,display.textContent.length).includes("."))
display.textContent += ".";
})
//Functions
function evaluate(){
let expression = display.textContent;
for (let i=0; i<expression.length; i++){
if (expression[i] === "×")
expression = expression.substring(0,i) + "*" + expression.substring(i+1,expression.length);
if (expression[i] === "÷")
expression = expression.substring(0,i) + "/" + expression.substring(i+1,expression.length);
}
if("0123456789.".includes(expression[expression.length-1]) && eval(expression) != expression)
output.textContent = eval(expression);
else
output.textContent = "";
}
*{
border:0;
margin:0;
}
body{
height: 100vh;
background: black;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: arial;
font-size: 1.5rem;
color: #f8f8f8;
}
.row{
display: flex;
}
.light-grey{
display: flex;
align-items: center;
justify-content: center;
background-color: #a6a6a6;
height: 4.2rem;
width: 4.2rem;
border-radius: 50%;
margin: .4rem;
cursor: pointer;
color: black;
}
.dark-grey{
display: flex;
align-items: center;
justify-content: center;
background-color: #333333;
height: 4.2rem;
width: 4.2rem;
border-radius: 50%;
margin: .4rem;
cursor: pointer;
}
.yellow{
display: flex;
align-items: center;
justify-content: center;
background-color: #ff9501;
height: 4.2rem;
width: 4.2rem;
border-radius: 50%;
margin: .4rem;
cursor: pointer;
}
#zero{
width: 9.2rem;
border-radius:0 50px 50px 0;
border-top-right-radius: 50px;
border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
border-top-left-radius: 50px;
}
.display{
width: 19.2rem;
height: 3rem;
margin: 0 .4rem 1.5rem .4rem;
text-align: right;
font-size: 3rem;
padding-bottom: 0.5rem;
overflow-y: hidden;
overflow-x: scroll;
}
.output{
width: 19.2rem;
height: 2rem;
margin: 0 .4rem 1.5rem .4rem;
text-align: right;
font-size: 2rem;
padding-bottom: 0.5rem;
overflow-y: hidden;
overflow-x: scroll;
}
i{
font-size: 1.3rem;
}
::-webkit-scrollbar {
width: 19.2rem;
height: .2rem;
}
::-webkit-scrollbar-track {
background: black;
}
::-webkit-scrollbar-thumb {
background: #333333;
}
::-webkit-scrollbar-thumb:hover {
background: #a6a6a6;
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<title>Calculator</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.0-2/css/all.min.css" integrity="sha256-46r060N2LrChLLb5zowXQ72/iKKNiw/lAmygmHExk/o=" crossorigin="anonymous" />
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="display"></div>
<div class="output"></div>
<div class="row">
<div class="light-grey clear">AC</div>
<div class="light-grey plus-minus">+/-</div>
<div class="light-grey operators">÷</div>
<div class="yellow backspace"><i class="fas fa-backspace"></i></div>
</div>
<div class="row">
<div class="dark-grey numbers">7</div>
<div class="dark-grey numbers">8</div>
<div class="dark-grey numbers">9</div>
<div class="yellow operators">×</div>
</div>
<div class="row">
<div class="dark-grey numbers">4</div>
<div class="dark-grey numbers">5</div>
<div class="dark-grey numbers">6</div>
<div class="yellow operators">-</div>
</div>
<div class="row">
<div class="dark-grey numbers">1</div>
<div class="dark-grey numbers">2</div>
<div class="dark-grey numbers">3</div>
<div class="yellow operators">+</div>
</div>
<div class="row">
<div class="dark-grey numbers" id="zero">0</div>
<div class="dark-grey dot">.</div>
<div class="yellow equalto">=</div>
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>

You should add white-space: nowrap to .display, so the text won't break with the dash.
If you change the font-size, you can see that the text is going down with the dash.

Related

trying to make a wordle game, but the letters are going up to down, instead of right to left, i don't know how to tackle it

I am making a 4x4 wordle game, and I used js to make the squares and input letters. When I input letters they go top to bottom instead of left to right and I'm not really sure how to fix it. I don't know how to modify the key events to go from the first column to the second, this is the code that deals with it, but I don't know why it isn't working, i feel like the code that is affecting it is this, but im not sure
if (col < gameWidth) {
let currsquare = document.getElementById(row.toString() + '-' + col.toString());
currsquare.innerText = e.code[3];
col++;
}
var gameHeight = 4; //number of guesses
var gameWidth = 4; //length of the word
var row = 0; //current guess (attempt #)
var col = 0; //current letter for that attempt
var gameOver = false;
var word = "RAAA";
window.onload = function() {
initialize();
};
function initialize() {
const darkModeToggle = document.getElementById("dark-mode-toggle");
darkModeToggle.addEventListener("click", () => {
document.body.classList.toggle("dark");
});
const instructionsToggle = document.getElementById("info");
const instructionsContainer = document.getElementById("instructions-container");
// Hide the instructions by default
instructionsContainer.style.display = "none";
// Show or hide the instructions when the button is clicked
instructionsToggle.addEventListener("click", () => {
if (instructionsContainer.style.display === "none") {
instructionsContainer.style.display = "block";
} else {
instructionsContainer.style.display = "none";
}
});
// Create the game board
for (let i = 0; i < gameHeight; i++) {
let row = document.createElement("div");
row.classList.add("row");
for (let j = 0; j < gameWidth; j++) {
let square = document.createElement("span");
square.id = i.toString() + "-" + j.toString();
square.classList.add("square");
square.innerText = "";
row.appendChild(square);
}
document.getElementById("board").appendChild(row);
}
// Listen for Key Press
document.addEventListener("keyup", (e) => {
if (gameOver) return;
if ("KeyA" <= e.code && e.code <= "KeyZ") {
if (col < gameWidth) {
let currsquare = document.getElementById(row.toString() + '-' + col.toString());
currsquare.innerText = e.code[3];
col++;
}
} else if (e.code == "Backspace") {
if (col > 0) {
col--;
let currsquare = document.getElementById(row.toString() + '-' + col.toString());
currsquare.innerText = "";
}
} else if (e.code == "Enter") {
update();
row += 1; // start new row
col = 0; // reset current index to 0 for new row
}
if (!gameOver && row == gameHeight) {
gameOver = true;
document.getElementById("answer").innerText = word;
}
});
}
function update() {
let correct = 0;
for (let column = 0; column < gameWidth; column++) {
let currsquare = document.getElementById(row.toString() + '-' + column.toString());
let letter = currsquare.innerText;
// Is it in the correct position?
if (word[row*gameWidth + (column % gameWidth)] == letter) {
currsquare.classList.add("correct");
correct += 1;
} // Is it in the word?
else if (word.includes(letter)) {
currsquare.classList.add("present");
} // Not in the word
else {
currsquare.classList.add("absent");
}
}
if (correct == gameWidth) {
gameOver = true;
document.getElementById("congrats").style.display = "block";
}
if (!gameOver && row == gameHeight - 1) {
gameOver = true;
document.getElementById("answer").innerText = word;
}
}
this is the updated html
<html>
<head>
<title>Wordle</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale = 1.0">
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.15.3/css/all.css" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" />
<link rel="stylesheet" href="wordle.css">
</head>
<body>
<h1 id="title">Wordle</h1>
<i id = "info" class="fas fa-info-circle"></i>
<i id="dark-mode-toggle" class="fas fa-circle"></i>
<hr>
<br>
<div id="board">
</div>
<br>
<div id="instructions-container">
<p>The goal is to guess the word </p>
</div>
<img id="congrats" src="https://res.cloudinary.com/mkf/image/upload/v1675467141/ENSF-381/labs/congrats_fkscna.gif" alt="Congratulations">
<script src="wordle.js"></script>
</html>
This is the updated css
body {
font-family: Arial, Helvetica, sans-serif;
text-align: center;
--correct:#6baa64;
--background-color:white;
--text-color:black;
color: var(--text-color);
background-color: var(--background-color);
}
body.dark{
font-family: Arial, Helvetica, sans-serif;
text-align: center;
--correct:#6baa64;
--background-color:black;
background-color: var(--background-color);
--text-color:white;
color:white;
}
hr {
width: 500px;
}
#title {
font-size: 36px;
font-weight: bold;
letter-spacing: 2px;
}
#board {
width: 350px;
height: 420px;
margin: 0 auto;
margin-top: 3px;
display: flex;
flex-wrap: wrap;
}
.square {
border: 2px solid lightgray;
width: 60px;
height: 60px;
margin: 2.5px;
color: black;
font-size: 36px;
font-weight: bold;
display: flex;
justify-content: center;
align-items: center;
}
.correct {
background-color: var(--correct);
color: white;
border-color: white;
}
.present {
background-color: #C9B458;
color: white;
border-color: white;
}
.absent {
background-color: #787C7E;
color: white;
border-color:white;
}
#congrats {
display: none;
}
#dark-mode-toggle {
position: fixed;
top: 10px;
right: 250px;
}
#question{
position: fixed;
top: 10px;
right: 200px;
}
#info{
position: fixed;
top: 10px;
right: 300px;
}
You dont need display: flex; in board but you need to add display: flex; to row
#board {
width: 350px;
height: 420px;
margin: 0 auto;
margin-top: 3px;
}
.row {
display: flex;
}

The Filter-function in my Recipe-App is not possible

I have developed a small recipe app. This one uses the edamame api for it. I have implemented a filter function which should filter by criteria like diet and health. In addition, it should also be possible to filter by calories. For this, the user specifies the maximum number of calories, if he wants to filter by calories. However, the filter function does not work. I enter the term "high protein" for the filter "health", and the term "burger" in the searchbar. But the result isn't filtered. The code looks functional to me. I hope you guys can help me out!
This is my HTML-Code:
<!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>Kitchn - Kochen leicht gemacht! </title>
<link href="styles.css" rel="stylesheet">
</head>
<body>
<main class="container">
<div style="text-align: center;">
<e style="margin: 0;" data-i18n-key="languages-title">Sprachen</e>
<div id="languages" class="grid">
<div id="de"></div>
<div id="en"></div>
</div>
<div class = "container" >
<div class = "row" id="photo"><!--collage-->
<div class="col-12" id="logo">
<img src="assets\image-removebg-preview.png" id= "food" class="row"/>
<div><p data-i18n-key="title" id="title">AppName</p></div>
</div>
</div>
</div>
<div class="row" id="search"><!--searchbar-->
<div class="col-8" id="searchbar" >
<img src = "assets\pawprint.png" id="paw"/>
<input placeholder="Vegan, etc." id="input"/>
</div>
<div class="col-2" id="button" >
<img src = "assets\paw.png" id="enter"/>
</div>
</div>
<div class ="row"id = "cards"><!--reccommedned-->
</div> <!--Filterfunktion für Kalorien etc. hier -->
<div class="row" id="filter">
<div class="col-3">
<select id="filter-select">
<option value="diet">Diät</option>
<option value="health">Gesundheit</option>
</select>
</div>
<div class="col-3">
<input type="text" id="filter-value" placeholder="Wert eingeben">
</div>
<div class="col-3">
<button id="submit" onclick="filterRecipes()">Filter anwenden</button>
</div>
<div class="col-3">
<div>Maximale Kalorien:</div>
<input type="text" id="calorie-limit" placeholder="Max. Kalorien">
</div>
</div>
</div>
<script src ="script.js"></script>
</body>
</html>
This is my JavaScript-Code:
const queryBox = document.getElementById("input");
const submit = document.getElementById("button");
submit.addEventListener("click", async function() {
const query = queryBox.value;
const recipes = await getRecipes(query);
useApiData(recipes);
});
document.addEventListener("keypress", async function(e) {
if (e.key === "Enter") {
const query = queryBox.value;
const recipes = await getRecipes(query);
useApiData(recipes);
}
});
const appId = "a59a7160";
const apiKey = "69e96203434da5104b731b2fd8a597b7";
async function getRecipes(query, from = 0, to = 8, diet = [], health = [], maxCalories = Number.POSITIVE_INFINITY) {
let url =`https://api.edamam.com/search?q=${query}&app_id=${appId}&app_key=${apiKey}&from=${from}&to=${to}`
if (diet.length) {
const dietString = diet.join(",");
url+=`&diet=${encodeURIComponent(dietString)}`
}
if (health.length) {
const healthString = health.join(",")
url+=`&health=${encodeURIComponent(healthString)}`
}
if (maxCalories !== Number.POSITIVE_INFINITY) {
url+= `&calories=${maxCalories.toString()}`
}
const response = await fetch(
url
);
const data = await response.json();
return data.hits;
}
function useApiData(data) {
const filteredRecipes = filterRecipes(data);
let toadd = "";
for (let i = 0; i < filteredRecipes.length; i++) {
let diet = "No Data Found";
if (data[i].recipe.dietLabels && Array.isArray(data[i].recipe.dietLabels) && data[i].recipe.dietLabels.length > 0) {
diet = data[i].recipe.dietLabels;
}
let health = "No restrictions";
if (data[i].recipe.healthLabels && Array.isArray(data[i].recipe.healthLabels) && data[i].recipe.healthLabels.length > 0) {
health = data[i].recipe.healthLabels;
}
toadd += `
<div class="card">
<img src="${data[i].recipe.image}" class="card-ing-top" alt="..."/>
<div class="card-body">
<h5 class="card-title">${data[i].recipe.label}</h5>
<b>Click here for full recipe! </b>
<br>
<br>
<r class = "item-data"><b>Calories: </b> <br> ${data[i].recipe.calories.toFixed(2)}</r>
<br>
<r class="item-data"><b>Diet label: </b> <br> ${diet}</r>
<br>
<r class = "item-data"><b>Health label: </b> <br> ${health}</r>
<br>
<r class = "item-data"><b>Ingredient line:</b> <br> ${data[i].recipe.ingredientLines}</r>
</div>
</div>
`
}
document.getElementById("cards").innerHTML = toadd;
}
function filterRecipes(recipes, diet = [], health = []) {
if (diet.length === 0 && health.length === 0) {
return recipes;
}
const filteredRecipes = recipes.filter((recipe) => {
if (diet.length > 0 && recipe.recipe.dietLabels) {
const dietLabels = recipe.recipe.dietLabels.map((label) => label.toLowerCase());
if (!diet.some((d) => dietLabels.includes(d))) {
return false;
}
}
if (health.length > 0 && recipe.recipe.healthLabels) {
const healthLabels = recipe.recipe.healthLabels.map((label) => label.toLowerCase());
if (!health.some((h) => healthLabels.includes(h))) {
return false;
}
}
return true;
});
return filteredRecipes;
}
//Language code
let exceeded = "You have exceeded the MONTHLY quota for Characters on your current plan, BASIC. Upgrade your plan at https://rapidapi.com/googlecloud/api/google-translate1"
const defaultLocale = navigator.language.slice(0,2)
let locale
let translations = {}
document.addEventListener("DOMContentLoaded", () => {
setLocale(defaultLocale)
bindLocaleSwitcher(defaultLocale)
})
function translateElement(element){
const key = element.getAttribute("data-i18n-key")
const translation = translations[locale][key]
element.innerText = translation
}
async function setLocale(newLocale){
if(newLocale===locale) return
const newTranslations = await fetchTranslationsFor(newLocale)
locale = newLocale
translations = newTranslations
translatePage()
}
async function fetchTranslationsFor(newLocale){
const response = await fetch(`/lang/${newLocale}.json`)
return await response.json()
}
function translatePage(){
document.querySelectorAll("[data-i18n-key]").forEach(translateElement)
}
function translateElement(element){
const key = element.getAttribute("data-i18n-key")
const translation = translations[key]
element.innerText = translation
}
function bindLocaleSwitcher(initialValue){
const switcher = document.getElementById("languages").children
for(const sw of switcher){
sw.addEventListener('click', () => {
setLocale(sw.id)
input.value = ""
results.innerHTML = ""
})
}
}
This is my CSS-Code:
#import url('https://fonts.googleapis.com/css2?family=Grand+Hotel&display=swap');
#import url('https://fonts.googleapis.com/css2?family=Montserrat:wght#500;700&display=swap');
.container{
background-color: #FDEEDC;
}
body{
margin: 0;
padding: 0;
background-color: #FDEEDC;
}
#languages{
display: flex;
justify-content: center;
margin-bottom: 15px;
}
#languages > div{
background-repeat: no-repeat;
background-position: center;
background-size: 180%;
border-radius: 999px;
width: 30px;
height: 30px;
margin-left: 2vh;
margin-top: 2vh;
transition: all .2s;
}
#languages > div:hover{
filter: brightness(105%);
background-size: 220%;
transition: all .2s;
}
#languages > div:active{
filter: brightness(85%);
}
#de{
background: url('svg/Flag_of_Germany.svg');
}
#en{
background: url('svg/gb.svg');
}
/* TEST ende */
#photo{
background-color: #FDEEDC;
height: 50vh;
}
#search{
position: absolute;
z-index: 1;
width: 100%;
height: 78px;
align-items: center;
justify-content: center;
display: flex;
top: 0;
margin-top: 57vh;
background-color: #FDEEDC;
}
#searchbar{
background-color: #FFC3A1;
width: 70%;
height: 80px;
align-items: center;
border-radius: 60px;
margin-right: 10px;
justify-content: center;
display: flex;
}
#button{
background-color: #FDEEDC;
}
#cards{
background-color: #FDEEDC;
margin-top: 100px;
}
#food{
height: 22%;
width:22% ;
align-items: center;
justify-content: center;
display: flex;
padding-top: 7px;
}
#logo{
align-items: center;
justify-content: center;
display: flex;
margin: auto;
}
#input{
width: 90%;
font-size: 28px;
border: 0;
background-color: #FFC3A100;
color: #FDEEDC;
}
#paw{
width: 9vh;
height: 9vh;
transform: scaleX(-1);
margin-left: 15px;
margin-right: 10px;
}
#input:focus{
outline: none;
}
p{
font-family: 'Grand Hotel', cursive;
font-size: 70px;
}
r{
font-family: 'Times New Roman';
font-size: 20px;
}
e{
font-family: 'Grand Hotel', cursive;
font-size: 30px;
}
#enter{
height: 8vh;
width: 8vh;
margin-left: 1vh;
background-color: #F0997D;
border-radius: 70px;
transition: 300ms;
}
#enter:hover{
cursor: pointer;
background-color: #F2B4B4;
background-size: 220%;
transition: all .2s;
}
.card{
border-radius: 10px;
border:10px solid #F2B4B4;
width:300px;
padding: 10px;
background-color: #FFDECF;
margin: 20px;
float: left;
height: 1000px;
}
.card-ing-top{
height: 300px;
width: 300px;
object-fit: cover;
border-radius: 10px;
}
.card-title{
font-family: Montserrat;
font-size: 20px;
}
.btn{
text-decoration: none;
font-family: Montserrat;
font-weight: 400;
color: #A75D5D;
}
In my localhost, I checked the functions of my app. I entered a term like "burer" in the search bar and "high-protein" as filter for health and pressed the search button. However, the filterfunction for the search doesn't work, meaning the get doesn't work and I don't get any filtered recipes back based on my search.
It looks like your API query string is incorrect and it returns a 400 error.
For example, if you remove the last parameter (e.g. &calories=), then the response is good. Check in the documentation.

Center an image in a contenteditable div

Please before tagging the question as duplicated, I tell you, I've been searching a lot and can't find a clear answer, so it may be worth it to try to get a clear one for the year we are living, 2022.
I have this contenteditable div:
<div class="input-field" placeholder="Tell me something..." contentEditable="true"></div>
I've been able to center the text and regular emojis setting the line-height in css but when I enter an image I am using as a custom emoji it does not get centered.
<img src="img/emojis/red-circle.png" class="image-emoji">
I am adding the image to the input field with event.target after I click it from another box:
inputField.innerHTML +=
"<div class='emo'>" + event.target.outerHTML + "</div>";
But the Divs get removed by innerHTML, so it blocks me from adding display:flex; align-items: center;
And if I set display:flex; align-items: center; directly on the contenteditable I get horizontal scrolling which I do not want.
Then if I set the css to be display:flex; align-items: center; flex-direction: column; on the contenteditable the image-emojis display one on each line every time, not side by side.
Please help.
EDIT:
Following the first answer advice I tested flex-wrap:wrap; on the contenteditable which also produces horizontal scrolling on long words with no spaces and flex-wrap:nowrap; does the same.
EDIT-2:
As suggested adding break-word:break-all; works partially but now I notice another problem with display: flex; It prevents the ENTER key from adding additional lines even thought <div> <br> </div> are added to the Html, any idea?
EDIT-3
Finally not using flex box, but just line-height to align text and emojis and as per Lukas below:
.input-field img {
vertical-align: middle;
}
...aligned the image.
const emojiBox = document.querySelector(".emoji-box");
const inputField = document.querySelector(".input-field");
emojiBox.addEventListener("click", (e) => {
let emoji = null;
let isImage = null;
let emojiImage = null;
let removeBR = null;
if (e.target != e.currentTarget) {
removeBR = inputField.querySelector("br");
if (removeBR) {
removeBR.outerHTML = "";
}
if (
e.target.tagName.toLowerCase() === "img" &&
e.target.classList.value.toLowerCase() === "emoji"
)
isImage = true;
if (isImage) {
emojiImage = e.target;
} else {
emoji = e.target;
}
}
if (emoji) {
inputField.innerHTML += emoji.outerHTML;
} else if (emojiImage) {
inputField.innerHTML += emojiImage.outerHTML;
}
cursorAtTheEnd();
});
function cursorAtTheEnd() {
let sel = window.getSelection();
sel.selectAllChildren(inputField);
sel.collapseToEnd();
inputField.focus();
}
html {
font-size: 62.5%;
}
.image-emoji {
max-width: 1.8rem;
max-height: 1.8rem;
border-radius: 100%;
padding: 0;
margin: 0 0.15rem 0;
}
.input-field {
display: flex;
align-items: center;
flex-wrap: wrap;
word-break: break-all;
font-size:1.6rem;
min-height: 3rem;
max-height: 20rem;
width: 40rem;
margin: 0.5rem;
padding: 1rem 6rem 1rem 4rem;
border: 2px solid #e6e6e6;
border-radius: 0.5rem;
outline: none;
overflow-y: auto;
}
[contenteditable="true"]:empty:before {
content: attr(placeholder);
pointer-events: none;
display: block; /* For Firefox */
}
.emoji-box {
display: flex;
align-items: center;
font-size:1.6rem;
background: white;
border: 0.2rem solid #eee;
border-radius: 0.5rem;
height: 3rem;
width: 40rem;
padding: 1rem 6rem 1rem 4rem;
margin: 0.5rem;
color: #183153;
cursor: pointer;
overflow-y: auto;
}
<div class="emoji-box">
<span>🙂</span>
<img src="https://upload.wikimedia.org/wikipedia/commons/0/02/Red_Circle%28small%29.svg" class="image-emoji">
</div>
<div class="input-field" placeholder="Tell me something..." contentEditable="true"></div>
try this
const emojiBox = document.querySelector(".emoji-box");
const inputField = document.querySelector(".input-field");
let lastKeyEnter = false;
function removeBR() {
let removeBR = inputField.querySelector("br:last-of-type");
if (
removeBR &&
removeBR.previousElementSibling &&
removeBR.previousElementSibling.tagName === "BR"
) {
removeBR.remove();
}
}
inputField.onkeydown = (e) => {
if (e.keyCode === 13) {
lastKeyEnter = true;
} else if (lastKeyEnter) {
lastKeyEnter = false;
}
};
emojiBox.addEventListener("click", (e) => {
let emoji = null;
let isImage = null;
let emojiImage = null;
if (e.target != e.currentTarget) {
if (
e.target.tagName.toLowerCase() === "img" &&
e.target.classList.value.toLowerCase() === "emoji"
)
isImage = true;
if (isImage) {
emojiImage = e.target;
} else {
emoji = e.target;
}
}
let lastChild = inputField.lastChild;
if (
lastChild &&
lastChild.previousSibling &&
lastChild.previousSibling.tagName === undefined
) {
lastChild.tagName === "BR" ? lastChild.remove() : "";
}
if (emoji && emoji.tagName === "SPAN") {
lastKeyEnter ? removeBR() : "";
lastKeyEnter = false;
inputField.innerHTML += emoji.innerHTML;
} else if (emoji && emoji.tagName === "IMG") {
lastKeyEnter ? removeBR() : "";
lastKeyEnter = false;
inputField.innerHTML += emoji.outerHTML;
} else if (emojiImage) {
lastKeyEnter ? removeBR() : "";
lastKeyEnter = false;
inputField.innerHTML += emojiImage.outerHTML;
}
cursorAtTheEnd();
});
function cursorAtTheEnd() {
let sel = window.getSelection();
sel.selectAllChildren(inputField);
sel.collapseToEnd();
inputField.focus();
}
html {
font-size: 62.5%;
}
.image-emoji {
max-width: 1.8rem;
max-height: 1.8rem;
border-radius: 100%;
padding: 0;
margin: 0 0.15rem 0;
}
.input-field {
word-break: break-all;
font-size:1.6rem;
min-height: 3rem;
max-height: 20rem;
width: 40rem;
margin: 0.5rem;
padding: 1rem 6rem 1rem 4rem;
border: 2px solid #e6e6e6;
border-radius: 0.5rem;
outline: none;
overflow-y: auto;
display: inline-block;
line-height: 2rem;
}
.input-field img {
vertical-align: text-bottom;
}
[contenteditable="true"]:empty:before {
content: attr(placeholder);
pointer-events: none;
display: block; /* For Firefox */
}
.emoji-box {
display: flex;
align-items: center;
font-size:1.6rem;
background: white;
border: 0.2rem solid #eee;
border-radius: 0.5rem;
height: 3rem;
width: 40rem;
padding: 1rem 6rem 1rem 4rem;
margin: 0.5rem;
color: #183153;
cursor: pointer;
overflow-y: auto;
}
<div class="emoji-box">
<span>🙂</span>
<img src="https://upload.wikimedia.org/wikipedia/commons/0/02/Red_Circle%28small%29.svg" class="image-emoji">
</div>
<div class="input-field" placeholder="Tell me something..." contentEditable="true"></div>

Editing a specific row in a dynamic table

I've been stuck with this problem for a while now and almost got it to work, but I'm left with an issue I cannot solve or find a solution anywhere.
So I'm trying to make an application which helps users log certain data - it all works on a table, adding rows and deleting them works just fine, but I have a problem with editing them.
At the end of each row, there are 2 buttons - delete and edit.
Edit pops up a modal, which should (and it does as far as I know) display inputs with values read from a specific table row. When you do this for the first time after reloading it works fine, but afterward, if you have more than one table rows it just starts to clean up these tr's upon submitting an edit of a row.
There's clearly a problem with logic, and I just cannot solve it. Most likely it can be found in this block
Record.prototype.addRow = function(){
let newLog = document.createElement('tr');
newLog.setAttribute('id',idContainer);
idContainer++;
recordTable.appendChild(newLog);
//store values and add them to each td
let valueStorage = [this.time,this.latitude,this.longitude,this.heading,
this.speed,this.wind,this.sea,this.visibility,this.remarks];
for (let i=0; i<9;i++) {
let tableData = document.createElement('td');
newLog.appendChild(tableData);
tableData.textContent = valueStorage[i];
}
//add 2 buttons - delete and edit
let deleteBtn = document.createElement('button');
deleteBtn.setAttribute('class','new-record__delete-row-btn')
newLog.appendChild(deleteBtn);
let editBtn = document.createElement('button');
editBtn.setAttribute('class','new-record__edit-row-btn')
newLog.appendChild(editBtn);
//adding functionality to edit/delete btns
function editThisRow(e){
//on pop up display values from the edited row
let popUpHeading = document.querySelector('.new-record__popup h2');
let thisRow = e.target.parentNode;
let editStorage = [];
for(let i = 0; i < 9; i++){
editStorage.push(thisRow.childNodes[i].textContent);
}
editStorage[1]=editStorage[1].replace(/([A-Z])/,"");
editStorage[2]=editStorage[2].replace(/([A-Z])/,"");
for(let i = 0; i <8; i++){
newRecordInputs[i].value = editStorage[i];
}
remarks.value = editStorage[8];
popUpHeading.textContent = 'Edit your record!'
openNewRecordPopup();
//adding event listener to the record edit button, so that it applies changes
const recordEditBtn = document.querySelector('#edit-record')
newRecordSubmitBtn.style.display = "none";
recordEditBtn.style.display = "block";
recordEditBtn.addEventListener('click',()=>{
let thisRowTds = thisRow.childNodes;
for(let i = 0; i < 8; i++){
thisRowTds[i].textContent = newRecordInputs[i].value
}
thisRowTds[8].textContent = remarks.value;
closeNewRecordPopup();
popUpHeading.textContent = 'Fill out inputs below to make a new record';
newRecordSubmitBtn.style.display = "block";
recordEditBtn.style.display = "none";
sortRecords();
})
}
deleteBtn.addEventListener('click',()=>{
newLog.remove();
})
editBtn.addEventListener('click',editThisRow);
}
All the code needed and live example can be found on GitHub:
https://github.com/michynow/electronic-ship-log-book
https://michynow.github.io/electronic-ship-log-book/
quick note: This is not designed for mobile use, and I really would appreciate vanilla JS solutions, without lib's or frameworks.
All edit clicks keep on stacking in below button:
const recordEditBtn = document.querySelector('#edit-record')
I have changed it to have fresh event handler always like this:
let oldRecordEditBtn = document.querySelector('#edit-record')
let recordEditBtn = oldRecordEditBtn.cloneNode(true);
oldRecordEditBtn.parentNode.replaceChild(recordEditBtn, oldRecordEditBtn);
So now below snippet is working fine for your issue:
//Set ship header and type
const shipDetailsBtn = document.querySelector('.ship-details__button');
const shipDetailsClosingBtn = document.querySelector('#ship-details__popup-closing-btn');
const shipDetailsPopUp = document.querySelector('.ship-details__popup');
const shipTypeSpan = document.querySelector('#ship-type-span');
const shipNameSpan = document.querySelector('#ship-name-span');
//opening of a form
shipDetailsBtn.addEventListener('click', () => {
shipDetailsPopUp.style.visibility = "visible";
disableButtons();
})
//disabling of button operation when popup is open;
function disableButtons() {
voyageDetailsBtn.disabled = true;
newRecordBtn.disabled = true;
shipDetailsBtn.disabled = true;
}
function enableButtons() {
voyageDetailsBtn.disabled = false;
newRecordBtn.disabled = false;
shipDetailsBtn.disabled = false;
}
//closing of a form
shipDetailsClosingBtn.addEventListener('click', () => {
shipDetailsPopUp.style.visibility = "hidden";
enableButtons();
})
//pop up input selection
const shipTypeSelect = document.querySelector('#ship-type');
const shipDetailsPopUpSubmit = document.querySelector('#ship-details-submit-btn');
//Submitting of ship details
shipDetailsPopUpSubmit.addEventListener('click', () => {
shipDetailsPopUp.style.visibility = "hidden";
shipTypeSpan.textContent = shipTypeSelect.options[shipTypeSelect.selectedIndex].value + " ";
shipNameSpan.textContent = document.querySelector('#ship-name-input').value;
enableButtons();
shipDetailsBtn.textContent = "Edit ship details";
})
//date and destination pop up form
const voyageDetailsBtn = document.querySelector('.voyage-details__button');
const voyageDetailsPopUp = document.querySelector('.voyage-details__popup');
const voyageDetailsClosingBtn = document.querySelector('#voyage-details__popup-closing-btn');
voyageDetailsBtn.addEventListener('click', () => {
voyageDetailsPopUp.style.visibility = "visible";
disableButtons();
})
//Update date and destination rows
const dateSpan = document.querySelector('#date-span');
const destinationSpanFrom = document.querySelector('#dest-span__from');
const destinationSpanTo = document.querySelector('#dest-span__to');
const voyageDetailsSubmit = document.querySelector('#voyage-details__submit-btn');
const destFromInput = document.querySelector('#ship-destination-input__from');
const destToInput = document.querySelector('#ship-destination-input__to');
voyageDetailsSubmit.addEventListener('click', () => {
dateSpan.textContent = " " + document.querySelector('#date-input').value;
//prevent empty inputs on destination form
if (destFromInput.value !== "" || destToInput.value !== "") {
destinationSpanFrom.textContent = " " + destFromInput.value + ' to: ';
destinationSpanTo.textContent = destToInput.value;
voyageDetailsBtn.textContent = "Edit date and destination";
voyageDetailsPopUp.style.visibility = "hidden";
enableButtons();
} else {
alert('Please fill in voyage details!');
}
})
//remember to add a default attribute setting the current date as placeholder in date form;
//closing of a voyage details pop up
voyageDetailsClosingBtn.addEventListener('click', () => {
voyageDetailsPopUp.style.visibility = "hidden";
enableButtons();
})
//add new data pop up opening / closing
const newRecordBtn = document.querySelector('.new-record__btn');
const newRecordPopUp = document.querySelector('.new-record__popup');
const newRecordSubmitBtn = document.querySelector('#new-record__submit-btn');
const recordTable = document.querySelector('.records-table');
newRecordBtn.addEventListener('click', openNewRecordPopup);
function openNewRecordPopup() {
newRecordPopUp.style.visibility = "visible";
disableButtons();
}
const newRecordClosingBtn = document.querySelector('#new-record__popup-closing-btn');
function closeNewRecordPopup() {
newRecordPopUp.style.visibility = "hidden";
enableButtons();
}
newRecordClosingBtn.addEventListener('click', closeNewRecordPopup);
// store input values in an array, then pass it to all created td's
let newRecordInputs = document.querySelectorAll('.new-record__popup input');
let remarks = document.querySelector('textarea');
function clearInputs() {
for (let i = 0; i < newRecordInputs.length; i++) {
newRecordInputs[i].value = "";
remarks.value = "";
};
}
newRecordSubmitBtn.addEventListener('click', addRecord);
class Record {
constructor(time, latitude, longitude, heading, speed, wind, sea, visibility, remarks) {
this.time = time;
this.latitude = latitude;
this.longitude = longitude;
this.heading = heading;
this.speed = speed;
this.wind = wind;
this.sea = sea;
this.visibility = visibility
this.remarks = remarks;
this.addRow();
}
}
//set id for each row
let idContainer = 0;
Record.prototype.addRow = function() {
let newLog = document.createElement('tr');
newLog.setAttribute('id', idContainer);
idContainer++;
recordTable.appendChild(newLog);
//store values and add them to each td
let valueStorage = [this.time, this.latitude, this.longitude, this.heading,
this.speed, this.wind, this.sea, this.visibility, this.remarks
];
for (let i = 0; i < 9; i++) {
let tableData = document.createElement('td');
newLog.appendChild(tableData);
tableData.textContent = valueStorage[i];
}
//add 2 buttons - delete and edit
let deleteBtn = document.createElement('button');
deleteBtn.setAttribute('class', 'new-record__delete-row-btn')
newLog.appendChild(deleteBtn);
let editBtn = document.createElement('button');
editBtn.setAttribute('class', 'new-record__edit-row-btn')
newLog.appendChild(editBtn);
//adding functionality to edit/delete btns
let editThisRow = function(e) {
//on pop up display values from the edited row
let popUpHeading = document.querySelector('.new-record__popup h2');
let thisRow = e.target.parentNode;
let editStorage = [];
for (let i = 0; i < 9; i++) {
editStorage.push(thisRow.childNodes[i].textContent);
}
editStorage[1] = editStorage[1].replace(/([A-Z])/, "");
editStorage[2] = editStorage[2].replace(/([A-Z])/, "");
for (let i = 0; i < 8; i++) {
newRecordInputs[i].value = editStorage[i];
}
remarks.value = editStorage[8];
popUpHeading.textContent = 'Edit your record!'
openNewRecordPopup();
//adding event listener to the record edit button, so that it applies changes
let oldRecordEditBtn = document.querySelector('#edit-record')
let recordEditBtn = oldRecordEditBtn.cloneNode(true);
oldRecordEditBtn.parentNode.replaceChild(recordEditBtn, oldRecordEditBtn);
newRecordSubmitBtn.style.display = "none";
recordEditBtn.style.display = "block";
recordEditBtn.addEventListener('click', () => {
let thisRowTds = thisRow.childNodes;
for (let i = 0; i < 8; i++) {
thisRowTds[i].textContent = newRecordInputs[i].value
}
thisRowTds[8].textContent = remarks.value;
closeNewRecordPopup();
popUpHeading.textContent = 'Fill out inputs below to make a new record';
newRecordSubmitBtn.style.display = "block";
recordEditBtn.style.display = "none";
sortRecords();
})
}
deleteBtn.addEventListener('click', () => {
newLog.remove();
})
editBtn.addEventListener('click', editThisRow);
}
function addRecord() {
//selecting all input values and storing them in an object
let timeValue = document.querySelector('#new-record__UTC-time').value;
let northOrSouth = document.querySelector('.north-south');
let northOrSouthValue = northOrSouth.options[northOrSouth.selectedIndex].value;
let latitudeValue = document.querySelector('#new-record__latitude').value + " " + northOrSouthValue;
let eastOrWest = document.querySelector('.east-west');
let eastOrWestValue = eastOrWest.options[eastOrWest.selectedIndex].value;
let longitudeValue = document.querySelector('#new-record__longitude').value + " " + eastOrWestValue;
let headingValue = document.querySelector('#new-record__heading').value;
let speedValue = document.querySelector('#new-record__SOG').value;
let windValue = document.querySelector('#new-record__wind-force').value;
let seaValue = document.querySelector('#new-record__sea-state').value;
let visibilityValue = document.querySelector('#new-record__visibility').value;
let anotherRecord = new Record(timeValue, latitudeValue, longitudeValue,
headingValue, speedValue, windValue, seaValue, visibilityValue, remarks.value);
closeNewRecordPopup();
clearInputs();
sortRecords();
}
//function for sorting out table rows by time dynamically upon edit or new record
function sortRecords() {
let rows, switching, i, x, y, shouldSwitch;
switching = true
while (switching) {
switching = false;
rows = recordTable.rows;
for (i = 2; i < (rows.length - 1); i++) {
shouldSwitch = false;
x = rows[i].getElementsByTagName("td")[0];
y = rows[i + 1].getElementsByTagName("td")[0];
if (x.textContent > y.textContent) {
shouldSwitch = true;
break;
}
}
if (shouldSwitch) {
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
}
}
}
body {
z-index: 0;
padding-top: 2vh;
/*height: 100vh;
width: 100vw;*/
/*overflow: hidden;*/
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-family: 'Montserrat', sans-serif;
font-size: 14px;
background: -webkit-gradient(linear, left top, left bottom, color-stop(50%, white), to(#347deb));
background: linear-gradient(to bottom, white 50%, #347deb);
position: relative;
}
header {
text-align: center;
color: black;
}
header p,
header .destination {
text-align: left;
padding-left: 5vw;
font-weight: bold;
}
.records-table-container {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
width: 90vw;
height: 60vh;
margin: auto;
overflow-x: auto;
background-color: #faf6c3;
-webkit-box-shadow: 0px -1px 22px -3px rgba(0, 0, 0, 0.75);
box-shadow: 0px -1px 22px -3px rgba(0, 0, 0, 0.75);
}
.records-table-container .new-record__delete-row-btn,
.records-table-container .new-record__edit-row-btn {
padding: 0.3rem;
width: 60px;
margin: 0.1rem;
color: white;
font-weight: bold;
border: none;
cursor: pointer;
background-color: #963c2c;
-webkit-transition: 0.3s all;
transition: 0.3s all;
}
.records-table-container .new-record__delete-row-btn:hover,
.records-table-container .new-record__edit-row-btn:hover {
background-color: #803325;
}
.records-table-container .new-record__delete-row-btn::after,
.records-table-container .new-record__edit-row-btn::after {
content: "Delete";
}
.records-table-container .new-record__edit-row-btn {
background-color: #5a51d6;
}
.records-table-container .new-record__edit-row-btn::after {
content: "Edit";
}
.records-table-container .new-record__edit-row-btn:hover {
background-color: #4f47bf;
}
.records-table-container table,
.records-table-container th,
.records-table-container td,
.records-table-container tr {
border: 1px solid black;
padding: 5px 2px;
border-collapse: collapse;
text-align: center;
}
.records-table-container .table__input-general-description {
width: 40vw;
}
.operation-buttons {
text-align: center;
padding: 5vh;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-ms-flex-pack: distribute;
justify-content: space-around;
}
.operation-buttons .new-record__btn {
border: none;
background-color: #4fa867;
color: white;
font-weight: bold;
padding: 10px;
-webkit-transition: background 0.3s;
transition: background 0.3s;
}
.operation-buttons .new-record__btn:hover {
background-color: #3f8a53;
cursor: pointer;
}
.operation-buttons .export-button {
border: none;
background-color: #963c2c;
color: white;
font-weight: bold;
padding: 10px;
-webkit-transition: background 0.3s;
transition: background 0.3s;
}
.operation-buttons .export-button:hover {
background-color: #803325;
cursor: pointer;
}
.operation-buttons .ship-details__button {
border: none;
background-color: #5a51d6;
color: white;
font-weight: bold;
padding: 10px;
-webkit-transition: background 0.3s;
transition: background 0.3s;
}
.operation-buttons .ship-details__button:hover {
background-color: #4f47bf;
cursor: pointer;
}
.operation-buttons .voyage-details__button {
border: none;
background-color: #88b33e;
color: white;
font-weight: bold;
padding: 10px;
-webkit-transition: background 0.3s;
transition: background 0.3s;
}
.operation-buttons .voyage-details__button:hover {
background-color: #739636;
cursor: pointer;
}
.ship-details__popup {
display: block;
visibility: hidden;
z-index: 9;
position: absolute;
top: 25%;
left: 20%;
width: 60vw;
background-color: lightgrey;
text-align: center;
padding: 1rem;
border: 1px solid black;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.ship-details__popup #ship-details__popup-closing-btn {
height: 20px;
width: 20px;
background-color: darkred;
color: white;
text-align: center;
font-weight: bold;
position: absolute;
right: 20px;
cursor: pointer;
border: 2px solid black;
}
.ship-details__popup form {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
width: 40%;
min-height: 25vh;
margin: 0 auto;
line-height: 1.5rem;
}
.ship-details__popup form input {
text-align: center;
}
.ship-details__popup select {
text-align-last: center;
padding: 0.1rem;
}
.ship-details__popup #ship-details-submit-btn {
border: none;
background-color: #31508f;
color: white;
font-weight: bold;
padding: 10px;
-webkit-transition: background 0.3s;
transition: background 0.3s;
}
.ship-details__popup #ship-details-submit-btn:hover {
background-color: darkred;
cursor: pointer;
}
.voyage-details__popup {
display: block;
visibility: hidden;
z-index: 9;
position: absolute;
top: 25%;
left: 20%;
width: 60vw;
background-color: lightgrey;
text-align: center;
padding: 1rem;
border: 1px solid black;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.voyage-details__popup form {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
width: 40%;
min-height: 25vh;
margin: 0 auto;
line-height: 1.5rem;
}
.voyage-details__popup form input {
text-align: center;
}
.voyage-details__popup #date-input {
padding-left: 15%;
cursor: pointer;
}
.voyage-details__popup #voyage-details__popup-closing-btn {
height: 20px;
width: 20px;
background-color: darkred;
color: white;
text-align: center;
font-weight: bold;
position: absolute;
right: 20px;
cursor: pointer;
border: 2px solid black;
}
.voyage-details__popup #voyage-details__submit-btn {
border: none;
background-color: #31508f;
color: white;
font-weight: bold;
padding: 10px;
-webkit-transition: background 0.3s;
transition: background 0.3s;
}
.voyage-details__popup #voyage-details__submit-btn:hover {
background-color: darkred;
cursor: pointer;
}
.new-record__popup {
display: block;
visibility: hidden;
z-index: 9;
position: absolute;
top: 25%;
left: 20%;
width: 60vw;
background-color: lightgrey;
text-align: center;
padding: 1rem;
border: 1px solid black;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
top: 15%;
margin: auto;
}
.new-record__popup form {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
width: 40%;
min-height: 25vh;
margin: 0 auto;
line-height: 1.5rem;
}
.new-record__popup form input {
text-align: center;
}
.new-record__popup #new-record__popup-closing-btn {
height: 20px;
width: 20px;
background-color: darkred;
color: white;
text-align: center;
font-weight: bold;
position: absolute;
right: 20px;
cursor: pointer;
border: 2px solid black;
}
.new-record__popup #new-record__submit-btn {
border: none;
background-color: #31508f;
color: white;
font-weight: bold;
padding: 10px;
-webkit-transition: background 0.3s;
transition: background 0.3s;
width: 40%;
margin: auto;
}
.new-record__popup #new-record__submit-btn:hover {
background-color: darkred;
cursor: pointer;
}
.new-record__popup #edit-record {
border: none;
background-color: #31508f;
color: white;
font-weight: bold;
padding: 10px;
-webkit-transition: background 0.3s;
transition: background 0.3s;
width: 40%;
margin: auto;
display: none;
}
.new-record__popup #edit-record:hover {
background-color: darkred;
cursor: pointer;
}
.new-record__popup form {
width: auto;
display: -ms-grid;
display: grid;
-ms-grid-columns: 1fr 1fr;
grid-template-columns: 1fr 1fr;
grid-gap: 0.8rem;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
line-height: 1.5rem;
padding-bottom: 2rem;
}
.new-record__popup form #new-record__remarks {
resize: none;
height: 3rem;
padding: 0.2rem;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your ship's log book.</title>
<meta name="description" content="Electronic log book of your ship">
<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
</head>
<body>
<header>
<h1><span id="ship-type-span"></span><span id="ship-name-span">Ship's name</span> logbook</h1>
<div class="date-destination-div">
<p>Date:<span id="date-span"></span></p>
<p>
Voyage from: <span id="dest-span__from"></span><span id="dest-span__to"></span>
</p>
</div>
</header>
<div class="records-table-container">
<table class="records-table" sortable>
<thead>
<tr class=table__input-general>
<th colspan="5">Voyage details</th>
<th colspan="3">Weather conditions</th>
<th class="table__input-general-description" rowspan="2">General description / comments</th>
<th class="actions" rowspan="2">Edit / delete record</th>
</tr>
<tr class="table__input-details">
<td>Time <br> UTC</td>
<td>Latitude <br> [° , ']</td>
<td>Longitude <br> [° , ']</td>
<td>Heading <br> [°]</td>
<td>SOG <br>[kt]</td>
<!-- weather conditions -->
<td>Wind force</td>
<td>Sea state</td>
<td>Visibility</td>
</tr>
</thead>
</table>
</div>
<div class="operation-buttons">
<button class="new-record__btn">
Add new record
</button>
<button class="voyage-details__button">
Enter date and destination
</button>
<button class="ship-details__button">
Set ship's details
</button>
<button class="export-button">
Export to PDF
</button>
</div>
<div class="ship-details__popup">
<div id="ship-details__popup-closing-btn">X</div><br>
<h2>Enter your ship's name and type</h2>
<form>
<label for="ship-type">Select your ship's type</label>
<!-- Selection of ship type - to be modified upon submit -->
<select name="ship-type" id="ship-type">
<option value="M/V">Motor Vessel</option>
<option value="M/T">Motor Tanker</option>
<option value="S/V">Sailing Vessel</option>
<option value="S/Y">Sailing Yacht</option>
<option value="OSV">Offshore Support Vessel</option>
<option value="DSV">Dive Support Vessel</option>
<option value="PSV">Platform Supply Vessel</option>
<option value="SOV">Service Operation Vessel</option>
<option value="Tug">Tugboat</option>
</select>
<label for="ship-name">Enter your ship's name:</label>
<input type="text" id="ship-name-input" placeholder="Enter your ship's name here" required><br>
<button type="button" id="ship-details-submit-btn">Submit</button>
</form>
</div>
<!-- Pop up with date setting and destination -->
<div class="voyage-details__popup">
<div id="voyage-details__popup-closing-btn">X</div><br>
<h2>Fill out inputs below to update voyage details</h2>
<form>
<label for="date">Enter date:</label>
<input type="date" id="date-input" name="date" value="" min="2018-01-01" max="2021-01-01">
<label for="destination">Enter your last port of call:</label>
<input type="text" id="ship-destination-input__from" placeholder="Enter your last port of call">
<label for="destination">Enter your current destination:</label>
<input type="text" id="ship-destination-input__to" placeholder="Enter your current destination"><br>
<button type="button" id="voyage-details__submit-btn">Submit</button>
</form>
</div>
<!--New record pop up-->
<div class="new-record__popup">
<div id="new-record__popup-closing-btn">X</div><br>
<h2>Fill out inputs below to make a new record</h2>
<form autocomplete="off">
<label for="UTC-time">UTC Time </label>
<input type="text" name="UTC-time" placeholder="Enter time of the record" id="new-record__UTC-time">
<label for="latitude">Latitude [° , '] </label>
<div class="latitude-container">
<input type="text" name="latitude" placeholder="Enter latitude" id="new-record__latitude">
<select class="north-south">
<option value="N">N</option>
<option value="S">S</option>
</select>
</div>
<label for="longitude">Longitude [° , '] </label>
<div class="longitude-container">
<input type="text" name="longitude" placeholder="Enter longitude" id="new-record__longitude" title="Degrees and minutes">
<select class="east-west">
<option value="E">E</option>
<option value="W">W</option>
</select>
</div>
<label for="heading">Heading [°] </label>
<input type="text" name="heading" placeholder="Enter your heading" id="new-record__heading">
<label for="SOG">Speed Over Ground [kt] </label>
<input type="number" name="SOG" placeholder="Enter your speed" min="-5" max="40" id="new-record__SOG">
<label for="wind-force">Wind Force [B] </label>
<input type="number" name="wind-force" placeholder="Enter wind force" min="0" max="12" id="new-record__wind-force">
<label for="sea-state">Sea State </label>
<input type="number" name="sea-state" placeholder="Enter sea state" min="0" max="9" id="new-record__sea-state">
<label for="visibility">Visibility</label>
<input type="text" name="visibility" placeholder="Enter visibility" id="new-record__visibility">
<label for="remarks">General remarks </label>
<textarea name="remarks" name="remarks" id="new-record__remarks" placeholder="Add remarks..."></textarea>
</form>
<button type="button" id="new-record__submit-btn">Submit record</button>
<button type="button" id="edit-record">Edit record</button>
</div>
</body>
</html>

How to create a webpage that shows a number with increment,decrement buttons and that counts down from the NUmber to zero?

I want to make a website with HTML, JAvascript and CSS,
There will be a number showing in the screen. THe user can decrement or increment the preset value using buttons.Start /stop button will start counting down from the shown number to zero. The page shows an alertbox when the number reaches zero. I know only html and css basics can anybody helpThis is a rough sketch
This may help get you started:
var intvl;
var valueContainer = document.getElementById("value");
document.getElementById("decrement").addEventListener("click", function(e){
var value = +valueContainer.textContent;
if(value){
valueContainer.textContent = value - 1;
}
});
document.getElementById("increment").addEventListener("click", function(e){
var value = +valueContainer.textContent;
valueContainer.textContent = value + 1;
});
document.getElementById("toggle").addEventListener("click", function(e){
if(intvl){
clearInterval(intvl);
} else {
var curr = +valueContainer.textContent;
intvl = setInterval(function(){
if(curr){
valueContainer.textContent = --curr;
} else {
clearInterval(intvl);
document.getElementById("messages").innerHTML = "Alert<br/>----------------<br/>Count reached 0!";
}
}, 1000);
}
});
document.getElementById("reset").addEventListener("click", function(e){
clearInterval(intvl);
valueContainer.textContent = 25;
document.getElementById("messages").innerHTML = "";
});
#messages {
text-align: center;
border: 1px solid grey;
width: 80%;
margin-bottom: 50px;
}
#wrapper {
text-align: center;
border: 1px solid grey;
display: inline-block;
width: 40%;
padding: 2px;
}
#wrapper > div {
display: inline-block;
}
body {
text-align: center;
}
#main > button, #controls > button {
border: 1px solid grey;
border-radius: 5px;
background-color: inherit;
padding: 2px 10px;
}
#controls {
margin-top: 10px;
}
<div id="wrapper">
<div id="messages">
</div>
<div id="main">
<button id="decrement">-</button>
<span id="value">25</span>
<button id="increment">+</button>
</div><br/>
<div id="controls">
<button id="toggle">Start/Stop</button>
<button id="reset">Reset</button>
</div>
</div>

Categories

Resources