How to print selectors of DOM objects - javascript

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>

Related

Javascript get text from child within child

I'm busy developing a wordpress plugin to look for numbers and hide them by formating the number and replacing it with 0000..., Example:
<a href="tel:0000000000">
<span>
<span>0000 000 000</span>
</span>
</a>
I have javascript that queries the <a href=""> tag. I then get the children of the a tag. However, my issue is that because I don't know what or how many children ill be working with i can't assume it will be 1 or 2 thus I have to predict and look for it.
Javascript code:
// REMOVE SPACES IN STRING
let replaceStr = function (self) {
let value = self.replace(/[- )(]/g, '')
return value
};
// REMOVE LETTERS FROM STRING
let rmLetters = function (self) {
// let value = self.replace( /^\D+/g, '')
let value = self.replace(/\D+%?/g, "");
return value
}
let a = document.querySelectorAll("a[href^='tel:'], a[href^='Tel:'], a[href^='callto:']");
for (var i = 0; i < a.length; i++) {
let hrefSlice = a[i].href.slice(4);
let countChildren = a[i].childElementCount
if (a[i].hasChildNodes()) {
let a_childNodes = a[i].children;
if (a_childNodes.length > 1) {
for (let l = 0; l < a_childNodes.length; l++) {
if (replaceStr(a_childNodes[l].textContent) === hrefSlice) {
a_childNodes[l].textContent = replaceStr(a_childNodes[l].textContent).slice(0, 4) +
"...Click Here";
} else if (replaceStr(rmLetters(a_childNodes[l].textContent)) === hrefSlice) {
a_childNodes[l].textContent = replaceStr(rmLetters(a_childNodes[l].textContent)).slice(
0, 4) + "...Click Here";
}
}
}
}
}
}
Not sure if I got you right but I'd do it like this:
document.querySelector('#hideButton').addEventListener('click', () => {
const phoneAnchors = document.querySelectorAll('a[href^="tel:"], a[href^="Tel:"], a[href^="callto:"]');
phoneAnchors.forEach((phoneAnchor) => {
const phoneNumber = phoneAnchor.href.split(':')[1] || '';
phoneAnchor.href = phoneAnchor.href.replace(/[0-9]/g, '0');
phoneAnchor.querySelectorAll('*').forEach(childNode => {
if (childNode.textContent.replace(/[ ]/g, '') === phoneNumber) {
childNode.textContent = childNode.textContent.replace(/[0-9]/g, '0');
}
});
});
});
a {
display: block;
}
<a href="tel:1234567890">
<span>
<span>1234 567 890</span>
</span>
</a>
<a href="tel:0987654321">
<span>
<span>0987 654 321</span>
</span>
</a>
<a href="tel:1122334455">
<span>
<span>1122334455</span>
</span>
</a>
<hr>
<button id="hideButton">Hide Phone Numbers</button>

Find text (child text nodes) and wrap it in a paragraph

I need a function that finds text (child text nodes) inside some (for this example the div) elements and wraps the text in a paragraph.
Text1
<div>
<div>
Text2
<div>Text3</div>
</div>
<div>Text4</div>
<p>Text5</p>
</div>
<div>Text6</div>
<div>
Text7
<p>Text8</p>
Text9
</div>
tried did it like this:
const fn = (doc) => {
const coll = [...doc.childNodes];
coll.forEach(el => {
if (el.tagName === 'DIV' && el.childElementCount === 0) {
el.innerHTML = `<p>${el.innerHTML}</p>`;
}
if (el.childElementCount > 0) {
el.childNodes.forEach(item => {
if (item.nodeType === 3 && item.textContent.trim()) {
const content = item.textContent.trim();
item.innerHTML = `<p>${content}</p>`;
console.log('2: ', item.innerHTML);
}
});
fn(el);
}
});
}
but it works wrong - in if condition (el.childElementCount > 0) in console log, I got all needed nodes in p tags. but not in result. item.innerHTML = `<p>${content}</p>`; not apply it to document :(.
Can anyone help to fix it?
result i need:
Text1
<div>
<div>
<p>Text2</p>
<div><p>Text3</p></div>
</div>
<div><p>Text4</p></div>
<p>Text5</p>
</div>
<div><p>Text6</p></div>
<div>
<p>Text7</p>
<p>Text8</p>
<p>Text9</p>
</div>
You can use replaceWith() to replace the text node with the paragraph element
function filterTextNode(node) {
var textNodes = [];
for (node = node.firstChild; node; node = node.nextSibling) {
if (node.nodeType == 3 && node.textContent.trim()) textNodes.push(node);
else textNodes = textNodes.concat(filterTextNode(node));
}
return textNodes;
}
function wrapTextNode(text) {
var p = document.createElement('p');
p.innerHTML = text.textContent;
text.replaceWith(p);
}
const fn = (doc) => {
var textNodes = filterTextNode(doc);
textNodes.forEach(text => {
if (text.parentNode.tagName != 'P') {
wrapTextNode(text);
}
});
}
fn(document.body)
p {
color: red;
}
Text1
<div>
<div>
Text2
<div>Text3</div>
</div>
<div>Text4</div>
<p>Text5</p>
</div>
<div>Text6</div>
<div>
Text7
<p>Text8</p>
Text9
</div>
References
Find all text nodes in HTML page
https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/replaceWith
By considering the childElementCount of the div we can get your desired result. Rewrite your function like below.
const fn = (document) => {
let elements = document.getElementsByTagName('div');
elements = Array.prototype.slice.call(elements);
elements.forEach(el => {
if (el.innerHTML && el.childElementCount === 0) {
el.innerHTML = `<p>${el.innerHTML}</p>`;
}
});
}
var elements = document.getElementsByTagName('div');
for(var i=0;i<elements.length;i++){
if(elements[i]===0){
console.log(elements[i].textContent);
}
else{
var y=elements[i].innerHTML
console.log(y)
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>testing result</title>
</head>
<body>
<div>Text1</div>
<div>
<div>Text2</div>
<p>Text3</p>
</div>
<div>Text4</div>
</body>
</body>
</html>
i tryed this but i cant get last two div(4 and 2) like this output in the console <div>text4</div> and <div>text2</div> i hope this my help and i dont know how to print last two div innerHTML

How to loop in nested loop through multiple arrays?

I'm trying to find and replace URL's for each a element.
Each wrap has data-folder with a path to a file.
Each <a> element inside each wrap links to a file. The problem is that each <a> can be linked with folder up, like '../' or multiple- '../../../'.
I have to check how many '../' each has and for each '../' remove one folder. like '/folder/'
This is my HTML:
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/">
Link
Link
Link
</div>
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/data_folder_4">
Link
</div>
And jQuery:
console.clear();
var wrap = $(".wrap");
$.each(wrap, function(index, value) {
var file = $(this).attr("data-folder");
var fileArray = file.split("/");
var links = $(this).find("a");
// loop for link elements (a), it looops 4 times in this case
$.each( links, function( ind, val ){
var $this = $(this);
var aHref = $(this).attr('href');
var hrToArr = aHref.split("/");
console.log(hrToArr);
$.each(hrToArr, function( indx, va ){
if( va == '..' ){
fileArray.pop();
$this.addClass( fileArray );
console.log(va);
}
});
})
});
The results should be:
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3">
Link
Link
Link
</div>
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/data_folder_4">
Link
</div>
Codepen here: https://codepen.io/rolandas/pen/XLEXPR?editors=1010
var wrap = $(".wrap");
$.each(wrap, function(index, value) {
var file = $(this).attr("data-folder");
var fileArray = file.split("/").filter(Boolean);
var links = $(this).find("a");
// loop for link elements (a), it looops 4 times in this case
$.each( links, function( ind, val ){
var $this = $(this);
var aHref = $(this).attr('href');
var hrToArr = aHref.split("/").filter(Boolean);
/* console.log(hrToArr) */;
let a = fileArray;
let b = [];
$.each(hrToArr, function( indx, va ){
if(va === '..') {
fileArray.pop();
} else {
b.push(va)
}
});
$this.attr('href', a.concat(b).join('/'));
})
});
Output:
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/">
Link
Link
Link
</div>
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/data_folder_4">
Link
</div>
Probably you don't need to remove ../ because servers/browsers usually support finding subdirectory in url (e.g /a/b/../c will be interpret as /a/c). However I do it in below code
let w=[...document.querySelectorAll('.wrap')];
for(let v of w) {
let f = v.dataset.folder.split('/');
for(let a of [...v.children]) {
let n= a.outerHTML.match(/href="(.*)">/)[1].match(/\.\.\//g);
n = n ? n.length : 0;
let p= n==0 ? f : f.slice(0,-n||1);
a.href = p.join('/') + a.pathname.replace(/\.\.\//g,'');
}
}
let w=[...document.querySelectorAll('.wrap')];
for(let v of w) {
let f = v.dataset.folder.split('/');
for(let a of [...v.children]) {
let n= a.outerHTML.match(/href="(.*)">/)[1].match(/\.\.\//g);
n = n ? n.length : 0;
let p= n==0 ? f : f.slice(0,-n||1);
a.href = p.join('/') + a.pathname.replace(/\.\.\//g,'');
}
}
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3">
Link
Link
Link
</div>
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/data_folder_4">
Link
</div>

How to make the what happening box like twitter in our site?

I am doing this by taking the cursor position from the content-editable box. When a new tag is created the cursor comes before the tag but it should be after the tag. Also i am not able to merge/split the tag.
Please give some idea how can i do this.
Visit (https://plnkr.co/edit/DSHKEcOnBXi54KyiMpaT?p=preview) !
What i want here, after pressing the enter key for new tag the cursor should be at the end of tag while it is not and also the merging/spliting functionality like the twitter what's happening box.
Thanks in advance.
Now this code is working fr me
$scope.myIndexValue = "5";
$scope.searchTag = function(term) {
var tagList = [];
angular.forEach($rootScope.tags, function(item) {
if (item.name.toUpperCase().indexOf(term.toUpperCase()) >= 0) {
tagList.push(item);
}
});
$scope.tag = tagList;
return $q.when(tagList);
};
$scope.getTagText = function(item) {
// note item.label is sent when the typedText wasn't found
return '<a>#<i>' + (item.name || item.label) + '</i></a> ';
};
$scope.resetDemo = function() {
// finally enter content that will raise a menu after everything is set up
$timeout(function() {
//var html = "Tell us something about this or add a macro like brb, omw, (smile)";
var htmlContent = $element.find('#htmlContent');
var html = "";
if (htmlContent) {
var ngHtmlContent = angular.element(htmlContent);
ngHtmlContent.html(html);
ngHtmlContent.scope().htmlContent = html;
// select right after the #
mentioUtil.selectElement(null, htmlContent, [0], 8);
ngHtmlContent.scope().$apply();
}
}, 0);
};
HTML :
<div class="share_tags fs-12">
<div class="row margin_row">
<div class="col-md-12 no_padding">
<div class="form-group">
<div contenteditable="true" mentio
mentio-typed-term="typedTerm"
mentio-macros="macros"
mentio-require-leading-space="true"
mentio-select-not-found="true"
class="editor tag" placeholder="Tell Us something about This"
mentio-id="'htmlContent'"
id="htmlContent"
ng-model="htmlContent">
</div>
</div>
<mentio-menu
mentio-for="'htmlContent'"
mentio-trigger-char="'#'"
mentio-items="tag"
mentio-template-url="/people-mentions.tpl"
mentio-search="searchTag(term)"
mentio-select="getTagText(item)"
></mentio-menu>
</div>
</div>
<script type="text/ng-template" id="/people-mentions.tpl">
<ul class="list-group user-search">
<li mentio-menu-item="tag" ng-repeat="tag in items" class="list-group-item">
<span ng-bind-html="tag.name | mentioHighlight:typedTerm:'menu-highlighted' | unsafe"></span>
</li>
</ul>
</script>
</div>
Reference link
http://jeff-collins.github.io/ment.io/?utm_source=angular-js.in&utm_medium=website&utm_campaign=content-curation#/
is working fine for me.
This is not working perfectly but for the time being i am using this code.
In app.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function ($scope, $filter, $element) {
var tags;
$scope.allTags = ['Tag1', 'PrivateTag', 'Xtag', 'PublicTag1', 'newTag', 'socialTag', 'cricketTag'];
var replacedTag = '';
var replacedIndex;
var data;
$scope.log = function (name) {
$scope.tags = [];
$('ul').html(' ');
console.log("here", $('ul'))
var data = $('textarea').val();
replacedIndex = data.indexOf(replacedTag)
console.log('test', name, replacedTag, replacedIndex, data);
var replacedData = data.substring(0, replacedIndex - 1) + ' #' + name + data.substr(replacedIndex + replacedTag.length);
$('textarea').val(replacedData);
$('textarea').keyup();
}
f = $scope.log;
$('textarea').on('keyup', function (e) {
function getIndexOf(arr, val) {
var l = arr.length,
k = 0;
for (k = 0; k < l; k = k + 1) {
if (arr[k] === val) {
return k;
}
}
return false;
}
$('ul').html('');
$scope.tags = [];
tags = $(this).val().match(/#\S+/g);
console.log("---tags-", tags)
var a = data = $(this).val();
if (tags && tags.length) {
tags.forEach(function (tag,index) {
var index1 = getIndexOf(tags, tag);
console.log("index----",index, index1,tag)
replacedTag = tag;
$scope.tags = tag ? $filter('filter')($scope.allTags, tag.substr(1)) : [];
if ($scope.tags && $scope.tags.length && (e.keyCode && e.keCode != 32)) {
$scope.tags.forEach(function (tag1, index) {
$('ul').append('<li>' + '<a href="javascript:;" onclick=f("' + tag1 + '");>'
+ tag1 + '</a>' + '</li>')
})
}
else {
$('ul').html(' ');
}
if(index == index1) {
var b = a.substring(0, a.indexOf(tag) - 1) + ' <a>' + tag + '</a> ' + a.substr(a.indexOf(tag) + tag.length);
}
else {
var b = a.substring(0, a.lastIndexOf(tag) - 1) + ' <a>' + tag + '</a> ' + a.substr(a.lastIndexOf(tag) + tag.length);
}
a = b;
$('p').html(b)
})
}
})
});
HTML
<br>
<br>
<p></p>
<textarea rows="2" cols="80"></textarea>
<div>
<ul>
</ul>
</div>
For live demo Visit
https://plnkr.co/edit/SD9eouQa5yrViwxQD6yN?p=preview
i am also looking for the better answer.
I assume you're talking about gathering hash tags from a string of sorts, the snippet below demonstrates how you can build an array of #hashed tags without modifying the cursor position.
It uses a simple regular expression to match tags found in the textarea and then pushes them to an array.
var tags;
$('textarea').on('keyup', function(){
tags = $(this).val().match(/#\S+/g)
$('ul').html('');
tags.forEach(function(tag){
$('ul').append('<li>' + tag + '</li>')
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea></textarea>
<ul></ul>

how to make output text inside nested div with jquery

I have div inside div (nested div) and one button click and one textarea, when i click this button i want output that div in text,and add the text to Textarea
example
<div id="container">
<div class="nested">
<div id="1">
<div class="nested">
<div id="3">helpX</div>
<div id="4">helpY</div>
</div>
</div>
<div id="2">helpZ</div>
</div>
</div>
when i click my button i need the output like this =nested(=nested(helpX)(helpY))(helpZ)
my code is :
$('#BUTTONCLICK').click(function(){
$('#container').find("div").each( function(index) {
....
});
});
I hope you can help me. Thanks .
You have to set up some condition to check whether the child is a nested or child has nested children, or a simple div. So I use a recursive function to handle it:
$('#BUTTONCLICK').click(function(){
var findNest = function(ele) {
// To see if current item needs a nested prefix
var result = $(ele).hasClass("nested") ? '=nested(' : '';
$(ele).find(' > div').each(function(idx, item) {
var $item = $(item);
if ($item.hasClass("nested")) {
// If current cheked item is a nested item, nested it.
result += findNest($item);
} else if ($(item).find(".nested").length > 0) {
result += findNest(item);
} else {
// Current check item is a simple div, add it
result += '(' + $(item).text() + ')';
}
});
// Decide tail
var tail = $(ele).hasClass("nested") ? ')' : '';
return result + tail;
};
var $container = $('#container');
var result = findNest($container);
console.log(result);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div id="container">
<div class="nested">
<div id="1">
<div class="nested">
<div id="3">helpX</div>
<div id="4">helpY</div>
</div>
</div>
<div id="2">helpZ</div>
</div>
</div>
<div id="BUTTONCLICK">click</div>
If you want to give a level limit, the code can be changed to:
$('#BUTTONCLICK').click(function(){
// Inits
var LEVEL_LIMIT = 2;
var currentLevel = 0;
var findNest = function(ele) {
// Add one level at start.
++currentLevel;
// To see if current item needs a nested prefix
var result = $(ele).hasClass("nested") ? '=nested(' : '';
$(ele).find(' > div').each(function(idx, item) {
var $item = $(item);
var $nestChilds = $(item).find(".nested");
if (currentLevel <= LEVEL_LIMIT &&
($item.hasClass("nested") || $nestChilds.length > 0)) {
// If current cheked item is a nested item, or it has child that is nest, go into it.
result += findNest($item);
} else {
// Current check item is a simple div or level limit reached,
// simply add div texts...(May need other process of text now.)
result += '(' + $(item).text() + ')';
}
});
// Decrease Level by one before return.
--currentLevel;
// Decide tail
var tail = $(ele).hasClass("nested") ? ')' : '';
return result + tail;
};
var $container = $('#container');
var result = findNest($container);
console.log(result);
});
Try
$('#BUTTONCLICK').click(function(){
var text = '';
$('#container').find("div").each( function(index) {
text += $(this).text();
});
$("textarea").val(text);
});
$('#BUTTONCLICK').click(function(){
var findNest = function(ele) {
// To see if current item needs a nested prefix
var result = $(ele).hasClass("nested") ? '=nested(' : '';
$(ele).find(' > div').each(function(idx, item) {
var $item = $(item);
if ($item.hasClass("nested")) {
// If current cheked item is a nested item, nested it.
result += findNest($item);
} else if ($(item).find(".nested").length > 0) {
// For all .nested child from the item, do the findNest action
$(item).find(".nested").each(function(idx, item) {
result += findNest(item);
});
} else {
// Current check item is a simple div, add it
result += '(' + $(item).text() + ')';
}
});
// Decide tail
var tail = $(ele).hasClass("nested") ? ')' : '';
return result + tail;
};
var $container = $('#container');
var result = findNest($container);
console.log(result);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div id="container">
<div class="nested">
<div id="1">
<div class="nested">
<div id="3">helpX</div>
<div id="4">helpY</div>
</div>
</div>
<div id="2">helpZ</div>
</div>
</div>
<div id="BUTTONCLICK">click</div>

Categories