Namey
Namey

Reputation: 1212

Get HTML Node (Not Necessarily Element) On Click

I have a web application that, after clicking any node in the HTML, needs to retrieve the index of that node in its parent's childNodes array. However, I am having trouble getting the currently selected node through an onclick event. The returned target of the event is the containing element rather than the specific node inside the element. This difference is important when text nodes exist, such as:

<div>This is Node 1<span>node 2</span>, node 3, and <span>node 4</span></div>

If you click on the spans for Node 2 or Node 4, it's straightforward to know where you are. However, if you click on the text for Node 1 and Node 3, I can't seem to find where the event would help you figure out which part of the actual content was clicked on.

This happens to be important because a later operation needs to check for certain properties either forward or backward through the document until the first match. So, if both Node 2 and Node 4 are a match for the search, I need to know if I am in Node 1 or Node 3 in order to know which one to return. For example, if searching rightwards, starting in Node 1 means that Node 2 should be returned, and starting in Node 3 means that Node 4 should be returned. Obviously, this is a simplification, but it demonstrates the issue. Does anyone know the canonical solution for this? If I can get the node object or the index, that should be sufficient. jquery is fine, but not necessary.

Upvotes: 3

Views: 1761

Answers (5)

Ferret
Ferret

Reputation: 1440

Maybe somthing like this demo could help you out a bit:

document.getElementsByTagName('div')[0].addEventListener('click', function () {
    var fullStr = this.innerHTML.replace(/<[^>]*>/g, ''),
        sel = window.getSelection(),
        str = sel.anchorNode.data,
        clickPos = sel.focusOffset,
        wordPosLeft = str.slice(0, clickPos + 1).search(/\S+$/),
        wordPosRight = str.slice(clickPos).search(/\s/),
        wordClicked,
        nextWordRegex,
        nextWordPosLeft,
        nextWord;

    if(wordPosRight < 0) {
        wordClicked = str.slice(wordPosLeft);
    } else {
        wordClicked = str.slice(wordPosLeft, wordPosRight + clickPos);
    }
    nextWordRegex = new RegExp(wordClicked);
    nextWordPosLeft = fullStr.search(nextWordRegex) + wordClicked.length;
    nextWord = fullStr.slice(nextWordPosLeft).match(/^\s*(\S*)\s*.*$/)[1];    

    console.log('wordClicked: ' + wordClicked);
    console.log('nextWord: ' + nextWord);
});

See this fiddle.

Upvotes: 1

Makaze
Makaze

Reputation: 1086

It is not possible to do this as far as I know. You cannot:

  1. Detect events on text nodes.
  2. Detect the position of the text node relative to window or page.

This answer gives an idea with some good insight, but does not do what you want (return the index of the node).

I believe you are out of luck, unless you can find a way to use the solution above to determine index.

Upvotes: 0

Joel Cox
Joel Cox

Reputation: 3469

If you're just trying to work out the text of the element you clicked, minus child nodes text, I have a solution:

$('body').on('click', function(e) {
    alert('Node Text: '+$(e.target).clone().children().remove().end().text());
});

http://jsfiddle.net/xoegujqu/1/

Essentially, delegate the click event to the highest-level element you want this to run for (in this example it just used body, but you'll probably want to be more specific). use $(e.target) to get the element that was actually clicked, .clone() to clone it so you can modify it without affecting the actual page content, .children().remove() to remove all it's descendant elements, .end() to go back to the previous jQuery selector object, then finally .text() to get the remaining text content.

Upvotes: 0

Jazi
Jazi

Reputation: 6732

You need to get Your nodes in some containers. If You would click on "Node 1" text, function will return You a <div> element. But, if You would change Your code on this:

<div>
    <span>This is Node 1</span>
    <span>node 2</span>
    <span>, node 3, and </span>
    <span>node 4</span>
</div>

it would work and return <span> container. Not possible in other way, I think.

You can eventually make some JavaScript split() or regex operations.

Upvotes: 0

Related Questions