Create Span on Each New Line in ContentEditable Div - javascript

I have one div which has contenteditable property true.
I want whenever new line is entered then that should be inside a span tag and that span should be inside p tag but whenever i am clicking on enter it just create new div.
Initial
<div contenteditable="true"></div>
Entering this text
some text
some new text
some more new text
What i am getting
<div contenteditable="true">
some text
<div>some new text</div>
<div>some more new text</div>
</div>
What i want
<div contenteditable="true">
<p><span>some text</span></p>
<p><span>some new text</span></p>
<p><span>some more new text</span></p>
</div>
How can i achieve above pattern using javascript.

Is there a need for the div to be initialized empty?
If not. You can already leave the initialized div with content with the formatting tags the way you want.
Ex:
div {
width: 150px;
height: 150px;
border: 1px solid red;
}
<div contenteditable="true">
<p><span>Some Text</span></p>
</div>
So each time a user inserts a newline, it will be with the formatting and content tags already present in the div.

You can do that by listening for the insertion of a line break and replacing it with the required elements, here is an example:
const elm = document.querySelector('#ce');
elm.addEventListener('beforeinput', (event) => {
if (['insertLineBreak', 'insertParagraph'].includes(event.inputType)) {
event.preventDefault();
event.stopPropagation();
const paragraph = document.createElement('p');
const span = document.createElement('span');
span.innerHTML = '​';
paragraph.append(span);
elm.append(paragraph);
const range = new Range();
range.selectNode(span);
range.setStart(span, 0);
range.collapse(true);
const selection = document.getSelection();
if (selection.rangeCount > 0) {
selection.removeAllRanges();
}
selection.addRange(range);
}
});
#ce {
width: 200px;
height: 100px;
border: 1px solid black;
}
<div id="ce" contenteditable="true"></div>
Here, I'm using the beforeinput listener to check when a new line is inserted, I'm preventing that event event.preventDefault() and then,
I'm creating the required elements (a <span> inside a <p>) and I'm using the Selection API to set the caret inside the newly created <span>.
The only unusual thing here is this:
span.innerHTML = '​';
I'm using this because the caret will not be positioned correctly if the <span> doesn't have any content. ​ is a zero width space character.
There are probably better ways of setting the caret's position.

Related

how to insert a span tag inside a button tag?

I am getting a div element using querySelector and able to change the button name, but I want to insert a span tag as well.
var element = document.querySelector("#secondselectionbox"); //This is the div element
(element.childNodes[1].textContent = "Standard"); //Name of the button
I want to wrap the "Standard" in span tag.
I have tried to create a span using createElement, but that just appends the span to the list buttons instead of inside the button.
Tell me if this works the way you want:
var element = document.querySelector("#secondselectionbox");
element.innerHTML += "<span>Standard</span>";
Create a <span> node using createElement.
Change the innerText (or textContent) of the <span> node.
Append the <span> node to the selected element.
OR
You can also set the innerHTML of the selected element but I would avoid doing that.
Check the code snippet below:
var element = document.querySelector("#secondselectionbox"); //This is the div element
const span = document.createElement("span");
span.innerText = "Standard"
element.appendChild(span);
// You can also set the innerHTML, but I would avoid doing that
// element.innerHTML = "<span>Standard</span>"
span {
color: red;
}
<div id="secondselectionbox"></div>
UPDATE: Based on OP's comment
If your div has multiple buttons inside them and you wish to add a span element inside each of those buttons, you can simply loop over all the child nodes of the div and if the child is a button you can append a span to it.
var element = document.querySelector("#secondselectionbox"); //This is the div element
Array.from(element.children).forEach(btn => {
if (btn.tagName === "BUTTON") {
const span = document.createElement("span");
span.innerText = "Standard"
btn.appendChild(span);
}
});
button {
display: block;
margin: 1rem 0;
}
span {
color: red;
}
<div id="secondselectionbox">
<button></button>
<button></button>
<p>Not a button</p>
<button></button>
<p>Not a button</p>
</div>

getting focus() inside a content editable div on tab

There is a main content editable div that displays certain templates with placeholders (underscores) - inside of which there may be other divs, also editable. The inside divs have a class - lets call it highlight.
I'd like to be able to tab through to the divs inside and type away.
I've given the inside divs a tabIndex which makes them tab-able but I'm not able to type unless I explicitly click them. I'd like to be able to do this using the keyboard only.
PS I need a JS solution, not Jquery
Replacing the inside divs with an input/ or text-area works perfectly, except, I'd like to use divs or spans
From another stackoverflow page, I attached an event listener, checking if the div had the class I was looking for, I called .blur() and .focus() on it explicitly - but that doesn't work
// partial code relevant to the problem
function contentEdit(text) {
....
// replace placeholder text (underscores) with div
// and maintain line breaks
text = text.replace(/(\r\n|\n|\r)/gm, '<br/>')
.replace(/[_]+/gm, '<div class="highlight" tabindex="0"> </div>');
vm.content = '<div contenteditable>' + text + '</div>';
var ce = document.getElementById('contenteditable-div');
// tried this approach from stackoverflow
ce.addEventListener('keydown', function(e) {
if (e.keyCode == 9) {
if (e.target.className == 'highlight') {
e.target.blur();
e.target.focus();
}
}
});
.......
}
The blur/ focus block only fires on the second time that condition is true - so, not on the first time a div of that condition is encountered.
Because of the tabIndex, the browser seems as if it's putting the focus on the div when tabbing through (there is a border highlight on it) but the input events don't fire unless you click the div. This is not the case with an input or a textarea - for some reason, they too come into focus but also take key inputs.
demo: codepen.io/anon/pen/bPEJjo
Any ideas/ suggestions why the inner div can't accept keyboard events or how to get them firing?
Listen keyup (better timing than with keydown) on the parent only, it'll bubble up from the child elements. Then create a range to the focused element and set the cursor to its position. Something like below:
function moveCursor(e) {
if (e.key !== 'Tab') {return;}
var element = document.activeElement,
range = document.createRange(),
selection = window.getSelection();
range.setStart(element, 0);
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);
element.focus();
}
document.getElementById('pad').addEventListener('keyup', moveCursor);
.ce {
position: relative;
width: 300px;
height: 50px;
border: 1px solid #000;
margin-bottom: 1em;
}
<div id="pad" contenteditable="true">
<div class="ce" tabindex="1"></div>
<div class="ce" tabindex="2"></div>
<div class="ce" tabindex="3"></div>
<div class="ce" tabindex="4"></div>
</div>

Javascript button ceases to write to texarea once user has added text

I am trying to make a simple text editing box so that I can eventually post text to another section of a website. I'm attempting to make buttons to make text bold, italicized, add a code box etc, (hence insertAdjacentHTML not insertAdjacentText) but I decided to just start making sure I could get plain text to print to a textarea.
I have achieved this easily but now my question becomes how do I make it so that the button still affects the text area after a user has added text to it? the code below will happily type out "hello"'s up until you click on the textarea, and from that point on it refuses to and I can't figure out why.
window.hello = function(textarea) {
var obj = document.getElementById("text");
obj.insertAdjacentHTML('beforeend', 'hello');
}
<body>
<button onclick="hello()">hello</button>
<form>
<p></p>
<textarea id="text"></textarea>
</form>
</body>
As you can read from MDN a textarea can contain only Character data.
This is the reason because you cannot use insertAdjacentHTML and instead you can use the value.
If you need to add text in bold or ... you can use a contenteditable div element.
The snippet:
window.helloDiv = function() {
var obj = document.getElementById("textDiv");
obj.insertAdjacentHTML('beforeend', 'hello');
};
window.helloTxtArea = function() {
var obj = document.getElementById("textTxtArea");
obj.value += 'hello';
}
div {
width: 300px;
height: 100px;
border: 1px;
border-style: solid;
}
textarea {
width: 300px;
height: 100px;
margin-top: 10px;
}
<button onclick="helloDiv()">helloDiv</button>
<button onclick="helloTxtArea()">helloTextArea</button>
<form>
<p></p>
<div id="textDiv" contenteditable="true"></div>
<textarea id="textTxtArea" contenteditable="true"></textarea>
</form>

Add <span> tags using jQuery or Javascript?

Is there a way to wrap the last line of a text in <span> tags using jQuery or Javascript?
#myspan{
color: #db1926;
}
<div id="myDiv">Here is some text, of which I want the last line to be wrapped in span-tags with id="myspan".<br>If it works this line will color red.
</div>
That specific example is quite easy, because the target text node is the last child in its parent; see comments:
// Create the span, give it its ID
var span = document.createElement("span");
span.id = "myspan";
// Get the div
var div = document.getElementById("myDiv");
// Move the last child of the div into the span
span.appendChild(div.childNodes[div.childNodes.length - 1]);
// Append the span to the div
div.appendChild(span);
#myspan{
color: #db1926;
}
<div id="myDiv">Here is some text of which I want the last line to be wrapped in span-tags with as id="myspan".<br>If it works this line will color red.
</div>
Or with jQuery:
// Create the span, give it its ID
var span = $("<span>").attr("id", "myspan");
// Get the div
var div = $("#myDiv");
// Move the last child of the div into the span
span.append(div.contents().last());
// Append the span to the div
div.append(span);
#myspan{
color: #db1926;
}
<div id="myDiv">Here is some text of which I want the last line to be wrapped in span-tags with as id="myspan".<br>If it works this line will color red.
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
As A.Wolff points out, that can be a lot shorter using wrap:
$("#myDiv").contents().last().wrap('<span id="myspan"></span>');
#myspan{
color: #db1926;
}
<div id="myDiv">Here is some text of which I want the last line to be wrapped in span-tags with as id="myspan".<br>If it works this line will color red.
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
See:
DOM4
jQuery documentation

using a div contentEditable innerText and innerHTML neither have newlines to and from database

I'm using a div for people to enter text and then I tried saving
div.innerText
and
div.innerHTML
to my database but when I bring it back from the database and put it back into the div all of the carriage returns or newlines are gone
innerHTML to database
a
b
c
//in database like this <div>a</div><div></div><div>b</div><div></div><div>c</div>
innerText to database
a
a
a
a
a
a
//how it stored in database aaaaaa
if you could tell me how to handle this situation I would appreciate it greatly thank you for your time
div.innerHTML creates an HTML output of your new lines using <div> containers.
Therefore the line breaks will be "replaced".
div.innerText uses the "invisible" character \n or \r\n to mark new lines and it is possible that they are not shown in your database. You can however replace them by <br> tags to see if they are there.
document.getElementById("output").addEventListener("click", function() {
console.log("HTML:");
console.log(document.getElementById("text").innerHTML);
console.log("Text:");
var text = document.getElementById("text").innerText;
console.log(text.replace(/(?:\r\n|\r|\n)/g, '<br>'));
});
#text {
background-color:#FAFAFA;
border: red solid 1px;
height:150px;
width: 200px;
}
<button id="output">
Show in console
</button>
<div id="text" contenteditable>
</div>
console.log(text.replace(/(?:\r\n|\r|\n)/g, '<br>')); replaces all different kinds of possible new lines into <br> tags.
You can substitute <textarea> element for <div> with contenteditable attribute set. Encode, decode .value of textarea using encodeURIComponent(), decodeURIComponent() or format data as JSON utilizing JSON.stringify(), JSON.parse()
var button = document.querySelector("button")
var textarea = document.querySelector("textarea");
button.onclick = function() {
var value = textarea.value
console.log(encodeURIComponent(value)
, decodeURIComponent(value)
, JSON.stringify(value)
, JSON.parse(JSON.stringify(value))
);
}
textarea {
border: 1px solid navy;
width: 300px;
height: 200px;
}
You can use
<button>click</button><br>
<textarea></textarea>

Categories