faqts : Computers : Programming : Languages : JavaScript : Event handling

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

38 of 44 people (86%) answered Yes
Recently 7 of 10 people (70%) answered Yes

Entry

How can I find the word in the text on the page related to an event (e.g. word clicked on or hovered)?
How can I find the word in the text on the page related to an event (e.g. word clicked on or hovered)?

Feb 4th, 2005 02:03
Martin Honnen, http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/objects/obj_textrange.asp http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/methods/movetopoint.asp http://msdn.microsoft.com/library/defau


With IE 5 and later (at least on Windows) you can create a text range on
the body of the document, move the range to the coordinates you get from
the event and then the range even has a method to expand it to the
nearest word.
With Mozilla browsers (Mozilla Suite, Firefox, Netscape 6/7 for
instance) the event object has two properties, rangeParent (a DOM node),
and rangeOffset (a number), which allow you to create a W3C DOM Level 2
range and position it where the event occured. You have to write your
own code then to expand that range to the nearest word, it is a complex
task as a W3C range operates on the DOM tree and not on text but it is
possible.
The HTML document below has the code for IE/Win and Mozilla, but the
task to expand the range in Mozilla to a word is only solved in there
for the simple examples in the document.
Tested to work with IE 6, Netscape 7.2, and Firefox 1.0. It hopefully
works with earlier IE and Mozilla versions too but I haven't tested.
For other browsers not implementing the used objects/properties/methods
the function getWordFromEvent returns null.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
          "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Finding a word related to an event</title>
<script type="text/javascript">
function getWordFromEvent (evt) {
  if (document.body && document.body.createTextRange) {
    var range = document.body.createTextRange();
    range.moveToPoint(evt.clientX, evt.clientY);
    range.expand('word');
    return range.text;
  }
  else if (evt.rangeParent && document.createRange) {
    var range = document.createRange();
    range.setStart(evt.rangeParent, evt.rangeOffset);
    range.setEnd(evt.rangeParent, evt.rangeOffset);
    expandRangeToWord(range);
    var word = range.toString();
    range.detach();
    return word;    
  }
  else {
    return null;
  }
}
/* The implementation below of expandRangeToWord is not meant to be a
complete
   implementation of the functionality to expand a range to a word, with
W3C DOM
   ranges allowing different types of start/endContainer and the offset
being
   a text offset or a node offset depending on the container node type
it would
   take more than the few lines below to have a complete implementation.
   So this function is here to demonstrate within this test case that
finding a
   word from an event is possible but if you want to use it in complex
cases you
   need a better implementation of expandRangeToWord as the one below
can throw
   errors.
   Also the current implementation considers any \S+ between \s and \s a
'word',
   your aim when finding a work might differ.
*/
function expandRangeToWord (range) {
  var startOfWord = /^\s\S+$/;
  var endOfWord = /^\S+\s$/;
  var whitespace = /^\s+$/;
  // if offset is inside whitespace
  range.setStart(range.startContainer, range.startOffset - 1);
  while (whitespace.test(range.toString())) {
    range.setEnd(range.endContainer, range.endOffset + 1);
    range.setStart(range.startContainer, range.startOffset + 1);
  }
  while (!startOfWord.test(range.toString())) {
    range.setStart(range.startContainer, range.startOffset - 1);
  }
  range.setStart(range.startContainer, range.startOffset + 1);
  while (!endOfWord.test(range.toString())) {
    range.setEnd(range.endContainer, range.endOffset + 1);
  }
  range.setEnd(range.endContainer, range.endOffset - 1);
  return range.toString();
}
</script>
<script type="text/javascript">
function displayWord (text, inputId) {
  var input;
  if (text != null && document.getElementById && (input =
document.getElementById(inputId))) {
    input.value = text;
  }
}
function isMouseLeave (node, evt) {
  if (node.contains && evt.toElement) {
    return !node.contains(evt.toElement);
  }
  else if (evt.relatedTarget) {
    return !contains(node, evt.relatedTarget);
  }
}
function contains (container, containee) {
  do {
    if (container == containee) {
      return true;
    }
    containee = containee.parentNode;
  }
  while (containee)
  return false;
}
</script>
</head>
<body>
<h1>Finding a word related to an event</h1>
<p onmousemove="displayWord(getWordFromEvent(event), 'wordOutput');"
   onmouseout="if (isMouseLeave(this, event)) {
                 displayWord('', 'wordOutput');
               }">
This is a test paragraph with an onmousemove event handler supposed to
display
the word the mouse is over in the text input below.
Kibology for all. All for Kibology.
</p>
<fieldset>
<legend>word under mouse in above paragraph</legend>
<label>
word: 
<input type="text" id="wordOutput" value="" size="20" readonly>
</label>
</fieldset>
<hr>
<p onclick="var word = getWordFromEvent(event);
            if (word != null) {
              alert('Clicked word: ' + word);
            }">
This is a test paragraph which you can click and then the word you
clicked on
should be displayed.
Kibology for all. All for Kibology.
</p>
</body>
</html>