Reputation: 71
So I have a piece of HTML that looks something like this...
<p>This is some copy. In this copy is the word hello</p>
I want to turn the word hello into a link using jquery.
<p>This is some copy. In this copy is the word <a href="">hello</a></p>
That in itself is not too hard. My problem is that if the word is already apart of a link like the example below...
<p>In this copy is the <a href="">word hello</a></p>
I don't want that to end up with a link within a link...
<p>In this copy is the <a href="">word <a href="">hello</a></a></p>
Any help would be much appreciated.
Upvotes: 7
Views: 3779
Reputation: 31
A little regex should do the trick (Update, see below):
$(document).ready(function(){
var needle = 'hello';
$('p').each(function(){
var me = $(this),
txt = me.html(),
found = me.find(needle).length;
if (found != -1) {
txt = txt.replace(/(hello)(?!.*?<\/a>)/gi, '<a href="">$1</a>');
me.html(txt);
}
});
});
Fiddle: http://jsfiddle.net/G8rKw/
Edit: This version works better:
$(document).ready(function() {
var needle = 'hello';
$('p').each(function() {
var me = $(this),
txt = me.html(),
found = me.find(needle).length;
if (found != -1) {
txt = txt.replace(/(hello)(?![^(<a.*?>).]*?<\/a>)/gi, '<a href="">$1</a>');
me.html(txt);
}
});
});
Fiddle: http://jsfiddle.net/G8rKw/3/
Edit again: This time, "hello" is passed as a variable to the regex
$(document).ready(function() {
var needle = 'hello';
$('p').each(function() {
var me = $(this),
txt = me.html(),
found = me.find(needle).length,
regex = new RegExp('(' + needle + ')(?![^(<a.*?>).]*?<\/a>)','gi');
if (found != -1) {
txt = txt.replace(regex, '<a href="">$1</a>');
me.html(txt);
}
});
});
Fiddle: http://jsfiddle.net/webrocker/MtM3s/
Upvotes: 3
Reputation: 148180
You can do it this way,
$('p').each(function(){
if($(this).find('a').length > 0) return;
lastSpaceIndex = $(this).text().lastIndexOf(' ');
if(lastSpaceIndex == -1)
lastSpaceIndex = 0;
WordToReplace = $(this).text().substring(lastSpaceIndex);
idx = $(this).text().lastIndexOf(WordToReplace);
resultstring = $(this).text().substring(0, idx);
$(this).html(resultstring);
$(this).append($( "<a href='#'>" + WordToReplace + "</a>"));
});
Upvotes: 1
Reputation: 79850
Wrote a simple function to check if the replacing text is enclosed by a link tag. See below,
DEMO: http://jsfiddle.net/wyUYb/4/
function changeToLink (sel, txt) {
var regEx = new RegExp(txt, 'g');
$.each($(sel), function (i, el) {
var linkHTML = $(el).html();
var idx = linkHTML.indexOf(txt);
if (idx >= 0) {
var t = linkHTML.substring(idx);
//Fix for IE returning tag names in upper case http://stackoverflow.com/questions/2873326/convert-html-tag-to-lowercase
t = t.replace(/<\/?[A-Z]+.*?>/g, function (m) { return m.toLowerCase(); })
var closingA = t.indexOf('</a>');
t = t.substring(0, closingA);
if (closingA != -1) {
t = t.substring(0, closingA);
if (t.indexOf('<a') < txt.length) {
return;
}
}
linkHTML = linkHTML.replace(regEx, '<a href="">' + txt + '</a>');
$(el).html(linkHTML);
}
});
}
Also even if you add a nested link your browser would simply change it to two links. May be because it is not legal to use nested links. See below,
Also documented in W3C for Nested Links
12.2.2 Nested links are illegal
Links and anchors defined by the A element must not be nested; an A element must not contain any other A elements.
Since the DTD defines the LINK element to be empty, LINK elements may not be nested either.
And that is why browser handles nested link as separate links.
See the firebug inspect on right bottom of the image.
Upvotes: 1
Reputation: 511
Can you not test for the parent element of the word before turning it into a link?
if (parent != 'a') {
// do your thing
}
(I don't know what the actual jQuery would be to test this)
EDIT
The following will replace the word in all <p>
elements that DO NOT contain a link in them.
May not work exactly as required but hopefully points you in the direction
// get all p elements that contain the word hello but DO NOT have link in them
var elems = $('p:contains("hello")').not(':has(a)');
// replace instances of hello in the selected p elements
$(elems).html($(elems).html().replace(/(hello)/g,'<a href="new">$1</a>'));
Upvotes: 0
Reputation: 141
This jQuery solution searches for a particular term and doesn't create a link if it finds it's followed by a closing link tag.
var searchTerm = "hello";
$('p:contains("' + searchTerm + '")').each(function(){
var searchString = $(this).html();
var searchIndex = searchString.indexOf(searchTerm);
var startString = searchString.substr(0 , searchIndex);
var endString = searchString.substr(searchIndex + searchTerm.length);
if(endString.match(/<\/a>/g)) return;
$(this).html(startString + "<a href=''>" + searchTerm + "</a>" + endString);
});
Here's a link to a jsfiddle for it.
Upvotes: 1
Reputation: 34426
First keep the words while getting rid of the current anchor tag, if there is one:
$('a').each(function() {
$(this).replaceWith(this.childNodes);
});
Then do a replace on the string that you need to work with
$('p').html($('p').text().replace('hello', '<a href="">hello</a>'));
Upvotes: 0
Reputation: 1402
Instead of searching for the word and trying to find its parent, search for the link and check the word it contains:
if($('a').text() === "hello"){
//already linked
}else{
//not linked
}
Upvotes: 0
Reputation: 928
You need the jquery :not selector, or .not().
The API docs cover this well, you should be able to select your content, then deselect links within it.
http://api.jquery.com/not-selector/
Upvotes: 0
Reputation: 4560
Try to user .replace jquery function something like this:
var str = $('p').html().replace('(some)','(to some)');
Upvotes: 0