Collapsible with content-dependent expanded size - javascript

I coded a collapsible button using both CSS and JS, and I would like to place a button nested inside another one.
Is it possibile to dynamically adapt the height of the first/external button so that, when the second/internal button is opened, the height of the first one is increased by the height of the second one?
Here is the code I'm working on
coll = document.getElementsByClassName("col");
conn = document.getElementsByClassName("con");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].setAttribute('data-id', 'con' + i);
conn[i].setAttribute('id', 'con' + i);
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = document.getElementById(this.getAttribute('data-id'));
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
.col {
cursor: help;
border: none;
outline: none;
background: none;
padding: 0;
font-size: 1em;
color: green;
border-bottom: 1px dashed;
transition: .3s;
}
.con {
padding: 0 18px;
margin: 3px 0;
max-height: 0;
overflow: hidden;
transition: .3s ease-out;
background-color: #f1f1f1;
box-shadow: 5px 5px 10px 3px inset rgba(0,0,0,0.60);
}
Does <button class=col>this</button> work?
<div class=con>
<p>Yes!</p>
And what about <button class=col>this</button>?
<div class=con>
<p>Yes, but below text is gone!</p>
</div>
<p>bye bye</p>
</div>
There is something to fix.
EDIT: LAZY SOLUTION
In the javascript replace content.scrollHeight with a high value such as 9999.
Drawback: when the button is opened, the transition from 0 to height starts immediately and is super fast since the space to cover is a lot; when the button is closed, the transition starts at max-height (not the actual height) so visually nothing happens from max-height to actual height, resulting in a delay.
coll = document.getElementsByClassName("col");
conn = document.getElementsByClassName("con");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].setAttribute('data-id', 'con' + i);
conn[i].setAttribute('id', 'con' + i);
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = document.getElementById(this.getAttribute('data-id'));
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = 9999 + "px";
}
});
}
.col {
cursor: help;
border: none;
outline: none;
background: none;
padding: 0;
font-size: 1em;
color: green;
border-bottom: 1px dashed;
transition: .3s;
}
.con {
padding: 0 18px;
margin: 3px 0;
max-height: 0;
overflow: hidden;
transition: .3s ease-out;
background-color: #f1f1f1;
box-shadow: 5px 5px 10px 3px inset rgba(0,0,0,0.60);
}
Does <button class=col>this</button> work?
<div class=con>
<p>Yes!</p>
And what about <button class=col>this</button>?
<div class=con>
<p>And the transition is super fast</p>
</div>
<p>Yes but there is a delay if you close it</p>
</div>
There is something to fix.
I think the true solution is in this page, but I'm not able to adapt it to my case.

No need to calculate dynamic height.
Example with button inside button
{}

Related

javascript on a webpage displaying text wrongly

I have JS code on a webpage that loads questions in from mysql db and displays the text . What happens is that it cuts off words at the end of the line and continues the word on the next line at the start. So all text across the screen starts/ends at the same point.
This seems to be the code where it displays the text.
For example the text will look like at the end of a line 'cont' and then on next line at the start 'inue'.
How do i fix this?
var questions = <?=$questions;?>;
// Initialize variables
//------------------------------------------------------------------
var tags;
var tagsClass = '';
var liTagsid = [];
var correctAns = 0;
var isscorrect = 0;
var quizPage = 1;
var currentIndex = 0;
var currentQuestion = questions[currentIndex];
var prevousQuestion;
var previousIndex = 0;
var ulTag = document.getElementsByClassName('ulclass')[0];
var button = document.getElementById('submit');
var questionTitle = document.getElementById('question');
//save class name so it can be reused easily
//if I want to change it, I have to change it one place
var classHighlight = 'selected';
// Display Answers and hightlight selected item
//------------------------------------------------------------------
function showQuestions (){
document.body.scrollTop = 0; // For Safari
document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
if (currentIndex != 0) {
// create again submit button only for next pages
ulTag.innerHTML ='';
button.innerHTML = 'Submit';
button.className = 'submit';
button.id = 'submit';
if(quizPage<=questions.length){
//update the number of questions displayed
document.getElementById('quizNumber').innerHTML = quizPage;
}
}
//Display Results in the final page
if (currentIndex == (questions.length)) {
ulTag.innerHTML = '';
document.getElementById('question').innerHTML = '';
if(button.id == 'submit'){
button.className = 'buttonload';
button.innerHTML = '<i class="fa fa-spinner fa-spin"></i>Loading';
}
showResults();
return
}
questionTitle.innerHTML = "Question No:" + quizPage + " "+currentQuestion.question.category_name +"<br/>"+ currentQuestion.question.text;
if(currentQuestion.question.filename !== ''){
var br = document.createElement('br');
questionTitle .appendChild(br);
var img = document.createElement('img');
img.src = currentQuestion.question.filename;
img.className = 'imagecenter';
img.width = 750;
img.height = 350;
questionTitle .appendChild(img);
}
// create a for loop to generate the options and display them in the page
for (var i = 0; i < currentQuestion.options.length; i++) {
// creating options
var newAns = document.createElement('li');
newAns.id = 'ans'+ (i+1);
newAns.className = "notSelected listyle";
var textAns = document.createTextNode(currentQuestion.options[i].optiontext);
newAns.appendChild(textAns);
if(currentQuestion.options[i].file !== ''){
var br = document.createElement('br');
newAns .appendChild(br);
var img1 = document.createElement('img');
img1.src = currentQuestion.options[i].file;
img1.className = 'optionimg';
img1.width = 250;
img1.height = 250;
newAns .appendChild(img1);
newAns .appendChild(br);
}
var addNewAnsHere = document.getElementById('options');
addNewAnsHere.appendChild(newAns);
}
//.click() will return the result of $('.notSelected')
var $liTags = $('.notSelected').click(function(list) {
list.preventDefault();
//run removeClass on every element
//if the elements are not static, you might want to rerun $('.notSelected')
//instead of the saved $litTags
$liTags.removeClass(classHighlight);
//add the class to the currently clicked element (this)
$(this).addClass(classHighlight);
//get id name of clicked answer
for (var i = 0; i < currentQuestion.options.length ; i++) {
// console.log(liTagsid[i]);
if($liTags[i].className == "notSelected listyle selected"){
//store information to check answer
tags = $liTags[i].id;
// tagsClass = $LiTags.className;
tagsClassName = $liTags[i];
}
}
});
//check answer once it has been submitted
button.onclick = function (){
if(button.id == 'submit'){
button.className = 'buttonload';
button.innerHTML = '<i class="fa fa-spinner fa-spin"></i>Loading';
}
setTimeout(function() { checkAnswer(); }, 100);
};
}
//self calling function
showQuestions();
The website is on my local now but i can upload a screenimage if need be and the whole code of the webpage. Or is the issue in html?
edit: here is html/css code
<style>
/*========================================================
Quiz Section
========================================================*/
/*styling quiz area*/
.main {
background-color: white;
margin: 0 auto;
margin-top: 30px;
padding: 30px;
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
/*white-space: nowrap;*/
}
/*Editing the number of questions*/
.spanclass {
font-size: x-large;
}
#pages{
border: 3px solid;
display: inline-flex;
border-radius: 0.5em;
float: right;
}
#question{
word-break: break-all;
}
/*format text*/
p {
text-align: left;
font-size: x-large;
padding: 10px 10px 0;
}
.optionimg{
border: 2px solid black;
border-radius: 1.5em;
}
/*Form area width*/
/*formatting answers*/
.listyle {
list-style-type: none;
text-align: left;
background-color: transparent;
margin: 10px 5px;
padding: 5px 10px;
border: 1px solid lightgray;
border-radius: 0.5em;
font-weight: normal;
font-size: x-large;
display: inline-grid;
width: 48%;
height: 300px;
overflow: auto;
}
.listyle:hover {
background: #ECEEF0;
cursor: pointer;
}
/*Change effect of question when the questions is selected*/
.selected, .selected:hover {
background: #FFDEAD;
}
/*change correct answer background*/
.correct, .correct:hover {
background: #9ACD32;
color: white;
}
/*change wrong answer background*/
.wrong, .wrong:hover {
background: #db3c3c;
color: white;
}
/*========================================================
Submit Button
========================================================*/
.main button {
text-transform: uppercase;
width: 20%;
border: none;
padding: 15px;
color: #FFFFFF;
}
.submit:hover, .submit:active, .submit:focus {
background: #43A047;
}
.submit {
background: #4CAF50;
min-width: 120px;
}
/*next question button*/
.next {
background: #fa994a;
min-width: 120px;
}
.next:hover, .next:active, .next:focus {
background: #e38a42;
}
.restart {
background-color:
}
/*========================================================
Results
========================================================*/
.circle{
position: relative;
margin: 0 auto;
width: 200px;
height: 200px;
background: #bdc3c7;
-webkit-border-radius: 100px;
-moz-border-radius: 100px;
border-radius: 100px;
overflow: hidden;
}
.fill{
position: absolute;
bottom: 0;
width: 100%;
height: 80%;
background: #31a2ac;
}
.score {
position: absolute;
width: 100%;
top: 1.7em;
text-align: center;
font-family: Arial, sans-serif;
color: #fff;
font-size: 40pt;
line-height: 0;
font-weight: normal;
}
.circle p {
margin: 400px;
}
/*========================================================
Confeeti Effect
========================================================*/
canvas{
position:absolute;
left:0;
top:11em;
z-index:0;
border:0px solid #000;
}
.imagecenter{
display: block;
margin: 0 auto;
}
.buttonload {
background-color: #04AA6D; /* Green background */
border: none; /* Remove borders */
color: white; /* White text */
padding: 12px 24px; /* Some padding */
font-size: 16px; /* Set a font-size */
}
/* Add a right margin to each icon */
.fa {
margin-left: -12px;
margin-right: 8px;
}
#media only screen and (max-width: 900px){
.listyle {
width: 100% !important;
height: auto !important;
}
.imagecenter {
width: 100% !important;
}
.listyle img{
width: inherit !important;
height: unset !important;
}
.ulclass
{
padding:0px !important;
}
}
</style>
<!-- Main page -->
<div class="main">
<!-- Number of Question -->
<div class="wrapper" id="pages">
<span class="spanclass" id="quizNumber">1</span><span class="spanclass">/<?=$count?></span>
</div>
<!-- Quiz Question -->
<div class="quiz-questions" id="display-area">
<p id="question"></p>
<ul class="ulclass" id="options">
</ul>
<div id="quiz-results" class="text-center">
<button type="button" name="button" class="submit" id="submit">Submit</button>
</div>
</div>
</div>
<canvas id="canvas"></canvas>
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
I'm guessing that #question{ word-break: break-all; } is probably the culprit then? –
CB..yes that fixed it:)

How make a textarea with tags in react that have clickable dropdown

Id like to make a component in react that allows me to have a textarea with tags that can be inserted when clicked from a dropdown. Id also like this textarea to be able to mix text aswell. I have currently been trying to use tagify with react but I cant seem to figure out a way to the tagify's function that adds the tag to be accessed by the onClick that is connected to the dropdown.
Any ideas?
I believe you can get your answer in this URL of other question asked on StackOverflow https://stackoverflow.com/a/38119725/15405352
var $container = $('.container');
var $backdrop = $('.backdrop');
var $highlights = $('.highlights');
var $textarea = $('textarea');
var $toggle = $('button');
// yeah, browser sniffing sucks, but there are browser-specific quirks to handle that are not a matter of feature detection
var ua = window.navigator.userAgent.toLowerCase();
var isIE = !!ua.match(/msie|trident\/7|edge/);
var isWinPhone = ua.indexOf('windows phone') !== -1;
var isIOS = !isWinPhone && !!ua.match(/ipad|iphone|ipod/);
function applyHighlights(text) {
text = text
.replace(/\n$/g, '\n\n')
.replace(/[A-Z].*?\b/g, '<mark>$&</mark>');
if (isIE) {
// IE wraps whitespace differently in a div vs textarea, this fixes it
text = text.replace(/ /g, ' <wbr>');
}
return text;
}
function handleInput() {
var text = $textarea.val();
var highlightedText = applyHighlights(text);
$highlights.html(highlightedText);
}
function handleScroll() {
var scrollTop = $textarea.scrollTop();
$backdrop.scrollTop(scrollTop);
var scrollLeft = $textarea.scrollLeft();
$backdrop.scrollLeft(scrollLeft);
}
function fixIOS() {
// iOS adds 3px of (unremovable) padding to the left and right of a textarea, so adjust highlights div to match
$highlights.css({
'padding-left': '+=3px',
'padding-right': '+=3px'
});
}
function bindEvents() {
$textarea.on({
'input': handleInput,
'scroll': handleScroll
});
$toggle.on('click', function() {
$container.toggleClass('perspective');
});
}
if (isIOS) {
fixIOS();
}
bindEvents();
handleInput();
#import url(https://fonts.googleapis.com/css?family=Open+Sans);
*, *::before, *::after {
box-sizing: border-box;
}
body {
margin: 30px;
background-color: #f0f0f0;
}
.container, .backdrop, textarea {
width: 460px;
height: 180px;
}
.highlights, textarea {
padding: 10px;
font: 20px/28px 'Open Sans', sans-serif;
letter-spacing: 1px;
}
.container {
display: block;
margin: 0 auto;
transform: translateZ(0);
-webkit-text-size-adjust: none;
}
.backdrop {
position: absolute;
z-index: 1;
border: 2px solid #685972;
background-color: #fff;
overflow: auto;
pointer-events: none;
transition: transform 1s;
}
.highlights {
white-space: pre-wrap;
word-wrap: break-word;
color: transparent;
}
textarea {
display: block;
position: absolute;
z-index: 2;
margin: 0;
border: 2px solid #74637f;
border-radius: 0;
color: #444;
background-color: transparent;
overflow: auto;
resize: none;
transition: transform 1s;
}
mark {
border-radius: 3px;
color: transparent;
background-color: #b1d5e5;
}
button {
display: block;
width: 300px;
margin: 30px auto 0;
padding: 10px;
border: none;
border-radius: 6px;
color: #fff;
background-color: #74637f;
font: 18px 'Opens Sans', sans-serif;
letter-spacing: 1px;
appearance: none;
cursor: pointer;
}
.perspective .backdrop {
transform:
perspective(1500px)
translateX(-125px)
rotateY(45deg)
scale(.9);
}
.perspective textarea {
transform:
perspective(1500px)
translateX(155px)
rotateY(45deg)
scale(1.1);
}
textarea:focus, button:focus {
outline: none;
box-shadow: 0 0 0 2px #c6aada;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="backdrop">
<div class="highlights"></div>
</div>
<textarea>This demo shows how to highlight bits of text within a textarea. Alright, that's a lie. You can't actually render markup inside a textarea. However, you can fake it by carefully positioning a div behind the textarea and adding your highlight markup there. JavaScript takes care of syncing the content and scroll position from the textarea to the div, so everything lines up nicely. Hit the toggle button to peek behind the curtain. And feel free to edit this text. All capitalized words will be highlighted.</textarea>
</div>
<button>Toggle Perspective</button>
Reference- https://codepen.io/lonekorean/pen/gaLEMR for example

JavaScript Etch-a-Sketch shading pen stops increasing opacity after another pen has been clicked on

I'm creating an Etch-a-Sketch for The Odin Project using HTML, CSS, & JavaScript. I'm having some difficulties with the JavaScript for the "shader pen" I've implemented.
Note: The "pens" described in this question are not to be confused with code pens.
There are two pens: a black pen that turns a cell black and the shader pen which, on the first pass, turns the cell black but changes the opacity to 0.1 so that it's almost transparent. This creates the illusion of slight darkening since the background behind the cell is the same as the original color of the cell. After each subsequent pass with the shader pen, the opacity increases by 0.1.
The shader pen is the default pen. It works fine at first, but when I click on the black pen and then go back to the shader pen, the shader pen increases the opacity once and stops. It also overrides the black cells.
Here's how I set up the pens:
makeGrid(16); // generate grid
pen("shader"); // default pen: shader
document.querySelector('#black').addEventListener("click", e => pen("black"));
document.querySelector('#shader').addEventListener("click", e => pen("shader"));
function pen(selected) {
let cells = document.querySelectorAll('div.cell');
cells.forEach(cell => {
cell.addEventListener('mouseover', function(e) {
if (selected == "black") {
// turns cell black
cell.classList.remove('shade');
cell.style.backgroundColor = '#101010';
cell.style.opacity = '1';
console.log('Make cell black')
} else if (selected == "shader") {
let opacity = cell.style.opacity;
if (cell.classList.contains("shade")) {
// increases opacity by 0.1
cell.style.opacity = (Number(opacity) + 0.1);
console.log('If there is shade, increase opacity.')
} else {
// turns cell to 0.1 opacity
cell.classList.add('shade');
cell.setAttribute('style', 'opacity:0.1');
cell.style.backgroundColor = '#101010';
console.log('Else, add shade class.')
}
}
})
});
}
I ran this code with a console.log statement in each conditional block and it looks like the black pen is still running when I go back to using the shader pen. My best guess is that this is what's causing the problem, but I'm not sure how to fix it.
I've created a CodePen with the rest of the code so you can see it in action. As previously mentioned, the default pen is the shader. It works as intended at the beginning, but it just stops after the black pen is selected.
Any help or guidance would be greatly appreciated.
There's so many problems with your code, The main one is when you change the pen type (when you call the pen() function) you add a new mouseover event listener.
Let's walk through it
Your code starts by calling pen('shader') making the shader the default pen type
pen("shader");
let's look at the pen() definition
function pen(selected) {
let cells = document.querySelectorAll('div.cell');
cells.forEach(cell => {
cell.addEventListener('mouseover', function(e){
...
})
});
}
What happens is the event listener takes the string shader and closes on it (This is called a closure) for that instance now whenever you hover over a cell the pen type will be shader
Now when you select the black pen you call the function pen() again adding a new set of event listeners.
This does not replace the old event listener with the new one, it stacks them like calling two functions one after the other.
Now when you hover over a cell the first event listener with the pen type shader will fire and then the second one with the black pen will fire after it, you can see this in the console you see two messages being printed from both if statement conditions.
Now when you pick the shader again you add a new set of event listeners with the shader pen type, what happens is the very first event listener will fire setting opacity to 0.1 then comes the black one removing the shade class then comes the third listener again checking if the cell has the class shade if(cell.classList.contains("shade")) which is false then falls down to the last else statement.
There's a ton of ways to fix this, but seeing that you're a beginner i will give you simple solutions
First make the pen type a global variable and on each button click you change it
Second add only one event listener to all cels at the start of your code and have them check the global variable
Demo
let penType = 'shader';
makeGrid(4); // generate grid
document.querySelector('#black').addEventListener("click", e => penType = "black");
document.querySelector('#shader').addEventListener("click", e => penType = "shader");
// generate grid
function makeGrid(dimension) {
const canvas = document.querySelector('#canvas');
const canvasWidth = document.getElementById("canvas").offsetWidth;
const cellWidth = canvasWidth / dimension;
for (let x = 1; x <= dimension * dimension; x++) {
const makeCell = document.createElement('div');
makeCell.classList.add('cell');
canvas.appendChild(makeCell);
};
canvas.style.gridTemplateRows = `repeat(${dimension}, ${cellWidth}px [row-start]`;
canvas.style.gridTemplateColumns = `repeat(${dimension}, ${cellWidth}px [column-start]`;
// after all cells have been generated add the event listener
// this is not the most optimize version of this but it gets the job done
let cells = document.querySelectorAll('div.cell');
cells.forEach(cell => {
cell.addEventListener('mouseover', function(e) {
console.log(penType)
if (penType == "black") { // turns cell black
cell.classList.remove('shade');
cell.style.backgroundColor = '#101010';
cell.style.opacity = '1';
console.log('Make cell black')
} else if (penType == "shader") { // turns cell 0.1
let opacity = cell.style.opacity;
if (cell.classList.contains("shade")) {
cell.style.opacity = (Number(opacity) + 0.1);
console.log('If there is shade, increase opacity.')
} else {
cell.classList.add('shade');
cell.setAttribute('style', 'opacity:0.1');
cell.style.backgroundColor = '#101010';
console.log('Else, add shade class.')
}
}
})
});
}
body {
margin: 0;
background-color: #514c53;
color: #fff;
font-size: 18pt;
}
/* DIV STYLING */
#container {
margin: 20px auto;
max-width: 400px;
display: flex;
flex-wrap: wrap;
}
.full {
width: 100%;
}
.left {
width: 75%;
margin-top: 15px;
}
.right {
width: 25%;
text-align: right;
}
#canvas {
display: grid;
flex-wrap: wrap;
grid-template-rows: repeat(16, 30px [row-start]);
grid-template-columns: repeat(16, 30px [col-start]);
background: #e8dfd6;
}
.cell {
background: #e8dfd6;
}
/* CELL SHADING */
.black {
background-color: #101010;
}
.shade {
background-color: #101010;
width: 100%;
height: 100%;
}
/* ELEMENT STYLING */
button {
font-weight: 700;
margin: 10px 0;
background-color: #b9967d;
color: #fff;
padding: 0px 15px;
text-shadow: 1px 1px #2e2e2e;
box-shadow: 3px 3px #2e2e2e;
border-radius: 5px;
border: 0px;
text-transform: uppercase;
height: 30px;
outline: none;
transition: 0.3s;
}
button:hover {
cursor: pointer;
background-color: #aa8062;
box-shadow: 0px -3px #2e2e2e;
}
button:active {
background-color: #997963;
}
.circle {
float: left;
height: 15px;
width: 15px;
border: 1px solid #fff;
border-radius: 50%;
margin: 1px 5px 0 0;
}
.circle:hover {
cursor: pointer;
/*transition: 0.3s;
border: 2px solid #fff;*/
}
.meaning {
float: left;
font-size: .542em;
text-transform: uppercase;
padding-top: 2px;
margin-right: 10px;
}
#black {
background-color: #101010;
}
#shader {
background-image: linear-gradient(#807b76, #dfd8d0);
}
<div id="container">
<div class="left" style="margin-bottom:10px">
<div class="circle" id="black"></div>
<div class="meaning">Black</div>
<div class="circle" id="shader"></div>
<div class="meaning">Shader</div>
</div>
<div id="canvas" class="full">
<!--grid generates here-->
</div>
</div>
<!--container-->
One tiny problem with your logic, when go to the black pen you don't have to remove the shade class because then when you come back to the shade pen and you hover over a black cell it sets opacity back to 0.1
I changed a lot, so I can't describe all of the changes, but here's a link to my forked codepen:
https://codepen.io/scoutskylar/pen/ExxWPMb
The biggest change was removing the black and shade classes and just changing the opacity instead. (All of the cells now start with 0 opacity.) I also added erasers just for fun. :) The other big thing was making the event handlers once instead of adding a handler every time the pen changed.
Here's the code:
var currentPen = "shader"; // default pen
makeGrid(16); // generate grid
document.querySelector("#black").addEventListener("click", e => {
currentPen = "black";
});
document.querySelector("#shader").addEventListener("click", e => {
currentPen = "shader";
});
document.querySelector("#eraser").addEventListener("click", e => {
currentPen = "eraser";
});
document.querySelector("#deshader").addEventListener("click", e => {
currentPen = "deshader";
});
// generate grid
function makeGrid(dimension) {
const canvas = document.querySelector("#canvas");
const canvasWidth = document.getElementById("canvas").offsetWidth;
const cellWidth = canvasWidth / dimension;
for (let x = 1; x <= dimension * dimension; x++) {
const makeCell = document.createElement("div");
makeCell.classList.add("cell");
canvas.appendChild(makeCell);
}
canvas.style.gridTemplateRows = `repeat(${dimension}, ${cellWidth}px [row-start]`;
canvas.style.gridTemplateColumns = `repeat(${dimension}, ${cellWidth}px [column-start]`;
let cells = document.querySelectorAll("div.cell");
cells.forEach(cell => {
cell.addEventListener("mouseover", function(e) {
if (currentPen == "black") {
// turns cell black
cell.style.opacity = "1";
// console.log("Make cell black");
} else if (currentPen == "shader") {
// turns cell 0.1 opacity darker
let opacity = Number(cell.style.opacity);
cell.style.opacity = opacity >= 1 ? "1" : opacity + 0.1 + "";
// console.log("Increase opacity");
} else if (currentPen == "eraser") {
// resets color
cell.style.opacity = "0";
// console.log("Reset opacity");
} else if (currentPen == "deshader") {
// turns cell 0.1 opacity lighter
let opacity = Number(cell.style.opacity);
cell.style.opacity = opacity <= 0 ? "0" : opacity - 0.1 + "";
// console.log("Decrease opacity");
}
});
});
}
body {
margin: 0;
background-color: #514c53;
color: #fff;
font-size: 18pt;
}
/* DIV STYLING */
#container {
margin: 20px auto;
max-width: 400px;
display: flex;
flex-wrap: wrap;
}
.full {
width: 100%;
}
.left {
width: 75%;
margin-top: 15px;
}
.right {
width: 25%;
text-align: right;
}
#canvas {
display: grid;
flex-wrap: wrap;
grid-template-rows: repeat(16, 30px [row-start]);
grid-template-columns: repeat(16, 30px [col-start]);
background: #e8dfd6;
}
.cell {
/* background: #e8dfd6; */
background-color: #101010;
opacity: 0;
}
/* CELL SHADING */
/* .black {
background-color: #101010;
} */
/* .shade {
background-color: #101010;
width: 100%;
height: 100%;
} */
/* ELEMENT STYLING */
button {
font-weight: 700;
margin: 10px 0;
background-color: #b9967d;
color: #fff;
padding: 0px 15px;
text-shadow: 1px 1px #2e2e2e;
box-shadow: 3px 3px #2e2e2e;
border-radius: 5px;
border: 0px;
text-transform: uppercase;
height: 30px;
outline: none;
transition: 0.3s;
cursor: pointer;
}
button:hover {
background-color: #aa8062;
box-shadow: 0px -3px #2e2e2e;
}
button:active {
background-color: #997963;
}
.circle {
display: inline-block;
height: 15px;
width: 15px;
border: 1px solid #fff;
border-radius: 50%;
margin: 1px 5px 0 0;
cursor: pointer;
}
.meaning {
font-size: 0.542em;
text-transform: uppercase;
padding-top: 2px;
margin-right: 10px;
cursor: pointer;
}
.penbutton {
display: inline-block;
}
#black .circle {
background-color: #101010;
}
#shader .circle {
background: linear-gradient(#807b76, #dfd8d0);
}
#eraser .circle {
background-color: #e8dfd6;
}
#deshader .circle {
background: linear-gradient(#9e9a96, #e8dfd6);
}
<head>
<title>Etch-a-Sketch</title>
</head>
<body>
<div id="container">
<div class="left" style="margin-bottom:10px">
<span id="black" class="penbutton">
<span class="circle"></span>
<span class="meaning">Black</span>
</span>
<span id="shader" class="penbutton">
<span class="circle"></span>
<span class="meaning">Shader</span>
</span>
<span id="eraser" class="penbutton">
<span class="circle"></span>
<span class="meaning">Super Eraser</span>
</span>
<span id="deshader" class="penbutton">
<span class="circle"></span>
<span class="meaning">Light Eraser</span>
</span>
</div>
<div id="canvas" class="full">
<!--grid generates here-->
</div>
</div>
<!--container-->
</body>
<script src="assets/js/eas.js"></script>

Little problem with accordion-menu (hide/show)

Good time. There is an accordion menu at this link: https://www.w3schools.com/code/tryit.asp?filename=G3Z0U159KFM3
(to see it, you need to click on the green "Run" button)
This is a simple show / hide menu. How to make the default content was expanded and by clicking could hide it? (i.e. the opposite of the current one)
Dears, please help with this problem.
Well, although the way you described your issue wasn't clear, I think you are trying to do the opposite of the code you provided, so you would like the "contents" menu to be shown by default and when you click on it the menu would collapse back.
First you want to set the .active class by default to the .ContentsAccordion button like so :
<button class="ContentsAccordion active">Contents</button>
And then you want to get the height of your menu and put it into the style element of your .ContentsPanel div with this code :
var pan = document.getElementsByClassName("ContentsPanel");
pan[0].setAttribute('style', 'max-height: ' + pan[0].scrollHeight + 'px;');
and the rest of your code doesn't need any change.
Working example below :
<style>
.ContentsAccordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 18px;
transition: 0.4s;
}
button.ContentsAccordion:after {
content: '\002B';
color: #777;
font-weight: bold;
float: right;
margin-left: 5px;
}
button.ContentsAccordion.active:after {
content: '\2212';
}
.active, .ContentsAccordion:hover {
background-color: #ccc;
}
.ContentsPanel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
border: 1px #ccc solid;
}
.ContentsAccordionP {
font-size: 16px;
}
</style>
<button class="ContentsAccordion active">Contents</button>
<div class="ContentsPanel">
<p class="ContentsAccordionP">Some text 1</p>
<p class="ContentsAccordionP">Some text 2</p>
<p class="ContentsAccordionP">Some text 3</p>
</div>
<script>
var acc = document.getElementsByClassName("ContentsAccordion");
var i;
var pan = document.getElementsByClassName("ContentsPanel");
pan[0].setAttribute('style', 'max-height: ' + pan[0].scrollHeight + 'px;');
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight){
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
</script>

Max-height transition problems

I make autocomplete
Max-height set from JavaScript:
if (data.length < 10)
element.css({'max-height': (30 * newVal.length) + 'px'})
If max-height decreases(e.g. 300px to 150px), transition does not work.
If max-height increases(e.g. 150px to 300px), transition works.
.autocomplete-ion {
background-color: gray;
position: absolute;
width: 90%;
left: 5%;
top:45px;
overflow-y: auto;
z-index: 10000000;
background-color: #FAFAFA;
transition: 0.8s;
max-height: 300px;
box-shadow: 0 3px 1px -2px rgba(0,0,0,.14),0 2px 2px 0 rgba(0,0,0,.098),0 1px 5px 0 rgba(0,0,0,.084);
ul li {
padding:5px;
}
}
It is because you have max-height value as 300px in your css. So you should remove that to work properly
.autocomplete-ion {
background-color: gray;
position: absolute;
width: 90%;
left: 5%;
top:45px;
overflow-y: auto;
z-index: 10000000;
background-color: #FAFAFA;
transition: 0.8s;
box-shadow: 0 3px 1px -2px rgba(0,0,0,.14),0 2px 2px 0 rgba(0,0,0,.098),0 1px 5px 0 rgba(0,0,0,.084);
ul li {
padding:5px;
}
Because the height change from element add/remove will not cause a animation.
When elements increasing, the new height is likely to always larger than previous max-height, so when you set a higher max-height, the animation appears from old max-height to new one.
When elements decreasing, if you remove the elements first, then the height will decrease first, without animation, then, when you set the new max-height, it'll only animate part only if new max-height is smaller than decreased height. And if the new max-height is still larger than decreased height, the animation not appears at all.
So you have to first set to the new max-height when new elements is less then old ones, to trigger animation, and set the list to new one(either by removing or create a new list) when animation ends.
var list = $(".autocomplete-ion ul");
var tryAppend = function(newList) {
var curList = $(".autocomplete-ion ul li");
var curLength = curList.length;
var newLength = newList.length;
if (newLength <= 10) {
// If its adding, no need to listen to animation, as the new height will be definetly larger.
// Otherwise,
if (newLength < curLength) {
$(".autocomplete-ion").on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() {
list.empty().append(newList);
$(this).off();
});
$(".autocomplete-ion").css({'max-height': (30 * newLength) + 'px'});
} else {
$(".autocomplete-ion").css({'max-height': (30 * newLength) + 'px'});
list.empty().append(newList);
}
}
};
var create = function(num) {
var list =[];
var i, li;
for (i = 0; i < num; ++i ) {
li = $("<li>").text("Test li " + (i + 1));
list.push(li);
}
tryAppend(list);
};
$(".cl").click(function() {
var counts = parseInt($(this).data("len"), 10);
create(counts);
});
$(".clear").click(function() {
list.empty();
});
.autocomplete-ion {
background-color: gray;
position: absolute;
width: 90%;
left: 5%;
top:45px;
overflow-y: auto;
z-index: 10000000;
background-color: #FAFAFA;
transition: 0.8s;
max-height: 0px;
box-shadow: 0 3px 1px -2px rgba(0,0,0,.14),0 2px 2px 0 rgba(0,0,0,.098),0 1px 5px 0 rgba(0,0,0,.084);
ul li {
height: 40px;
padding:5px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="autocomplete-ion">
<ul>
</ul>
</div>
<button class="cl" data-len="1">1</button>
<button class="cl" data-len="5">5</button>
<button class="cl" data-len="10">10</button>

Categories