Related
I wish to replace any character not in the passport format(A9999999) from my input text. I have written the following (jsfiddle here):
HTML
Doc Type <input id='docType' value = 'PASS'/> <br>
Doc ID <input id='docId'/>
JS:
$(document).ready(function () {
var docTypeVal = $("#docType").val();
$('#docId').keyup(function() {
if(docTypeVal == "PASS") {
var $th = $(this);
$th.attr("maxlength","8");
if($th.val().length <= 1) {
$th.val().replace(/[^a-zA-Z]/g, function(str) {
alert('You typed " ' + str + ' ".\n\nPlease use correct format.');
return '';
})
}
else if($th.val().length <= 8 && $th.val().length > 1) {
$th.val().replace(/^(?!.*^([a-zA-Z]){1}([0-9]){7}$)/, function(str) {
alert('You typed " ' + str + ' ".\n\nPlease use correct format.');
return '';
})
}
}
});
});
However, firstly, this doesn't replace any characters (wrong/right). Secondly, it gives the alert the moment I enter 2nd character onwards. It should accept the 1st char if it is alphabet (replace otherwise), from 2nd till 8th char it should accept only numbers (replace otherwise).
You can test this with 1 Regular Expression.
/^[a-z]?\d{0,7}$/i
This pattern will look A9 up to A9999999. It will fail on AA or 99.
Example: https://jsfiddle.net/Twisty/awL0onjg/20/
JavaScript
$(function() {
var docTypeVal = $("#docType").val();
$('#docId').keyup(function(e) {
var exc = [
11, // Tab
127, // Del
];
if (exc.indexOf(e.which) > -1) {
return true;
}
var term = $(this).val();
var re = /^[a-z]?\d{0,7}$/i;
console.log("Testing:", term, re.test(term));
if (re.test(term)) {
$(this).removeClass("invalid");
return true;
} else {
$(this).addClass("invalid");
}
});
});
Consider using .keydown() if you want to prevent the User from typing outside of that pattern. See More.
Fiddle Demo
Referred the JS of Twisty's and realized it should be as shown below:
if(docTypeVal == "PASS") {
$(this).attr("maxlength","8");
var term = $(this).val();
var re = /^[a-zA-Z]{1}\d{0,7}$/i;
if (re.test(term)) {
$(this).removeClass("invalid");
return true;
} else {
$(this).addClass("invalid");
$(this).val(term.replace(term.charAt(term.length-1),
function(str) {
alert('You typed " ' + str + ' ".\n\nPlease use correct format.');
return '';
}));
return false;
}
}
I am trying to have sql's like clause like effect in javascript.
I am aware that similar question are already present on internet but the following approach is not working for me:
$(document).ready(function() {
var listAll = [
"X1",
"ANTENNA SYSTEMS 00000000AS",
"Security & Wrokf 00000000CS",
"MICROWAVE & COMM 00000000MC",
"MICROWAVE SENSOR 00000000MT",
"PLANNING & PROJE 00000000PG",
"MECHANICAL SYSTE 00000000MS",
"ELECTRO-OPTICAL 00000000EO",
"SATCOM EXPERIMEN 00000000SE",
"QUALITY ASSURANC 00000000QA",
"QUALITY ASSURANC 00000000QC",
"DATA PRODUCTS SO 00000000DP"
];
var lstfiltered = ["X2"];
for (i = 0; i <= listAll.length - 1; i++) {
console.log(listAll[i]);
var string = listAll[i];
var substring = "lan";
if (string.indexOf(substring) !== -1) {
lstfiltered.push(string);
}
}
console.log(lstfiltered);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
I have set substring which is to be looked up in string as "lan", which should push "PLANNING & PROJE 00000000PG" into the array. But it does not.
I think that the problem is with the letter casing. Try this :
$(document).ready(function() {
var listAll = ["X1", "ANTENNA SYSTEMS 00000000AS", "Security & Wrokf 00000000CS", "MICROWAVE & COMM 00000000MC", "MICROWAVE SENSOR 00000000MT", "PLANNING & PROJE 00000000PG", "MECHANICAL SYSTE 00000000MS", "ELECTRO-OPTICAL 00000000EO", "SATCOM EXPERIMEN 00000000SE", "QUALITY ASSURANC 00000000QA", "QUALITY ASSURANC 00000000QC", "DATA PRODUCTS SO 00000000DP"];
var lstfiltered = ["X2"];
for (i = 0; i <= listAll.length - 1; i++) {
console.log(listAll[i]);
var string = listAll[i];
var substring = "lan";
if (string.toLowerCase().indexOf(substring) !== -1) {
lstfiltered.push(string);
}
}
console.log(lstfiltered);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
I suggest to search for lower case letters and move the search string outside of the loop.
$(document).ready(function() {
var listAll = ["X1", "ANTENNA SYSTEMS 00000000AS", "Security & Wrokf 00000000CS", "MICROWAVE & COMM 00000000MC", "MICROWAVE SENSOR 00000000MT", "PLANNING & PROJE 00000000PG", "MECHANICAL SYSTE 00000000MS", "ELECTRO-OPTICAL 00000000EO", "SATCOM EXPERIMEN 00000000SE", "QUALITY ASSURANC 00000000QA", "QUALITY ASSURANC 00000000QC", "DATA PRODUCTS SO 00000000DP"];
var lstfiltered = ["X2"];
var substring = "lan";
for (i = 0; i <= listAll.length - 1; i++) {
console.log(listAll[i]);
var string = listAll[i];
if (string.toLowerCase().indexOf(substring) !== -1) {
lstfiltered.push(string);
}
}
console.log(lstfiltered);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
For a more concise version, you could use Array#filter
$(document).ready(function() {
var listAll = ["X1", "ANTENNA SYSTEMS 00000000AS", "Security & Wrokf 00000000CS", "MICROWAVE & COMM 00000000MC", "MICROWAVE SENSOR 00000000MT", "PLANNING & PROJE 00000000PG", "MECHANICAL SYSTE 00000000MS", "ELECTRO-OPTICAL 00000000EO", "SATCOM EXPERIMEN 00000000SE", "QUALITY ASSURANC 00000000QA", "QUALITY ASSURANC 00000000QC", "DATA PRODUCTS SO 00000000DP"];
var substring = "lan";
var lstfiltered = listAll.filter(function (a) {
return a.toLowerCase().indexOf(substring) !== -1;
});
lstfiltered.unshift('X2')
console.log(lstfiltered);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
If you want to push original string then compare with string converted by using toLowerCase() and push the original string as shown below :
$(document).ready(function() {
var listAll = ["X1", "ANTENNA SYSTEMS 00000000AS", "Security & Wrokf 00000000CS", "MICROWAVE & COMM 00000000MC", "MICROWAVE SENSOR 00000000MT", "PLANNING & PROJE 00000000PG", "MECHANICAL SYSTE 00000000MS", "ELECTRO-OPTICAL 00000000EO", "SATCOM EXPERIMEN 00000000SE", "QUALITY ASSURANC 00000000QA", "QUALITY ASSURANC 00000000QC", "DATA PRODUCTS SO 00000000DP"];
var lstfiltered = ["X2"];
for (i = 0; i <= listAll.length - 1; i++) {
console.log(listAll[i]);
var string = listAll[i].toLowerCase();
var substring = "lan";
if (string.indexOf(substring) !== -1) // compare with string converted by toLowerCase()
{
lstfiltered.push(listAll[i]); // Push original string.
}
}
console.log(lstfiltered);
});
I am currently working with ng-bind-html. Basically, what I am trying to do is, when I post a blog, the blog contains links and other styling. So when I am trying to show the list of blogs, I am using ng-bing-html like this:
<p ng-bind-html="blog.blogContent"></p>
which works fine.
But in addition, I try to truncate the blog and show only few paragraphs with view more option by passing a custom filter. But when I pass the filter I get the following:
<p ng-bind-html="blog.blogContent | Truncate"></p>
Error: [$sanitize:badparse] The sanitizer was unable to parse the
following block of html: <a href="https:.......
My Filter looks like this:
return function (text, length, end) {
if (text !== undefined) {
if (isNaN(length)) {
length = 450;
}
if (end === undefined) {
end = ".......";
}
if (text.length <= length || text.length - end.length <= length) {
return text;
} else {
return String(text).substring(0, length - end.length) + end;
}
}
You can solve this using custom directives and filters. try this one: https://stackoverflow.com/a/45076560/6816707
I used the solution posted by Minouris in this post (Javascript truncate HTML text) and adapted it into an AngularJS filter. It seems to work pretty well. The filter is
angular.module('plunker').filter('Truncate', function() {
return function(text, length, end) {
if (text !== undefined) {
if (isNaN(length)) {
length = 20;
}
if (end === undefined) {
end = ".......";
}
if (text.length <= length || text.length - end.length <= length) {
return text;
}
var truncated = text.substring(0, length);
// Remove line breaks and surrounding whitespace
truncated = truncated.replace(/(\r\n|\n|\r)/gm,"").trim();
// If the text ends with an incomplete start tag, trim it off
truncated = truncated.replace(/<(\w*)(?:(?:\s\w+(?:={0,1}(["']{0,1})\w*\2{0,1})))*$/g, '');
// If the text ends with a truncated end tag, fix it.
var truncatedEndTagExpr = /<\/((?:\w*))$/g;
var truncatedEndTagMatch = truncatedEndTagExpr.exec(truncated);
if (truncatedEndTagMatch != null) {
var truncatedEndTag = truncatedEndTagMatch[1];
// Check to see if there's an identifiable tag in the end tag
if (truncatedEndTag.length > 0) {
// If so, find the start tag, and close it
var startTagExpr = new RegExp(
"<(" + truncatedEndTag + "\\w?)(?:(?:\\s\\w+(?:=([\"\'])\\w*\\2)))*>");
var testString = truncated;
var startTagMatch = startTagExpr.exec(testString);
var startTag = null;
while (startTagMatch != null) {
startTag = startTagMatch[1];
testString = testString.replace(startTagExpr, '');
startTagMatch = startTagExpr.exec(testString);
}
if (startTag != null) {
truncated = truncated.replace(truncatedEndTagExpr, '</' + startTag + '>');
}
} else {
// Otherwise, cull off the broken end tag
truncated = truncated.replace(truncatedEndTagExpr, '');
}
}
// Now the tricky part. Reverse the text, and look for opening tags. For each opening tag,
// check to see that he closing tag before it is for that tag. If not, append a closing tag.
var testString = reverseHtml(truncated);
var reverseTagOpenExpr = /<(?:(["'])\w*\1=\w+ )*(\w*)>/;
var tagMatch = reverseTagOpenExpr.exec(testString);
while (tagMatch != null) {
var tag = tagMatch[0];
var tagName = tagMatch[2];
var startPos = tagMatch.index;
var endPos = startPos + tag.length;
var fragment = testString.substring(0, endPos);
// Test to see if an end tag is found in the fragment. If not, append one to the end
// of the truncated HTML, thus closing the last unclosed tag
if (!new RegExp("<" + tagName + "\/>").test(fragment)) {
truncated += '</' + reverseHtml(tagName) + '>';
}
// Get rid of the already tested fragment
testString = testString.replace(fragment, '');
// Get another tag to test
tagMatch = reverseTagOpenExpr.exec(testString);
}
return truncated;
}
}
function reverseHtml(str) {
var ph = String.fromCharCode(206);
var result = str.split('').reverse().join('');
while (result.indexOf('<') > -1) {
result = result.replace('<',ph);
}
while (result.indexOf('>') > -1) {
result = result.replace('>', '<');
}
while (result.indexOf(ph) > -1) {
result = result.replace(ph, '>');
}
return result;
}
});
Working plunkr:
http://plnkr.co/edit/oCwmGyBXB26omocT2q9m?p=preview
I havent tested the above solution and you may run into issues with more complicated HTML strings. May I suggest using a Jquery library like https://github.com/pathable/truncate to be safe?
I seem to be doing something wrong here. This script works with the prompts, which have been commented out, but not with the textboxes. Am I somehow failing to send the input values to the function?
I'm also having trouble using regular expressions in the if-statements, rather than a clumsy list of punctuation marks.
<html>
<head>
</head>
<body>
<div id="myTypingText"></div>
<label>Say what you want typed</label>
<input class="textBox" id="userInput" />
<label>A pregnant pause... (300?)</label>
<input type="number" id="userBreath" />
<button onclick="printLooper()" href="javascript:;">Submit</button>
<! --input name="buttonExecute" onclick="execute(document.getElementById('textbox1').value)" type="button" value="Execute" --/>
<script type="text/javascript" language="javascript">
var myString = document.getElementById('userInput').value;
//var myString = prompt('Say what you want to see typed','Right here, baby'); //prompts are annoying, i know
//var myDelay = prompt('Type speed (try 50)', 'The higher the number, the slower it types');
//var myBreath = prompt('Now tell me how long to pause at each breath (shift+2)', 'Try 300')
var myBreath = document.getElementById('userBreath').value;
var myArray = myString.split("");
var loopTimer;
function printLooper(){
if(myArray.length > 0 ){
var char = myArray.shift();
if ( char === '#'){
document.getElementById("myTypingText").innerHTML
}else {
document.getElementById("myTypingText").innerHTML += char;
}
} else {
clearTimeout(loopTimer);
}
if (char === ' '){
loopTimer = setTimeout('printLooper()', 20);
} else if (char === ',' || char === '.' || char === '?') {
loopTimer = setTimeout('printLooper()', 220); //fiddle with these 2nd params as you see fit
} else if (char === '#'){
loopTimer = setTimeout('printLooper()', myBreath);
} else {
loopTimer = setTimeout('printLooper()', 47);
}
}
printLooper();
</script>
</body>
</html>
Any help appreciated!
You need to have some variables inside your function.
I made a demo and removed the inline js on the button.
Use this if useful:
<button id="sub_btn">Submit</button>
var loopTimer;
var char, myString, myBreath, myArray;
function printLooper() {
if (myArray.length > 0) {
char = myArray.shift();
console.log(char);
if (char === '#') {
document.getElementById("myTypingText").innerHTML = '';
} else {
document.getElementById("myTypingText").innerHTML += char;
}
} else {
clearTimeout(loopTimer);
return false; // To the loop will stop when the array is empty
}
if (char === ' ') {
loopTimer = setTimeout(printLooper, 20);
} else if (char === ',' || char === '.' || char === '?') {
loopTimer = setTimeout(printLooper, 220); //fiddle with these 2nd params as you see fit
} else if (char === '#') {
loopTimer = setTimeout(printLooper, myBreath);
} else {
loopTimer = setTimeout(printLooper, 47);
}
}
document.getElementById('sub_btn').onclick = function () {
myString = document.getElementById('userInput').value;
myBreath = document.getElementById('userBreath').value;
myArray = myString.split("");
printLooper(myString, myBreath, myArray);
};
Demo here
This syntax has extra characters you probably typo'd in there. I also have never seen a button element with the href attribute before but I don't get out much. You might want to revisit this.
<button onclick="printLooper()" href="javascript:;">Submit</button>
You should put these lines inside the function
var myString = document.getElementById('userInput').value;
var myBreath = document.getElementById('userBreath').value;
var myArray = myString.split("");
It's empty because you put it outside the function and initially the inputs are empty and inside the function if(myArray.length > 0 ) is always false, you need to populate the array once the function is called after the button pressed and also href is not a valid attribute for button as another answer stated it.
var myString = document.getElementById('userInput').value;
//var myString = prompt('Say what you want to see typed','Right here, baby'); //prompts are annoying, i know
//var myDelay = prompt('Type speed (try 50)', 'The higher the number, the slower it types');
//var myBreath = prompt('Now tell me how long to pause at each breath (shift+2)', 'Try 300')
var myBreath = document.getElementById('userBreath').value;
var myArray = myString.split("");
Move these inside the function.
HTML
<body>
<div class="lol">
<a class="rightArrow" href="javascriptVoid:(0);" title"Next image">
</div>
</body>
Pseudo Code
$(".rightArrow").click(function() {
rightArrowParents = this.dom(); //.dom(); is the pseudo function ... it should show the whole
alert(rightArrowParents);
});
Alert message would be:
body div.lol a.rightArrow
How can I get this with javascript/jquery?
Here is a native JS version that returns a jQuery path. I'm also adding IDs for elements if they have them. This would give you the opportunity to do the shortest path if you see an id in the array.
var path = getDomPath(element);
console.log(path.join(' > '));
Outputs
body > section:eq(0) > div:eq(3) > section#content > section#firehose > div#firehoselist > article#firehose-46813651 > header > h2 > span#title-46813651
Here is the function.
function getDomPath(el) {
var stack = [];
while ( el.parentNode != null ) {
console.log(el.nodeName);
var sibCount = 0;
var sibIndex = 0;
for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {
var sib = el.parentNode.childNodes[i];
if ( sib.nodeName == el.nodeName ) {
if ( sib === el ) {
sibIndex = sibCount;
}
sibCount++;
}
}
if ( el.hasAttribute('id') && el.id != '' ) {
stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
} else if ( sibCount > 1 ) {
stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')');
} else {
stack.unshift(el.nodeName.toLowerCase());
}
el = el.parentNode;
}
return stack.slice(1); // removes the html element
}
Using jQuery, like this (followed by a solution that doesn't use jQuery except for the event; lots fewer function calls, if that's important):
$(".rightArrow").click(function () {
const rightArrowParents = [];
$(this)
.parents()
.addBack()
.not("html")
.each(function () {
let entry = this.tagName.toLowerCase();
const className = this.className.trim();
if (className) {
entry += "." + className.replace(/ +/g, ".");
}
rightArrowParents.push(entry);
});
console.log(rightArrowParents.join(" "));
return false;
});
Live example:
$(".rightArrow").click(function () {
const rightArrowParents = [];
$(this)
.parents()
.addBack()
.not("html")
.each(function () {
let entry = this.tagName.toLowerCase();
const className = this.className.trim();
if (className) {
entry += "." + className.replace(/ +/g, ".");
}
rightArrowParents.push(entry);
});
console.log(rightArrowParents.join(" "));
return false;
});
<div class=" lol multi ">
Click here
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
(In the live examples, I've updated the class attribute on the div to be lol multi to demonstrate handling multiple classes.)
That uses parents to get the ancestors of the element that was clicked, removes the html element from that via not (since you started at body), then loops through creating entries for each parent and pushing them on an array. Then we use addBack to add the a back into the set, which also changes the order of the set to what you wanted (parents is special, it gives you the parents in the reverse of the order you wanted, but then addBack puts it back in DOM order). Then it uses Array#join to create the space-delimited string.
When creating the entry, we trim className (since leading and trailing spaces are preserved, but meaningless, in the class attribute), and then if there's anything left we replace any series of one or more spaces with a . to support elements that have more than one class (<p class='foo bar'> has className = "foo bar", so that entry ends up being p.foo.bar).
Just for completeness, this is one of those places where jQuery may be overkill, you can readily do this just by walking up the DOM:
$(".rightArrow").click(function () {
const rightArrowParents = [];
for (let elm = this; elm; elm = elm.parentNode) {
let entry = elm.tagName.toLowerCase();
if (entry === "html") {
break;
}
const className = elm.className.trim();
if (className) {
entry += "." + className.replace(/ +/g, ".");
}
rightArrowParents.push(entry);
}
rightArrowParents.reverse();
console.log(rightArrowParents.join(" "));
return false;
});
Live example:
$(".rightArrow").click(function () {
const rightArrowParents = [];
for (let elm = this; elm; elm = elm.parentNode) {
let entry = elm.tagName.toLowerCase();
if (entry === "html") {
break;
}
const className = elm.className.trim();
if (className) {
entry += "." + className.replace(/ +/g, ".");
}
rightArrowParents.push(entry);
}
rightArrowParents.reverse();
console.log(rightArrowParents.join(" "));
return false;
});
<div class=" lol multi ">
Click here
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
There we just use the standard parentNode property (or we could use parentElement) of the element repeatedly to walk up the tree until either we run out of parents or we see the html element. Then we reverse our array (since it's backward to the output you wanted), and join it, and we're good to go.
I needed a native JS version, that returns CSS standard path (not jQuery), and deals with ShadowDOM. This code is a minor update on Michael Connor's answer, just in case someone else needs it:
function getDomPath(el) {
if (!el) {
return;
}
var stack = [];
var isShadow = false;
while (el.parentNode != null) {
// console.log(el.nodeName);
var sibCount = 0;
var sibIndex = 0;
// get sibling indexes
for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {
var sib = el.parentNode.childNodes[i];
if ( sib.nodeName == el.nodeName ) {
if ( sib === el ) {
sibIndex = sibCount;
}
sibCount++;
}
}
// if ( el.hasAttribute('id') && el.id != '' ) { no id shortcuts, ids are not unique in shadowDom
// stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
// } else
var nodeName = el.nodeName.toLowerCase();
if (isShadow) {
nodeName += "::shadow";
isShadow = false;
}
if ( sibCount > 1 ) {
stack.unshift(nodeName + ':nth-of-type(' + (sibIndex + 1) + ')');
} else {
stack.unshift(nodeName);
}
el = el.parentNode;
if (el.nodeType === 11) { // for shadow dom, we
isShadow = true;
el = el.host;
}
}
stack.splice(0,1); // removes the html element
return stack.join(' > ');
}
Here is a solution for exact matching of an element.
It is important to understand that the selector (it is not a real one) that the chrome tools show do not uniquely identify an element in the DOM. (for example it will not distinguish between a list of consecutive span elements. there is no positioning/indexing info)
An adaptation from a similar (about xpath) answer
$.fn.fullSelector = function () {
var path = this.parents().addBack();
var quickCss = path.get().map(function (item) {
var self = $(item),
id = item.id ? '#' + item.id : '',
clss = item.classList.length ? item.classList.toString().split(' ').map(function (c) {
return '.' + c;
}).join('') : '',
name = item.nodeName.toLowerCase(),
index = self.siblings(name).length ? ':nth-child(' + (self.index() + 1) + ')' : '';
if (name === 'html' || name === 'body') {
return name;
}
return name + index + id + clss;
}).join(' > ');
return quickCss;
};
And you can use it like this
console.log( $('some-selector').fullSelector() );
Demo at http://jsfiddle.net/gaby/zhnr198y/
The short vanilla ES6 version I ended up using:
Returns the output I'm used to read in Chrome inspector e.g body div.container input#name
function getDomPath(el) {
let nodeName = el.nodeName.toLowerCase();
if (el === document.body) return 'body';
if (el.id) nodeName += '#' + el.id;
else if (el.classList.length)
nodeName += '.' + [...el.classList].join('.');
return getDomPath(el.parentNode) + ' ' + nodeName;
};
I moved the snippet from T.J. Crowder to a tiny jQuery Plugin. I used the jQuery version of him even if he's right that this is totally unnecessary overhead, but i only use it for debugging purpose so i don't care.
Usage:
Html
<html>
<body>
<!-- Two spans, the first will be chosen -->
<div>
<span>Nested span</span>
</div>
<span>Simple span</span>
<!-- Pre element -->
<pre>Pre</pre>
</body>
</html>
Javascript
// result (array): ["body", "div.sampleClass"]
$('span').getDomPath(false)
// result (string): body > div.sampleClass
$('span').getDomPath()
// result (array): ["body", "div#test"]
$('pre').getDomPath(false)
// result (string): body > div#test
$('pre').getDomPath()
Repository
https://bitbucket.org/tehrengruber/jquery.dom.path
I've been using Michael Connor's answer and made a few improvements to it.
Using ES6 syntax
Using nth-of-type instead of nth-child, since nth-of-type looks for children of the same type, rather than any child
Removing the html node in a cleaner way
Ignoring the nodeName of elements with an id
Only showing the path until the closest id, if any. This should make the code a bit more resilient, but I left a comment on which line to remove if you don't want this behavior
Use CSS.escape to handle special characters in IDs and node names
~
export default function getDomPath(el) {
const stack = []
while (el.parentNode !== null) {
let sibCount = 0
let sibIndex = 0
for (let i = 0; i < el.parentNode.childNodes.length; i += 1) {
const sib = el.parentNode.childNodes[i]
if (sib.nodeName === el.nodeName) {
if (sib === el) {
sibIndex = sibCount
break
}
sibCount += 1
}
}
const nodeName = CSS.escape(el.nodeName.toLowerCase())
// Ignore `html` as a parent node
if (nodeName === 'html') break
if (el.hasAttribute('id') && el.id !== '') {
stack.unshift(`#${CSS.escape(el.id)}`)
// Remove this `break` if you want the entire path
break
} else if (sibIndex > 0) {
// :nth-of-type is 1-indexed
stack.unshift(`${nodeName}:nth-of-type(${sibIndex + 1})`)
} else {
stack.unshift(nodeName)
}
el = el.parentNode
}
return stack
}
All the examples from other ответов did not work very correctly for me, I made my own, maybe my version will be more suitable for the rest
const getDomPath = element => {
let templateElement = element
, stack = []
for (;;) {
if (!!templateElement) {
let attrs = ''
for (let i = 0; i < templateElement.attributes.length; i++) {
const name = templateElement.attributes[i].name
if (name === 'class' || name === 'id') {
attrs += `[${name}="${templateElement.getAttribute(name)}"]`
}
}
stack.push(templateElement.tagName.toLowerCase() + attrs)
templateElement = templateElement.parentElement
} else {
break
}
}
return stack.reverse().slice(1).join(' > ')
}
const currentElement = document.querySelectorAll('[class="serp-item__thumb justifier__thumb"]')[7]
const path = getDomPath(currentElement)
console.log(path)
console.log(document.querySelector(path))
console.log(currentElement)
var obj = $('#show-editor-button'),
path = '';
while (typeof obj.prop('tagName') != "undefined"){
if (obj.attr('class')){
path = '.'+obj.attr('class').replace(/\s/g , ".") + path;
}
if (obj.attr('id')){
path = '#'+obj.attr('id') + path;
}
path = ' ' +obj.prop('tagName').toLowerCase() + path;
obj = obj.parent();
}
console.log(path);
hello this function solve the bug related to current element not show in the path
check this now
$j(".wrapper").click(function(event) {
selectedElement=$j(event.target);
var rightArrowParents = [];
$j(event.target).parents().not('html,body').each(function() {
var entry = this.tagName.toLowerCase();
if (this.className) {
entry += "." + this.className.replace(/ /g, '.');
}else if(this.id){
entry += "#" + this.id;
}
entry=replaceAll(entry,'..','.');
rightArrowParents.push(entry);
});
rightArrowParents.reverse();
//if(event.target.nodeName.toLowerCase()=="a" || event.target.nodeName.toLowerCase()=="h1"){
var entry = event.target.nodeName.toLowerCase();
if (event.target.className) {
entry += "." + event.target.className.replace(/ /g, '.');
}else if(event.target.id){
entry += "#" + event.target.id;
}
rightArrowParents.push(entry);
// }
where $j = jQuery Variable
also solve the issue with .. in class name
here is replace function :
function escapeRegExp(str) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
function replaceAll(str, find, replace) {
return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}
Thanks
$(".rightArrow")
.parents()
.map(function () {
var value = this.tagName.toLowerCase();
if (this.className) {
value += '.' + this.className.replace(' ', '.', 'g');
}
return value;
})
.get().reverse().join(", ");