I am building a JS script which at some point is able to, on a given page, allow the user to click on any word and store this word in a variable.
I have one solution which is pretty ugly and involves class-parsing using jQuery:
I first parse the entire html, split everything on each space " "
, and re-append everything wrapped in a <span class="word">word</span>
, and then I add an event with jQ to detect clicks on such a class, and using $(this).innerHTML I get the clicked word.
This is slow and ugly in so many ways and I was hoping that someone knows of another way to achieve this.
PS: I might consider running it as a browser extension, so if it doesn't sound possible with mere JS, and if you know a browser API that would allow that, feel free to mention it !
A possible owrkaround would be to get the user to highlight the word instead of clicking it, but I would really love to be able to achieve the same thing with only a click !
Here is a completely different method. I am not sure about the practicality of it, but it may give you some different ideas. Here is what I am thinking if you have a container tag with position relative with just text in it. Then you could put a span around each word record its offset Height, Width, Left, and Top, then remove the span. Save those to an array then when there is a click in the area do a search to find out what word was closest to the click. This obviously would be intensive at the beginning. So this would work best in a situation where the person will be spending some time perusing the article. The benefit is you do not need to worry about possibly 100s of extra elements, but that benefit may be marginal at best.
Note I think you could remove the container element from the DOM to speed up the process and still get the offset distances, but I am not positive.
And another take on @stevendaniel's answer:
Here are improvements for the accepted answer:
As far as I know, adding a
span
for each word is the only way to do this.You might consider using Lettering.js, which handles the splitting for you. Though this won't really impact performance, unless your "splitting code" is inefficient.
Then, instead of binding
.click()
to everyspan
, it would be more efficient to bind a single.click()
to the container of thespan
s, and checkevent.target
to see whichspan
has been clicked.This is a followup on my comment to stevendaniels' answer (above):
Here is my code to make the range expansion code in that answer work reliably:
Here's a solution that will work without adding tons of spans to the document (works on Webkit and Mozilla and IE9+):
http://jsfiddle.net/Vap7C/15/
in IE8, it has problems because of getSelection. This link ( Is there a cross-browser solution for getSelection()? ) may help with those issues. I haven't tested on Opera.
I used http://jsfiddle.net/Vap7C/1/ from a similar question as a starting point. It used the Selection.modify function:
Unfortunately they don't always get the whole word. As a workaround, I got the Range for the selection and added two loops to find the word boundaries. The first one keeps adding characters to the word until it reaches a space. the second loop goes to the end of the word until it reaches a space.
This will also grab any punctuation at the end of the word, so make sure you trim that out if you need to.