What I need to do
I display an iframe with javascript in the body of an HTML page.
With something like that document.write('<iframe ...></iframe'>);
In this iframe there is my javascript function witch search a keyword in the body of the parent document, and replace it with an html link <a href="#">keyword</a>
in the parent document.
What I've tried
- Javascript Bookmarklet to replace text with a link : complex script, but I need the skipTags
- and Javascript .replace command replace page text? : very short and nice script, but there is not the skipTags function...
Those worked like a charm when the script is in the document but not in an iframe to work with the parent document.
My problems/questions
- The problem is that the 'keyword' is replaced with a
'non-interpreted' html as text. (Browser displays
<a
href="#">keyword</a>
).
- My second question is how to do the replace just once, and not for
all the matching expressions ?
Usualy I use some jQuery but in this project I need to use only some javascript without any library.
Any idea to help me ? (I don't want anyone to "write my code", I just want some advices to make it by myself)
P.S. 1 : I use Chrome, but I would like to make it work in every browser.
P.S. 2 : English is not my first language, so if you don't understand something, don't hesitate to ask it to me, I'll try to explain it better.
Edit 2
First script now works for the HTML, so question 1 is solved, but how to do the replace only once, even if the keyword is repeated several times ? (question 2)
With the help of xiaoyi, I've found some solutions :
- Stop the loop and replace only the first match
- Globalize the functions to search/replace multiple keywords
I think that it could be optimized, but for me it works like a charm, and I share it with you, if it can help anyone (don't forget to change the target of the document, here "parent") :
(function(){
// don't replace text within these tags
var skipTags = { 'a': 1, 'style': 1, 'script': 1, 'iframe': 1, 'meta':1, 'title':1, 'img':1, 'h':1 };
// find text nodes to apply replFn to
function findKW( el, term, replFn )
{
var child, tag,found=false;
for (var i = 0;i<=el.childNodes.length - 1 && !found; i++)
{
child = el.childNodes[i];
if (child.nodeType == 1)
{ // ELEMENT_NODE
tag = child.nodeName.toLowerCase();
if (!(tag in skipTags))
{
findKW(child, term, replFn);
}
}
else if (child.nodeType == 3)
{ // TEXT_NODE
found=replaceKW(child, term, replFn); // if found=true, we stop the loop
}
}
};
// replace terms in text according to replFn
function replaceKW( text, term, replFn)
{
var match,
matches = [],found=false;
while (match = term.exec(text.data))
{
matches.push(match);
}
for (var i = 0;i<=matches.length - 1 && !found; i++)
{
match = matches[i];
// cut out the text node to replace
text.splitText(match.index);
text.nextSibling.splitText(match[1].length);
text.parentNode.replaceChild(replFn(match[1]), text.nextSibling);
if(matches[i])found=true;// To stop the loop
}
return found;
};
// First search/replace
var replTerm = 'keyword';
findKW(
parent.document.body,
new RegExp('\\b(' + replTerm + ')\\b', 'gi'),
function (match)
{
var link = parent.document.createElement('a');
link.href = 'http://www.okisurf.com/#q=' + replTerm;
link.target = '_blank';
link.innerHTML = match;
return link;
}
);
// A second search/replace
var replTerm = 'word';
findKW(
parent.document.body,
new RegExp('\\b(' + replTerm + ')\\b', 'gi'),
function (match)
{
var link = parent.document.createElement('a');
link.href = 'http://www.okisurf.com/#q=' + replTerm;
link.target = '_blank';
link.innerHTML = match;
return link;
}
);
// Other search/replace
// ...
}());
I've also discovered that the second solution doesn't works with Internet Explorer witch doesn't accept the createTreeWalker()
DOM function