JavaScript contenteditable - javascript

I am creating a HTML rich text editor and I would like to use the contenteditable attribute on a div. I have a list of divs inside a div called editor. When the user hits enter I prevent the default action. I then insert a new div after the current div. The only problem is I cannot focus on the new div. Does anyone know how to do this?
The HTML
<body>
<div id="editor" contenteditable="true">
<div id="1" contenteditable="ture" class="line" style="height: 20px; background-color: #a0f;"></div>
<div contenteditable="ture" class="line" style="height: 20px; background-color: #abf;"></div>
<div contenteditable="ture" class="line" style="height: 20px; background-color: #a9f;"></div>
<div contenteditable="ture" class="line" style="height: 20px; background-color: #aff;"></div>
<div contenteditable="ture" class="line" style="height: 20px; background-color: #aaf;"></div>
</div>
</body>
The JavaScript
$(function(){
var thisLine;
$("#editor").bind("keydown", function(event){
if(event.keyCode == 13){
event.preventDefault();
var newLine = $("<div tabindex=\"-1\" contenteditable=\"ture\" id=\"2\"class=\"line\" style=\"height: 20px; background-color: #aff;\"></div>");
newLine.insertAfter(thisLine);
$("#2").focus();
}
})
$(".line").bind("click", function(){
thisLine = $(this);
})
});

This should work:
newLine.insertAfter(thisLine).focus();
Demo: http://jsfiddle.net/tymeJV/7xEXt/

Get the selection, and add a new collapsed range to it. See moveCaretToStartOf method in the example
function moveCaretToStartOf(element) {
var selection = document.getSelection();
selection.removeAllRanges();
var range = document.createRange();
range.setStart(element, 0);
selection.addRange(range)
}
document.querySelector('div').focus();
window.setTimeout(function () {
moveCaretToStartOf(document.querySelectorAll('p')[1])
}, 1000);
<blockquote>
Cursor will be placed into the second paragraph after 1 second
</blockquote>
<div contenteditable="true">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Vel laboriosam nobis nam tempore sint adipisci, ullam perspiciatis placeat aliquid dolorem. Aliquid nisi, dicta sunt dolor qui voluptatem perferendis veniam ad!</p>
<p><br></p>
</div>

Related

Toggle text inserted with innerHTML from Javascript

As an exercise I am trying to create a small quiz app and a part of it are the question cards. On these cards I have a question and then a button to show the answer. When the button is clicked, then the answer (which doesn't exist in the HTML DOM yet, therefore not visible) will show up and with the next click, the answer should be hidden again. Basically it will look something like this:
Before Show Answer is clicked
After Show Answer is clicked
Here is the HTML code:
<section class="question-card">
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsam vitae
labore repudiandae tenetur. Qui maiores animi quibusdam voluptatum
nobis. Nam aperiam voluptatum dolorem quia minima assumenda velit libero
saepe repellat. Tempore delectus deleniti libero aliquid rem velit illum
expedita nostrum quam optio maiores officiis consequatur ea, sint enim
cum repudiandae inventore ab nemo?
</p>
<div class="bookmark">
<i class="fa-regular fa-bookmark fa-lg"></i>
</div>
<button class="answer-button" data-js="answer-button">Show Answer</button>
<ul class="answer-container" data-js="answer-container">
</ul>
<div class="container-categories">
<button class="category-button category-html">#html</button>
<button class="category-button category-flexbox">#flexbox</button>
<button class="category-button category-css">#css</button>
<button class="category-button category-js">#js</button>
</div>
</section>
I have added an EventListener for the Show Answer button that adds a list item in the already existing ul when it is clicked. I have done this with innerHTML:
const answerButton = document.querySelector(".answer-button");
const answerContainer = document.querySelector(".answer-container");
const answer1 = "Lorem ipsum dolor sit amet consectetur adipisicing elit.";
answerButton.addEventListener("click", () => {
answerContainer.innerHTML = `<li class="show-answer">${answer1}</li>`;
});
Now what I can't seem to manage is to hide the answer when the button is clicked again (the next challenge will be that the button will change the text to "Hide Answer" after the first click, but I have no idea how to approach that yet). The closest I got was this:
answerButton.addEventListener("click", () => {
answerContainer.innerHTML = `<li class="show-answer">${answer1}</li>`;
answerContainer.classList.toggle("hide-answer");
});
However, this method displays the .hide-answer class first, after which the 2 classes are toggled and everything is as it should be. So after the first click, the answer is still hidden and only after the 2nd click the button behaves the way I want it to.
I have tried this as well:
answerButton.addEventListener("click", () => {
answerContainer.innerHTML = `<li class="hide-answer">${answer1}</li>`;
answerContainer.classList.toggle("show-answer");
});
But for some reason this shows the container with all the CSS properties, but there is no text:
Answer Container is there, but no text
This is the CSS for the 2 classes (show-answer and hide-answer):
.show-answer {
background-color: hotpink;
border-radius: 7px;
border: none;
list-style: none;
width: 50%;
display: flex;
justify-content: center;
align-items: center;
padding: 1rem;
box-shadow: rgba(0, 0, 0, 0.3) 0px 19px 38px;
}
.hide-answer {
display: none;
}
If anybody has any idea how I could get the result I need, I would be extremely grateful...
You're mixing up the answer-container with the answer-container's child (the innerHtml <li> element).
initially there's a visible, but empty <ul class="answer-container"></ul>.
Next on click of the button, you add the content into the answer-container expecting it to be visible with a show-answer class
Immediately after, you add the hide-answer class to the <ul class="answer-container"> parent element which hides the newly added content.
Click the button again and you finally see your answer because the container element has the hide-answer class toggled off. From here it works as you're expecting.
You can fix this by having the answer-container be hidden initially and then continue to toggle the display of the container. You can also just use a DOM element's hidden attribute to do this as I do in this code snippet below where I've taken your exact example and just modified the answer-container to start with hidden and toggle the hidden attribute on click. You can do the same thing w/ a CSS display: none class too.
const answerButton = document.querySelector(".answer-button");
const answerContainer = document.querySelector(".answer-container");
const answer1 = "Lorem ipsum dolor sit amet consectetur adipisicing elit.";
answerButton.addEventListener("click", () => {
answerContainer.innerHTML = `<li class="answer">${answer1}</li>`;
answerContainer.hidden = !answerContainer.hidden;
});
.answer {
background-color: hotpink;
border-radius: 7px;
border: none;
list-style: none;
width: 50%;
display: flex;
justify-content: center;
align-items: center;
padding: 1rem;
box-shadow: rgba(0, 0, 0, 0.3) 0px 19px 38px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<section class="question-card">
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsam vitae
labore repudiandae tenetur. Qui maiores animi quibusdam voluptatum
nobis. Nam aperiam voluptatum dolorem quia minima assumenda velit libero
saepe repellat. Tempore delectus deleniti libero aliquid rem velit illum
expedita nostrum quam optio maiores officiis consequatur ea, sint enim
cum repudiandae inventore ab nemo?
</p>
<div class="bookmark">
<i class="fa-regular fa-bookmark fa-lg"></i>
</div>
<button class="answer-button" data-js="answer-button">Show Answer</button>
<ul class="answer-container" hidden data-js="answer-container">
</ul>
<div class="container-categories">
<button class="category-button category-html">#html</button>
<button class="category-button category-flexbox">#flexbox</button>
<button class="category-button category-css">#css</button>
<button class="category-button category-js">#js</button>
</div>
</section>
Would something like this work?
You just use if the container has the class show-answer to determine if the answer needs to be shown or hidden
answerButton.addEventListener("click", () => {
if (answerContainer.classList.contains('show-answer')) {
// container has `showing` class
// hide the answer
answerContainer.innerHTML = ``; // ? - my guess, not sure how to want to hide it
}else{
// container doesn't have `showing` class
// show the answer
answerContainer.innerHTML = `<li class="hide-answer">${answer1}</li>`;
};
// update class
answerContainer.classList.toggle("show-answer");
});

Shrink overflowing content to fit container?

Is it possible in CSS (if not, javascript?) to shrink content that overflows its container, rather than hide it?
I have a box with some text etc, which shrinks in width as the viewport gets smaller, and the height is restricted too. All the content needs to remain visible, but within the bounds. Scroll is not an option.
body {
background-color: mediumaquamarine;
}
div {
width: 300px;
height: 150px;
overflow: hidden;
background-color: #fff;
}
<div>
<h1>example title</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati fugiat dolore amet odit quaerat iusto sapiente ea quod atque necessitatibus id eius accusantium itaque voluptatibus laborum, doloremque, recusandae, nobis consequatur.</p>
<button>a button</button>
</div>
Hmm, the question is a little unclear, but you could look into using viewport width font-size. It will resize based on the screen size:
body {
background-color: mediumaquamarine;
}
div {
width: 300px;
height: 150px;
overflow: hidden;
background-color: #fff;
font-size: 1.3vw;
}
button {
font-size: 1.3vw;
}
<div>
<h1>example title</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati fugiat dolore amet odit quaerat iusto sapiente ea quod atque necessitatibus id eius accusantium itaque voluptatibus laborum, doloremque, recusandae, nobis consequatur.</p>
<button>a button</button>
</div>
Use this function to adjust the font-size of a span inside a div:
function adjustHeights(elem) {
var fontstep = 2;
if ($(elem).height() > $(elem).parent().height() || $(elem).width() > $(elem).parent().width()) {
$(elem).css('font-size', (($(elem).css('font-size').substr(0, 2) - fontstep)) + 'px').css('line-height', (($(elem).css('font-size').substr(0, 2))) + 'px');
adjustHeights(elem);
}
}
div {
position: fixed;
width: 200px;
height: 100px;
border: 1px solid blue;
padding: 1px;
overflow-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<span id="text">
sldfjslfjladf
sf
as
f
wer
qwreqwrewasdf
sd
f
s
fs
df
s
ffadsssssssssssssssssssssssssssss
asdf<br/>
sdf
s
dsfsfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</span>
</div>
<script>
function adjustHeights(elem) {
var fontstep = 2;
if ($(elem).height() > $(elem).parent().height() || $(elem).width() > $(elem).parent().width()) {
$(elem).css('font-size', (($(elem).css('font-size').substr(0, 2) - fontstep)) + 'px').css('line-height', (($(elem).css('font-size').substr(0, 2))) + 'px');
adjustHeights(elem);
}
}
var div = document.getElementById("text");
adjustHeights(div);
</script>
JSFiddle: http://jsfiddle.net/e8B9j/1390/
SVG with text element.
Make an svg with expandable text.
It will eventually be hard to read.
<div style="width: 60px;">
<svg width="100%" height="100%" viewBox="0 -200 1000 300"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<text font-size="300" fill="black">Text</text>
</svg>
</div>
Non styled example
https://jsfiddle.net/k8L4xLLa/32/
Cool styled example
https://jsfiddle.net/k8L4xLLa/14/
You can use media queries to change the font size when needed.
Honestly though, consider flexbox. Its a much cleaner solution that does not make the text scalable. Then you can wrap your elements when theyre too small. :)

How to set collapse on all other divs when one div is open?

I have seen many questions but none are similar to my case. I have bootstrap collapse and show for a few div contents. The div content shows when title is clicked. I want to close all other div contents when I click another content's title.
The color of the title div is gray and should change to white when its content shows. Once the content is collapsed, title div color should back to gray.
Here's my code:
function collapse (e, id, collapasibleName) {
var toggleColor = document.getElementById(id);
var collapsibles = document.getElementById(collapasibleName);
if(collapsibles.className == 'home__questions-content collapse' || collapsibles.className == 'home__questions-content collapsed')
{
alert("Sdfsdfdsf")
toggleColor.classList.remove('home__questions-title-show');
}
if(collapsibles.className == 'home__questions-content collapse show') {
alert("in show")
toggleColor.classList.add('home__questions-title-show');
}
}
.home__more-questions-content {
padding-right: 40px;
padding-left:40px;
padding-bottom: 20px;
background-color: $white-color;
position:relative;
max-width: 1080px;
margin: auto;
}
.home__questions-content-tile {
margin-bottom: 10px;
border:1px solid #eee;
}
.home__questions-content-title {
padding:20px;
background-color: #000
cursor: pointer;
}
.home__questions-content {
padding-top: 0;
padding-right:20px;
padding-left:20px;
padding-bottom:20px;
}
.home__questions-title-show { background-color: #fff; }
.collapse {
display:none;
}
.collapse.show {
display: block;
}
.collapsing {
position: relative;
height: 0;
overflow: hidden;
transition: height 0.35s ease;
}
<div class="home__more-questions-content" id="accordion">
<div class="home__questions-content-tile">
<div class="home__questions-content-title" data-toggle="collapse" data-target="#collapsible-one" data-parent="#accordion" id="collapse-one" onclick="collapse(event, this.id,'collapsible-one');">
<h2>
// title 1 here
</h2>
</div>
<div class="home__questions-content collapse" id="collapsible-one">
//title 1's content here
</div>
</div>
<div class="home__questions-content-tile">
<div class="home__questions-content-title" data-toggle="collapse" data-target="#collapsible-two" data-parent="#accordion" id="collapse-two" onclick="collapse(event, this.id,'collapsible-two');">
<h2>
//title 2
</h2>
</div>
<div class="home__questions-content collapse" id="collapsible-two">
//title 2's content here
</div>
</div>
<div class="home__questions-content-tile">
<div class="home__questions-content-title" data-toggle="collapse" data-target="#collapsible-three" data-parent="#accordion" id="collapse-three" onclick="collapse(event, this.id, 'collapsible-three');">
<h2>
//title 3
</h2>
</div>
<div class="home__questions-content collapse" id="collapsible-three">
// title 3's content here
</div>
</div>
</div>
Here is the code, explanation is in the comment of the question.
Add new code
if (e.target.parentNode.classList.contains('active')) {
e.target.parentNode.classList.remove('active')
return
}
If current block is opened, then close it and return from further processing.
const container = document.querySelector('.container')
container.addEventListener('click', e => {
if (e.target.parentNode.classList.contains('active')) {
e.target.parentNode.classList.remove('active')
return
}
const collapsable = document.querySelectorAll('.item')
Array.prototype.forEach.call(collapsable, el => {
el.classList.remove('active')
})
e.target.parentNode.classList.add('active')
})
.container {
width: 500px;
margin: 0 auto;
color:darkslategrey;
}
.item {
margin: 10px 0;
border-bottom: 1px solid #666;
padding: 5px 10px;
}
.item.active h3 {
color:aquamarine;
}
p {
overflow: hidden;
transition: height .5s ease;
height: 0px;
}
.item.active p {
height: 80px;
}
<div class="container">
<div class="item active">
<h3>I am a title</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magni minus neque nisi, rem doloribus unde quisquam, similique distinctio voluptate mollitia praesentium quo ut magnam ducimus nemo vitae soluta impedit harum?</p>
</div>
<div class="item">
<h3>I am a title</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magni minus neque nisi, rem doloribus unde quisquam, similique distinctio voluptate mollitia praesentium quo ut magnam ducimus nemo vitae soluta impedit harum?</p>
</div>
<div class="item">
<h3>I am a title</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magni minus neque nisi, rem doloribus unde quisquam, similique distinctio voluptate mollitia praesentium quo ut magnam ducimus nemo vitae soluta impedit harum?</p>
</div>
</div>

How do I make the box below move ( accordion )

Didn't really know how to explain my problem in the title, my question is how do I make it so when I press the top box the other two boxes move down so you can see the text? The same goes for the other two boxes, if I press the middle the last box moves and when I press the last one the top and the middle stays. Plus the boxes has to go back to it's original place. Please I need help with this
$(".faq,.faq2,.faq3").click(function() {
$(this).find(".faq-box-more").toggleClass("open");
$(".faq,.faq2,.faq3").not(this).find(".faq-box-more").removeClass("open");
});
.faq,
.faq2,
.faq3 {
height: 100px;
width: 500px;
background: red;
position: relative;
top: 100px;
left: 50%;
transform: translate(-50%, 0%);
}
.faq-box {
position: relative;
height: 100%;
width: 100%;
background: #333;
cursor: pointer;
padding: 0 20px;
}
.faq-box h2 {
position: absolute;
top: 50%;
transform: translate(0, -50%);
color: #fff;
text-transform: uppercase;
letter-spacing: 3px;
font-size: 1.9rem;
}
.faq-box i {
position: absolute;
left: 96%;
top: 50%;
font-size: 3rem;
transform: translate(-100%, -50%);
color: #fff;
}
.faq-box-more {
position: absolute;
height: 0%;
top: 100%;
background-color: #222;
color: #fff;
width: 100%;
}
.faq-box-more p {
position: absolute;
width: 100%;
padding: 20px;
}
.open {
height: 140% !important;
}
<link href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
<div class="faq">
<div class="faq-box">
<h2>lorem ipsum</h2>
<i class="ion-ios-arrow-down"></i>
</div>
<div class="faq-box-more">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur numquam, atque nemo pariatur maiores eos harum, ab magni nisi quod, commodi ipsum totam vel nihil voluptatum vitae quisquam, qui amet!</p>
</div>
</div>
<div class="faq2">
<div class="faq-box">
<h2>lorem ipsum</h2>
<i class="ion-ios-arrow-down"></i>
</div>
<div class="faq-box-more">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur numquam, atque nemo pariatur maiores eos harum, ab magni nisi quod, commodi ipsum totam vel nihil voluptatum vitae quisquam, qui amet!</p>
</div>
</div>
<div class="faq3">
<div class="faq-box">
<h2>lorem ipsum</h2>
<i class="ion-ios-arrow-down"></i>
</div>
<div class="faq-box-more">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur numquam, atque nemo pariatur maiores eos harum, ab magni nisi quod, commodi ipsum totam vel nihil voluptatum vitae quisquam, qui amet!</p>
</div>
</div>
</section>
see snippet below or jsfiddle
if you don't want to use the jqueryUI accordion and want to learn how it actually works, it's something like this
in CSS do not use absolute positioning on faq-box-more as it won't occupy any space. instead hide it with display:none
for JQ
first, you don't need to add different classes to all the faq divs, you can add one common class and then select the respective faq-box-more connected to the faq you click on , using jQuery methods below
when you click on faq-box ( either one of them ) , in a variable ( for cleaner and concise code ) you store the corresponding faq-box-more .
you do this by using sibling() method. searching .faq-box's ' brothers ' for the .faq-box-more . in HTML structure faq-box and faq-box-more are on the same level, therefore they are siblings
then using an if condition you check if the previous selected faq-box-more is visible or not. IF YES -> close it , IF NO -> open IT .
you close and open using slideUp() and slideDown() methods ( click on the methods to see more info about them )
then, you also want to find any previous opened faq-box-more and close them, so only one is opened at one time ( the one corresponding to the box you clicked on ) . to do this you use the parents() method to 'climb' up the HTML structure and get to faq and then using siblings() and find() you find the .faq-box-more , and if it is open, you hide it with slideUp()
i think it's important that you try to understand the process behind the accordion and not just copy-paste it .
if you have anymore questions on this subject, feel free to ask in the comments
P.S. you had many problems in your code ( CSS ), it tried to correct some of them but also i wanted not to change too much your code.
$(".faq-box").on("click",function() {
var boxMore = $(this).siblings(".faq-box-more")
if ($(boxMore).is(":visible")) {
$(boxMore).slideUp()
} else {
$(boxMore).slideDown(500)
}
$(this).parents(".faq").siblings().find(".faq-box-more").slideUp()
});
.faq {
width: 500px;
background: red;
position: relative;
left: 50%;
transform: translate(-50%, 0%);
}
.faq-box {
position: relative;
height: 100%;
width: 100%;
background: #333;
cursor: pointer;
padding: 0 20px;
}
.faq-box h2 {
color: #fff;
text-transform: uppercase;
letter-spacing: 3px;
font-size: 1.9rem;
}
.faq-box i {
position: absolute;
left: 96%;
top: 50%;
font-size: 3rem;
transform: translate(-100%, -50%);
color: #fff;
}
.faq-box-more {
background-color: #222;
color: #fff;
width: 100%;
height:200px;
display:none;
}
.faq-box-more p {
position: absolute;
width: 100%;
padding: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
<div class="faq">
<div class="faq-box">
<h2>lorem ipsum</h2>
<i class="ion-ios-arrow-down"></i>
</div>
<div class="faq-box-more">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur numquam, atque nemo pariatur maiores eos harum, ab magni nisi quod, commodi ipsum totam vel nihil voluptatum vitae quisquam, qui amet!</p>
</div>
</div>
<div class="faq">
<div class="faq-box">
<h2>lorem ipsum</h2>
<i class="ion-ios-arrow-down"></i>
</div>
<div class="faq-box-more">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur numquam, atque nemo pariatur maiores eos harum, ab magni nisi quod, commodi ipsum totam vel nihil voluptatum vitae quisquam, qui amet!</p>
</div>
</div>
<div class="faq">
<div class="faq-box">
<h2>lorem ipsum</h2>
<i class="ion-ios-arrow-down"></i>
</div>
<div class="faq-box-more">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur numquam, atque nemo pariatur maiores eos harum, ab magni nisi quod, commodi ipsum totam vel nihil voluptatum vitae quisquam, qui amet!</p>
</div>
</div>
</section>

JQuery "click" not triggering function

I'm trying to trigger a JQuery function when you click on a div (i've tried making it a button as well) to no avail. Google Chrome Inspector does not even recognize an event handler being created behind the scenes.
<!DOCTYPE>
<html>
<head>
<meta charset="UTF-8">;
<script type = "text/javascript" src = "http://code.jquery.com/jquery-1.9.1.js"></script>
</head>
<body>
<div id = "main" style = "width: 500px; height: 500px; background-color: black; color: white;">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eius aliquam nobis optio ut ratione a eligendi excepturi cumque est commodi? Sed, odit, culpa deserunt distinctio at commodi modi architecto aliquam.
</div>
<button class = "button" href="#" style = "width: 50px; height: 50px; background-color: black;"></button>
<script type = "text/javacsript">
$(document).ready(function(){
$(".button").click(function(){
$("main").val("IT WORKED");
});
};
</script>
</html>
You forgot to use # for id selector, also use text() or html() instead of val() for div and you also missed the closing parenthesis of document.ready.
Live Demo
$(document).ready(function(){
$(".button").click(function(){
$("#main").text("IT WORKED");
});
});

Categories

Resources