9

I am trying to alert the correct css selector and xpath on right click on a dom element. I can show a menu on right click but I'm blocked getting the css selector and xpath value. Input for the code will be any website source code (right click on site, view source) or sample html code which has some classnames. I have a reference to pull unique css selector here

Any pointers on how to get unique css selector and xpath on right click on any dom element?

My Fiddle is here

<h2>Copy paste source code</h2>
<textarea id="txtSrcCode"></textarea>
<input type="button" value="Load Page" id="btnLoadPage" />
<div id="divToBindSrcCode">

</div>

<ul class='custom-menu'>
  <li data-action="first">First thing</li>
  <li data-action="second">Second thing</li>
  <li data-action="third">Third thing</li>
</ul>

Jquery code

$('#btnLoadPage').click(function() {
  $('#divToBindSrcCode').html($('#txtSrcCode').val()); // Laod dom on to the page
});

$(document).bind("contextmenu", function(event) {

  // Avoid the real one
  event.preventDefault();
  // Show contextmenu
  $(".custom-menu").finish().toggle(100).

  // In the right position (the mouse)
  css({
    top: event.pageY + "px",
    left: event.pageX + "px"
  });
});


// If the document is clicked somewhere
$(document).bind("mousedown", function(e) {
  // If the clicked element is not the menu
  if (!$(e.target).parents(".custom-menu").length > 0) {
    // Hide it
    $(".custom-menu").hide(100);
  }
});

// If the menu element is clicked
$(".custom-menu li").click(function() {
  var kk = $(this).val();
  // This is the triggered action name
  switch ($(this).attr("data-action")) {
    // A case for each action. Your actions here
    case "first":
      alert(kk);
      break;
    case "second":
      alert("second");
      break;
    case "third":
      alert("third");
      break;
  }

  // Hide it AFTER the action was triggered
  $(".custom-menu").hide(100);
});
2
  • 1
    Did you check out this answer? Commented Jun 1, 2017 at 11:37
  • click and right click works differently with $(this) and pulling its parent elements for xpath or css selector. Commented Jun 3, 2017 at 21:48

2 Answers 2

4
+50

Putting the answer of @jeka5555 together with a library such as css-selector-generator.js, and using MDN's xpath generator you can do this:

<html>
    <head>
        <script src="./css-selector-generator.js"></script>
        <script>
            function getXPathForElement(el, xml) {
                var xpath = '';
                var pos, tempitem2;

                while(el !== xml.documentElement) {
                    pos = 0;
                    tempitem2 = el;
                    while(tempitem2) {
                        if (tempitem2.nodeType === 1 && tempitem2.nodeName === el.nodeName) { // If it is ELEMENT_NODE of the same name
                            pos += 1;
                        }
                        tempitem2 = tempitem2.previousSibling;
                    }

                    xpath = "*[name()='"+el.nodeName+"' and namespace-uri()='"+(el.namespaceURI===null?'':el.namespaceURI)+"']["+pos+']'+'/'+xpath;

                    el = el.parentNode;
                }
                xpath = '/*'+"[name()='"+xml.documentElement.nodeName+"' and namespace-uri()='"+(el.namespaceURI===null?'':el.namespaceURI)+"']"+'/'+xpath;
                xpath = xpath.replace(/\/$/, '');
                return xpath;
            }
        </script>
        <script>
            function context(event) {
                event.preventDefault();
                console.log(event.target);
                var sel_gen = new CssSelectorGenerator();
                var sel = sel_gen.getSelector(event.target);
                var xpath = getXPathForElement(event.target, document);
                alert("sel: " + sel + "; xpath: " + xpath);
            }
        </script>
    </head>

    <body>
        <div class=myclass>
            <div>
                <p oncontextmenu="context(event)">Right click me</p>
                <p>Clicking me won't help</p>
            </div>
        </div>
    </body>
</html>

This particular case alerts:

sel: .myclass > div > :nth-child(1); xpath: /*[name()='HTML' and namespace-uri()='http://www.w3.org/1999/xhtml']/*[name()='BODY' and namespace-uri()='http://www.w3.org/1999/xhtml'][1]/*[name()='DIV' and namespace-uri()='http://www.w3.org/1999/xhtml'][1]/*[name()='DIV' and namespace-uri()='http://www.w3.org/1999/xhtml'][1]/*[name()='P' and namespace-uri()='http://www.w3.org/1999/xhtml'][1]

I would trust the library to get it right much more than I would trust myself!

And try this jsfiddle.

Also this jsfiddle modifies the Mozilla function to give a simpler xpath.

There are other libraries available for the css selector, see this answer to a similar question.

Sign up to request clarification or add additional context in comments.

8 Comments

Is this library free to use? In git hub it say unlicensed.
It is licensed with the UNLICENSE license, which says "This is free and unencumbered software released into the public domain.", so yes it's free to use.
No, because obviously an xpath wouldn't include for example the id or class of an element. But generally with programming HTML / javascript / CSS you only really care about selectors, and xpaths aren't very useful. Do you really need an xpath for something, or just a CSS selector?
Updated my answer with the xpath, and also the jsfiddle.
It's an equally valid xpath, just completely unambiguous and with the namespace information. It's easy to modify the function to give a simpler path if you want, see jsfiddle.net/daphtdazz/8jgyxrbt
|
3

event.target - indicates the element by which you clicked

3 Comments

good pointer to get current html element. Any option to get unique css selector please?
I would dynamically add to it a unique ID, for example: var unique = 'id' + (new Date ()). GetTime (); $(event.target).attr('id', unique);
I mean if there are 4 classes wit same names, I want to get the correct css selector for clicked element. any pointer to get css selector for the clicked element?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.