问题
I want to create script which add <span>
to each letter of contenteditable div. For example:
If you write something in contenteditable div
, in HTML code, you will see:
<div contenteditable="true">
SomeText
</div>
What I have to do to see something like this:
<div contenteditable="true">
<span>S</span>
<span>o</span>
<span>m</span>
<span>e</span>
<span>T</span>
<span>e</span>
<span>x</span>
<span>t</span>
</div>
I wrote some code (using Rangy), but it doesn't work. You can see that code below, but I do not recommend it because it is to long and, as I said, doesn't work.
$('#Box').keypress(function() {
setTimeout(function() {
var selLenght = getCaretCharacterOffsetWithin(document.getElementById('Box'));
var precedingChar = "",
sel, range, precedingRange;
sel = rangy.getSelection();
range = sel.getRangeAt(0).cloneRange();
range.setStart(document.getElementById('Box'), 0);
sel.setSingleRange(range);
sel.removeAllRanges();
range.setStart(document.getElementById('Box'), selLenght - 21);
sel.setSingleRange(range);
/*
var newElem = document.createElement('span');
newElem.className = 'test';
$(newElem).html(range.extractContents());
range.insertNode(newElem);
$('#MainBox > span:empty').remove();
*/
rangy.getSelection().move('character', 0);
});
});
function getCaretCharacterOffsetWithin(element) {
var caretOffset = 0;
if (typeof window.getSelection != "undefined") {
var range = window.getSelection().getRangeAt(0);
var preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
caretOffset = preCaretRange.toString().length;
} else if (typeof document.selection != "undefined" && document.selection.type != "Control") {
var textRange = document.selection.createRange();
var preCaretTextRange = document.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}
return caretOffset;
}
div{
width: 400px;
height: 200px;
border: 1px solid black;
}
<script src="https://github.com/timdown/rangy/blob/master/lib/rangy-core.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" id="Box"></div>
How can I do something like that in JavaScript and/or JQuery and/or free for commercial use external library?
Thanks for help.
回答1:
UPDATE:
Using this Github solution I solved the issue of chars appearing on the beginning.
Does this help you?
var myDiv = document.getElementById("yourDiv");
function doJob(){
var myDivContent = myDiv.textContent.trim();
var myDivContentSplit = myDivContent.split("");
myDiv.innerHTML = "";
for(var i=0; i<myDivContentSplit.length ; i++){
var newSpan = document.createElement('span')
newSpan.innerHTML = myDivContentSplit[i];
myDiv.appendChild(newSpan);
}
setEndOfContenteditable(myDiv);
}
myDiv.addEventListener("keyup", doJob);
function setEndOfContenteditable(contentEditableElement)
{
var range,selection;
if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
{
range = document.createRange();//Create a range (a range is a like the selection but invisible)
range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
selection = window.getSelection();//get the selection object (allows you to change selection)
selection.removeAllRanges();//remove any selections already made
selection.addRange(range);//make the range you have just created the visible selection
}
else if(document.selection)//IE 8 and lower
{
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
range.select();//Select the range (make it the visible selection
}
}
div{
border: 1px solid #999;
padding: 10px;
}
span{
background-color: #ea0;
}
<div contenteditable="true" id="yourDiv">
SomeText
</div>
回答2:
Using jQuery you can do something like the following, also note that we need some helper functions to manage the cursor position.
var box = $('#Box');
var button = $('button');
box.on('input', function(e) {
restoreCaret = saveCaretPosition(this);
box.html(wrapLetters(box.text()));
restoreCaret();
});
var textContent = '';
button.on('mousedown', function() {
button.text('Hide HTML');
textContent = box.text();
box.text(box.html());
});
button.on('mouseup', function() {
button.text('Show HTML');
box.text(textContent);
box.html(wrapLetters(textContent));
});
/* HELPERS */
function wrapLetters(textContent) {
return textContent.split('').map(function(letter) {
return '<span>' + letter + '</span>';
}).join('');
}
function saveCaretPosition(context) {
var selection = window.getSelection();
var range = selection.getRangeAt(0);
range.setStart(context, 0);
var len = range.toString().length;
return function restore() {
var pos = getTextNodeAtPosition(context, len);
selection.removeAllRanges();
var range = new Range();
range.setStart(pos.node, pos.position);
selection.addRange(range);
}
}
function getTextNodeAtPosition(root, index) {
var lastNode = null;
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, function next(elem) {
if (index > elem.textContent.length) {
index -= elem.textContent.length;
lastNode = elem;
return NodeFilter.FILTER_REJECT
}
return NodeFilter.FILTER_ACCEPT;
});
var c = treeWalker.nextNode();
return {
node: c ? c : root,
position: c ? index : 0
};
}
#Box {
width: 400px;
height: 100px;
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" id="Box"></div>
<button>Show HTML</button>
回答3:
I think this is what you need.
Set "Id" to your contenteditable div
and then write this simple script...
var text = document.getElementById("contenteditableDiv");
var string = "SomeText";
string.split("");
var i = 0, length = string.length;
for (i; i < length; i++) {
text.innerHTML += "<span>" + string[i] + "</span>";
}
https://jsfiddle.net/f85zsLdf/3/ if you need it...
Let me know if this helpful for you!
来源:https://stackoverflow.com/questions/45877256/javascript-add-span-to-each-letter-written-in-contenteditable-div