How can I convert the characters of a div into spans?
For example, I'd like to convert this:
<div>
Hello World
</div>
Into this:
<div>
<span>H</span>
<span>e</span>
<span>l</span>
<span>l</span>
<span>o</span>
<span>W</span>
<span>o</span>
<span>r</span>
<span>l</span>
<span>d</span>
</div>
I've tried this StackOverflow suggestion, but that converts spaces into spans. What I need is to convert only characters to spans:
$("div").each(function (index) {
var characters = $(this).text().split("");
$this = $(this);
$this.empty();
$.each(characters, function (i, el) {
$this.append("<span>" + el + "</span");
});
});
You can use String#replace method and html() method with a callback to reduce the code.
$("div").html(function(index, html) {
return html.replace(/\S/g, '<span>$&</span>');
});
$("div").html(function(index, html) {
return html.replace(/\S/g, '<span>$&</span>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
Hello World
</div>
You can try with this simple JavaScript.
(function() {
var div, i, span = "";
div = document.querySelectorAll("div")[0];
for (i = 0; i < div.innerText.length; i++) {
if (div.innerText[i] !== " ") {
span += "<span>";
span += div.innerText[i];
span += "</span>";
}
}
div.innerHTML = span;
}());
<div>
Hello World
</div>
I'd prefer to use regular expression:
var txt = $('#container').text();
var newTxt = txt.replace(/\w/g,function(c){
return '<span>'+c+'</span>';
})
$('#container').html(newTxt);
span {
display:inline-block;
background-color:#dfdfdf;
color:#aaa;
padding:3px;
margin:3px;
border-radius:3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
Hello World
</div>
var textWrapper = document.querySelector('h1');
textWrapper.innerHTML = textWrapper.textContent.replace(/\S/g, "<span class='letter'>$&</span>");
<h1>Hello world</h1>
$("div").each(function (index) {
var characters = $(this).text().split("");
$this = $(this);
$this.empty();
$.each(characters, function (i, el) {
if(el != ' ')
$this.append("<span>" + el + "</span");
});
put a condition for space
try:
$("div").each(function (index) {
var characters = $(this).text().split("");
characters = characters.filter(v => v != '');
$(this).empty();
for(var i =0; i < characters.length; i++) {
$(this).append("<span>" + characters[i] + "</span");
}
});
tried to write as little as I can
html
<div>
HelloWorld
</div>
js
var d=$("div");
var text=d.text();
text=$.trim(text);
d.empty();
for(i=0;i<text.length;i++){
var span=$("<span></span>");
span.text(text[i]);
d.append(span)
}
Related
Given a DOM structure like this:
<div>
<div>
<span>
<img/>
<i>
<span></span>
<meter></meter>
</i>
<a><span></span></a>
</span>
</div>
<nav>
<form>
<input/>
<button></button>
</form>
</nav>
</div>
Wondering how you take that and then return a flat array of all the selectors:
[
'div > div > span > img',
'div > div > span > i > span',
'div > div > span > i > meter',
'div > div > span > a > span',
'div > nav > form > input',
'div > nav > form > button'
]
My attempt hasn't gotten anywhere:
function outputSelectors(array, node) {
var tag = node.tagName
array.push(tag)
for (var i = 0, n = node.children.length; i < n; i++) {
var child = node.children[i]
outputSelectors(array, child)
}
}
outputSelectors([], document.body.children[0])
Not sure where to go from here.
One possible, a non-recursive approach going from top (root, to be precise) to bottom:
function collectLeafNodePathes(root) {
const paths = [];
const selectorParts = [];
let el = root;
while (el) {
const tagName = el.tagName.toLowerCase();
if (el.childElementCount) {
selectorParts.push(tagName);
el = el.firstElementChild;
continue;
}
paths.push(selectorParts.concat([tagName]).join(' > '));
do {
if (el.nextElementSibling) {
el = el.nextElementSibling;
break;
}
el = el.parentNode;
selectorParts.pop();
if (el === root) {
el = null;
}
} while (el);
}
return paths;
}
const selectors = collectLeafNodePathes(document.getElementById('xxx'));
console.log(selectors);
<div id="xxx">
<div>
<span>
<img/>
<i>
<span></span>
<meter></meter>
</i>
<a><span></span></a>
</span>
</div>
<nav>
<form>
<input/>
<button></button>
</form>
</nav>
</div>
That last part (do-while loop) is a bit rough around the edges, though; open to any improvement.
I've used helper properties (childElementCount, firstElementChild, nextElementSibling) to skip checking for text nodes and stuff. If that's not an option (because of compatibility reasons), it's easy to either implement polyfills or just 'rewind' the loop on non-element nodes.
You can map all elements on a page using the getPath method from this answer.
Best try this in your own console, as the snippet takes some time to run, and the snippet's console doesn't seem to handle the output properly.
jQuery.fn.extend({
getPath: function () {
var path, node = this;
while (node.length) {
var realNode = node[0], name = realNode.localName;
if (!name) break;
name = name.toLowerCase();
var parent = node.parent();
var sameTagSiblings = parent.children(name);
if (sameTagSiblings.length > 1) {
allSiblings = parent.children();
var index = allSiblings.index(realNode) + 1;
if (index > 1) {
name += ':nth-child(' + index + ')';
}
}
path = name + (path ? '>' + path : '');
node = parent;
}
return path;
}
});
const allElements = $("*");
const allPaths = allElements.map((_, e) => $(e).getPath());
console.log(allPaths);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Here is a version without jQuery, if that's preferable:
function getPath (node) {
var path;
while (node.parentElement) {
var name = node.localName;
if (!name) break;
name = name.toLowerCase();
var parent = node.parentElement;
var sameTagSiblings = [...parent.children].filter(e => e.localName === name);
if (sameTagSiblings.length > 1) {
allSiblings = parent.children;
var index = [...allSiblings].indexOf(node) + 1;
if (index > 1) {
name += ':nth-child(' + index + ')';
}
}
path = name + (path ? '>' + path : '');
node = parent;
}
return path;
};
const allElements = document.querySelectorAll("*");
const allPaths = [...allElements].map(e => getPath(e));
console.log(allPaths);
Slightly modifying this solution to get path and this one to get leaf nodes.
function getPath(node)
{
var path;
while (node.parentNode )
{
name = node.nodeName;
if (!name) break;
var parent = node.parentNode;
path = name + (path ? ' > ' + path : '');
node = parent;
}
return path;
}
function getLeafNodes()
{
var allNodes = document.getElementsByTagName("*");
var leafNodes = Array.from( allNodes ).filter(function(elem) {
return !elem.hasChildNodes();
});
return leafNodes;
}
var leadNodes = getLeafNodes() ;
var output = leadNodes.map( s => getPath(s) );
console.log(output);
<div>
<div>
<span>
<img/>
<i>
<span></span>
<meter></meter>
</i>
<a><span></span></a>
</span>
</div>
<nav>
<form>
<input/>
<button></button>
</form>
</nav>
</div>
You can create recursive function and check if current element contains children using children() method.
const result = []
const getTag = (el) => el.prop('tagName').toLowerCase()
function print(el, prev = '') {
prev = prev.length ? prev : getTag(el)
const children = el.children();
if(!children.length) result.push(prev)
else {
children.each(function() {
let tag = getTag($(this))
let str = prev + (prev.length ? ' > ' : '') + tag;
print($(this), str)
})
}
}
print($('#start'))
console.log(result)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="start">
<div>
<span>
<img/>
<i>
<span></span>
<meter></meter>
</i>
<a><span></span></a>
</span>
</div>
<nav>
<form>
<input/>
<button></button>
</form>
</nav>
</div>
To get array of unique selectors you can use Set on final result to remove duplicates.
let result = []
const getTag = (el) => el.prop('tagName').toLowerCase()
function print(el, prev = '') {
prev = prev.length ? prev : getTag(el)
const children = el.children();
if(!children.length) result.push(prev)
else {
children.each(function() {
let tag = getTag($(this))
let str = prev + (prev.length ? ' > ' : '') + tag;
print($(this), str)
})
}
}
print($('#start'))
result = [...new Set(result)]
console.log(result)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="start">
<div>
<span>
<img/>
<i>
<span></span>
<meter></meter>
</i>
<a><span></span></a>
<a><span></span></a>
</span>
</div>
<nav>
<form>
<input/>
<button></button>
</form>
</nav>
</div>
I have a span tag and a button tag
<span class="myspan">1</span>
<button id="add">Add +1</button>
var arr=["myspan1","myspan2","myspan3","myspan4"}
I want to append more span tag with new class from this array with increment value by clicking button.
Like this output:
<span class="myspan1">1</span>
<span class="myspan2">2</span>
<span class="myspan3">3</span>
<span class="myspan4">4</span>
i try `
this JsFiddle
But i can not add class name to new append tag from array.
Another useful link for appending tag with new class from array
http://jsbin.com/nojipowo/2/edit?html,css,js,output
...
But i can not bring my desire output at any case...enter code here
value increaseesenter code here this snippet
<script> var i = 0; function buttonClick() {i++; document.getElementById('inc').value = i; } </script> <button onclick="buttonClick();">Click Me</button> <input type="text" id="inc" value="0"></input>
another attempt...anyone can help.. to get desire output
var i=6;
var backgrounds = ["myspan1", "myspan2", "myspan4"];
var elements = document.getElementsByClassName("myspan");var len = backgrounds.length;
$("#add").click( function() {
(i < elements.length){
$(".new-field").append('<span class="myspan">1</span><script');
var value = parseInt($(".myspan").text(), 10) + 1;
elements[i].className += ' ' + backgrounds[i%len];
i++;
$(".background").text(i);
}
});
*/
<span class="myspan">1</span>
<button id="add">Add +1</button>
<div class="new-field">
</div>
<script> var i = 0; function buttonClick() {i++; document.getElementById('inc').value = i; } </script> <button onclick="buttonClick();">Click Me</button> <input type="text" id="inc" value="0"></input>
Try this check the span length via parseInt($(".myspan").length) .And use with Array#forEach for iterate the array instead of increment i.parseInt used convert ths string to number
var i=6;
var backgrounds = ["myspan1", "myspan2", "myspan4"];
var len = backgrounds.length;
$("#add").click( function() {
var len = parseInt($(".myspan").length)
backgrounds.forEach(function(a){
$(".new-field").append('<span class="'+a+'">'+(len++)+'</span>');
})
console.log($(".new-field").html())
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="myspan">1</span>
<button id="add">Add +1</button>
<div class="new-field">
</div>
Check the fiddle. Hope this helps!
HTML :
<div id="mainContainer">
<span class="myspan">1</span>
</div>
<button id="add">Add +1</button>
JS :
var arr = ["myspan1", "myspan2", "myspan3", "myspan4"];
$("#add").on("click", function() {
var spans = $("span");
var classList = [];
$.each(spans, function() {
var elemCls = $(this).attr('class').length > 1 ? $(this).attr('class').split(' ') : $(this).attr('class');
if (elemCls) {
$.each(elemCls, function() {
classList.push(this.toString());
});
}
});
$.each(arr, function(i, e) {
if ($.inArray(e, classList) == -1) {
$("#mainContainer").append("<span class='" + e + "'>" + parseInt(spans.length + 1) + "</span>");
return false;
}
});
});
Here is my code
And I am trying to change the color of any match in the <li> elements that matches the text in the <input> element. So if you type lets say "this is a simple text" the result should look like this:
<input value="this is a simple text" id="term"/>
<ul id="ul-id" >
<li id="li-id-1"> hello budy <span style="color:red">this</span> <span style="color:red">is</span> really <span style="color:red">simple</span> stuff </li>
<li id="li-id-2"> <span style="color:red">this</span> <span style="color:red">is</span> it</li>
<li id="li-id-3"> there <span style="color:red">is</span> something here</li>
<li id="li-id-4"> plain <span style="color:red">text</span> file</li>
</ul>
Any help would be appreciated.
Thank you.
You can remove the delay function if you like, but this would lead to a performance loss:
// https://stackoverflow.com/a/9310752/1636522
RegExp.escape = function (text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
};
window.addEventListener('load', function () {
var wrapper = '<span style="background:yellow">$&</span>';
var input = document.getElementById('term');
var list = document.getElementById('ul-id');
var items = list.getElementsByTagName('li');
var l = items.length;
var source = Array.prototype.map.call(
items, function (li) { return li.textContent; }
);
var cmp = function (a, b) {
return b.length - a.length;
};
var delay = function (fn, ms) {
var id, scope, args;
return function () {
scope = this;
args = arguments;
id && clearTimeout(id);
id = setTimeout(function () {
fn.apply(scope, args);
}, ms);
};
};
term.addEventListener('keyup', delay(function () {
var i, re, val;
if (val = this.value.match(/[^ ]+/g)) {
val = val.sort(cmp).map(RegExp.escape);
re = new RegExp(val.join('|'), 'g');
for (i = 0; i < l; i++) {
items[i].innerHTML = source[i].replace(re, wrapper);
}
}
else {
for (i = 0; i < l; i++) {
items[i].textContent = source[i];
}
}
}, 500));
});
<input value="" id="term"/>
<ul id="ul-id" >
<li id="li-id-1"> hello budy this is really simple stuff </li>
<li id="li-id-2"> this is it</li>
<li id="li-id-3"> there is something here</li>
<li id="li-id-4"> plain text file</li>
</ul>
Similar topic: https://stackoverflow.com/a/20427785/1636522.
I don't know if it is possible with only RegEx, but here is a jQuery solution:
$('#term').change(function() {
var inpArr = $(this).val().split(" ");
$('#ul-id li').each(function() {
var liArr = $(this).text().split(" ");
var txt = "";
$.each(liArr, function(i, v) {
if(inpArr.indexOf(v) > -1) {
txt += "<span class='red'>"+ v +"</span> ";
} else {
txt += v + " ";
}
});
$(this).html(txt);
});
});
span.red {
color: red;
}
And the working fiddle: https://jsfiddle.net/ermk32yc/1/
Plain JS solution
var list = document.querySelector('#ul-id'),
listItem,
listItems,
term = document.querySelector('#term'),
oldRef = list.innerHTML,
oldValue;
term.addEventListener('keyup', function () {
var regExp,
value = term.value;
if (oldValue !== value) {
oldValue = value;
// Reset
list.innerHTML = oldRef;
if (value.trim() !== '') {
listItems = list.querySelectorAll('#ul-id li');
regExp = new RegExp(term.value, 'g');
// Perform matching
for (var i = 0; i < listItems.length; i++) {
listItem = listItems[i];
listItem.innerHTML = listItem.innerHTML.replace(regExp, function (match) {
return '<span class="matched">' + match + '</span>';
});
}
}
}
}, false);
.matched {
color: red;
}
<input id="term"/>
<ul id="ul-id" >
<li id="li-id-1"> hello budy this is really simple stuff </li>
<li id="li-id-2"> this is it</li>
<li id="li-id-3"> there is something here</li>
<li id="li-id-4"> plain text file</li>
</ul>
You might do something like this
$('#term').change(function (i) {
var terms = $('#term').val().split(" ");
$('#ul-id > li').each(function (i, el) {
var val = $(el).html().replace(/<[^<]+>/g, ''),
match;
terms.forEach(function (term) {
val = val.replace(new RegExp(term, 'g'),
'<span style="color:red">' + term + '</span>');
});
$(el).html(val);
});
});
https://jsfiddle.net/1vm0259x/5/
You can use the below solution if there is no html contents in the li elemnets
if (!RegExp.escape) {
RegExp.escape = function(value) {
return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&")
};
}
var lis = [].slice.call(document.querySelectorAll('#ul-id li'));
lis.forEach(function(el) {
el.dataset.text = el.innerHTML;
});
document.querySelector('#term').addEventListener('change', function() {
var parts = this.value.split(' ').map(function(value) {
return '\\b' + RegExp.escape(value) + '\\b';
});
var regex = new RegExp(parts.join('|'), 'g');
lis.forEach(function(el) {
el.innerHTML = el.dataset.text.replace(regex, function(part) {
return '<span class="highlight">' + part + '</span>'
})
});
});
.highlight {
color: red;
}
<input id="term" />
<ul id="ul-id">
<li id="li-id-1">hello budy this is really simple stuff</li>
<li id="li-id-2">this is it</li>
<li id="li-id-3">there is something here</li>
<li id="li-id-4">plain text file</li>
</ul>
With jQuery
if (!RegExp.escape) {
RegExp.escape = function(value) {
return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&")
};
}
$('#term').on('change keyup', function() {
//$('#ul-id li .highlight').contents().unwrap();//remove previous highlights
var parts = this.value.split(' ').map(function(value) {
return '\\b' + RegExp.escape(value) + '\\b';
});
var regex = new RegExp(parts.join('|'), 'g');
$('#ul-id li ').each(function() {
var text = $(this).text();
$(this).html(text.replace(regex, function(part) {
return '<span class="highlight">' + part + '</span>'
}))
})
});
.highlight {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input id="term" />
<ul id="ul-id">
<li id="li-id-1">hello budy this is really simple stuff</li>
<li id="li-id-2">this is it</li>
<li id="li-id-3">there is something here</li>
<li id="li-id-4">plain text file</li>
</ul>
you can handle blur event or you can copy paste the inner function code to wherever it is required. this is the guide code here you can more explore match function as per your requirement and then can traverse your li elements as shown below.
$('#term).blur(function() {
$('#ul-id li').foreach(function()
{
if($(this).text().match($("#term").text()))
{
///set/change here color of li element
$(this).css('color', 'red');
}
}
}
How do I edit the selected text of a textarea form element?
EDIT: as in edit it in-place, replacing the orignal text.
This works:
function replaceIt(txtarea, newtxt) {
$(txtarea).val(
$(txtarea).val().substring(0, txtarea.selectionStart)+
newtxt+
$(txtarea).val().substring(txtarea.selectionEnd)
);
}
$("button").on('click', function() {
replaceIt($('textarea')[0], 'fun')
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea>Hello world.</textarea>
<button>Replace with fun</button>
I found this:
function wrapText(elementID, openTag, closeTag) {
var textArea = $('#' + elementID);
var len = textArea.val().length;
var start = textArea[0].selectionStart;
var end = textArea[0].selectionEnd;
var selectedText = textArea.val().substring(start, end);
var replacement = openTag + selectedText + closeTag;
textArea.val(textArea.val().substring(0, start) + replacement + textArea.val().substring(end, len));
}
$('button').on('click', function() {
wrapText('test', '<b>', '</b>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="test">This is a test</textarea>
<button>Surround with <b> tag</button>
But personaly its not working with content-editable divs.
Let's say I have a DIV as below.
<div id="mydiv">
<p class="abc">some text here</p>
<p class="xyz"><img src="img.jpg" title="my img"/> some "double quoted text" here</p>
</div>
I read the inner html of the div.
var originalcontent = $("mydiv").html();
Now I need to replace double quotes for the texts only but not for the tag attributes. So my output should be as below.
var myoutput = '<p class="abc">some text here</p><p class="xyz"><img src="img.jpg" title="my img"/> some "double quoted text" here</p>'
Can you suggest me a solution please. Thank you!
Try this:
function replace_text(node){
node = node || document.getElementById('mydiv'); // Change 'mydiv' if you need
var children = node.childNodes;
var i = 0;
while(node = children[i]){ // While-loop
if (node.nodeType == 3){ // Some text, replace
if (node.textContent) { // Not IE (IE's equivalent to textContent is nodeValue)
node.textContent = node.textContent.replace(/"/g, '"');
}
else { // IE
node.nodeValue = node.nodeValue.replace(/"/g, '"');
}
} else { // not text, take step further
replace_text(node);
}
i++;
}
} // While-loop
// Don't forget to call function
replace_text();
With Jquery You can do this :
String.prototype.replaceAll = function(stringToFind,stringToReplace){
var temp = this;
var index = temp.indexOf(stringToFind);
while(index != -1){
temp = temp.replace(stringToFind,stringToReplace);
index = temp.indexOf(stringToFind);
}
return temp;
};
$(function(){
$("#mydiv").children().each(function(){
var text=$(this).text();
text=text.replaceAll("\"",""");
//alert(text);
$(this).text(text);
});
});