Since we cannot listen for events directly on the textNodes themselves, we have to take a more creative path to solving the problem. One thing we can do is look at the coordinates of the click event, and see if it overlaps with a textNode.
First, we'll need a small helper method to help us track whether a set of coordinates exists within a set of constraints. This will make it easier for us to arbitrarily determine if a set of x/y values are within the a set of dimensions:
function isInside ( x, y, rect ) {
return x >= rect.left && y >= rect.top
&& x <= rect.right && y <= rect.bottom;
}
This is fairly basic. The x
and y
values will be numbers, and the rect
reference will be an object with at least four properties holding the absolute pixel values representing four corners of a rectangle.
Next, we need a function for cycling through all childNodes that are textNodes, and determining whether a click event took place above one of them:
function textNodeFromPoint( element, x, y ) {
var node, nodes = element.childNodes, range = document.createRange();
for ( var i = 0; node = nodes[i], i < nodes.length; i++ ) {
if ( node.nodeType !== 3 ) continue;
range.selectNodeContents(node);
if ( isInside( x, y, range.getBoundingClientRect() ) ) {
return node;
}
}
return false;
}
With all of this in place, we can now quickly determine if a textNode was directly below the clicked region, and get the value of that node:
element.addEventListener( "click", function ( event ) {
if ( event.srcElement === this ) {
var clickedNode = textNodeFromPoint( this, event.clientX, event.clientY );
if ( clickedNode ) {
alert( "You clicked: " + clickedNode.nodeValue );
}
}
});
Note that the initial condition if ( event.srcElement ) === this
allows us to ignore click events originating from nested elements, such as an image or a span tag. Clicks that happen over textNodes will show the parent element as the srcElement
, and as such those are the only ones we're concerned with.
You can see the results here: http://jsfiddle.net/jonathansampson/ug3w2xLc/