On May 13, 10:28 am, Gordon <[EMAIL PROTECTED]> wrote:
> I had previously written a javascript that scans a div inside a HTML
> document for keywords and then wraps those words in hyperlinks, as
> part of adynamic help system.  This worked by modifying the innerHTML
> of the div in question.  This approach worked but had a few problems,
> namely that you had to be careful you didn't accidentally try to wrap
> links around form elements, tag attributes and other such things, and
> that it didn't work in Safari.
>
> I did a recode recently that made use of the jQuery library. It cut
> the line count of the script in half but it still worked in
> fundamentally the same way as before, by doing regex search and
> replace on the .html() of the target div.

I think replacing innerHTML is kludgy.  Below is an example that uses
a DOM traversal and replaces matching words within text nodes with
wrapped words and text.  It's pretty straight forward, you need to
skip over some nodes (textareas, selects, etc.) that you don't want to
modify.  I uses a NodeList and adds nodes to it, so it goes backwards
over it.  Tested in Firefox and Safari, I'll leave IE to you.

I'm new to jQuery so it's not jQuery-ish at all, maybe someone else
can do that bit.

<script>

// Recursive traverse of DOM from node down
function highLight(node, txt){

  // Don't wrap content of textarea, select, option or button elements
  // Add any other elements that shouldn't be processed
  var tagName = node.tagName.toLowerCase();
  if ('textarea' == tagName ||
      'select' == tagName ||
      'option' == tagName ||
      'button' == tagName ) {
    return;
  }

  if (node.nodeType == 3) return wrap(node, txt);

  var kid, kids = node.childNodes;
  var i = kids.length;
  while(i--) {
    kid = kids[i];
    (kid.nodeType == 1)? highLight(kid, txt) : wrap(kid, txt);
  }

  // Remove unnecessary text nodes
  if (node.normalize) node.normalize();
}


function wrap(txtNode, txt) {

  var re = new RegExp('\\b' + txt + '\\b');
  var s = txtNode.data.split(re);

  if (s.length < 2) return;

  var p = txtNode.parentNode;
  var lastEl, tempEl;

  // Element to wrap text in, could use em, strong, a, etc.
  var wrapEl = document.createElement('span');
  wrapEl.style.color = 'red';

  lastEl = document.createTextNode(s[0]);
  p.replaceChild(lastEl, txtNode);

  for (var i=1, len=s.length; i<len; i++) {
    tempEl = wrapEl.cloneNode(true);
    tempEl.appendChild(document.createTextNode(txt));
    p.insertBefore(tempEl, lastEl.nextSibling);
    p.insertBefore(document.createTextNode(s[i]), tempEl.nextSibling);
    lastEl = tempEl.nextSibling;
  }
}

</script>
</head>
<body>

<div id="xx">Here is some blah text so that I can blah test
<p>my new blah</p>blah function to see if it blah blah works and joins
blahdy blah
<textarea>Here is blah text</textarea>
<select><option>blah<option>blah</select>
<div>blah</div>
<div>And blah. awsome. blah is blah.</div>
<table><tr><td>blah<td>some blah text<td>blah text blah</table>
</div>
<button onclick="
  highLight(document.getElementById('xx'), 'blah');
">Hightlight blah</button>

</body>


--
Rob

Reply via email to