<p>Lorem Ipsum <a href="#">Link</a> <div ... </div> </p>
I want to put a span around 'Lorem Ipsum' without using jQuery, so the result looks like:
<p><span>Lorem Ipsum </span><a href="#">Link</a> <div ... </div> </p>
Any ideas? Thanks
<p>Lorem Ipsum <a href="#">Link</a> <div ... </div> </p>
I want to put a span around 'Lorem Ipsum' without using jQuery, so the result looks like:
<p><span>Lorem Ipsum </span><a href="#">Link</a> <div ... </div> </p>
Any ideas? Thanks
Combine these 2 tutorials:
PPK on JavaScript: The DOM - Part 3
Basically you need to access the node value, remove it, and create a new child element who's node value is the value of the parent item's node, then append that element (span in this case) to the parent (paragraph in this case)
How about using a regular expression in javascript and replacing "Lorem Ipsum" with "<span>Lorem Ipsum</span>" (just remember that you will have to get the "innerHTML" of the element and then replace the whole lot again which may be a bit slow)
First, you need some way of accessing the paragraph. You might want to give it an id
attribute, such as "foo":
<p id="foo">Lorem Ipsum <a href="#">Link</a> <div ... </div> </p>
Then, you can use document.getElementById
to access that element and replace its children as required:
var p = document.getElementById('foo'),
firstTextNode = p.firstChild,
newSpan = document.createElement('span');
// Append "Lorem Ipsum" text to new span:
newSpan.appendChild( document.createTextNode(firstTextNode.nodeValue) );
// Replace old text node with new span:
p.replaceChild( newSpan, firstTextNode );
To make it more reliable, you might want to call p.normalize()
before accessing the first child, to ensure that all text nodes before the anchor are merged as one.
Oook, So you want to replace a part of a text node with an element. Here's how I'd do it:
function giveMeDOM(html) {
var div = document.createElement('div'),
frag = document.createDocumentFragment();
div.innerHTML = html;
while (div.firstChild) {
frag.appendChild( div.firstChild );
}
return frag;
}
var p = document.getElementById('foo'),
firstChild = p.firstChild;
// Merge adjacent text nodes:
p.normalize();
// Get new DOM structure:
var newStructure = giveMeDOM( firstChild.nodeValue.replace(/Lorem Ipsum/i, '<span>$&</span>') );
// Replace first child with new DOM structure:
p.replaceChild( newStructure, firstChild );
Working with nodes at the low level is a bit of a nasty situation to be in; especially without any abstraction to help you out. I've tried to retain a sense of normality by creating a DOM node out of an HTML string produced from the replaced "Lorem Ipsum" phrase. Purists probably don't like this solution, but I find it perfectly suitable.
EDIT: Now using a document fragment! Thanks Crescent Fresh!
UPDATE:
The method below will search through the subtree headed by container
and wrap all instances of text
in a span element. The words can occur anywhere within a text node, and the text node can occur at any position in the subtree.
(OK, so it took more than a few minor tweaks. :P)
function wrapText(container, text) {
// Construct a regular expression that matches text at the start or end of a string or surrounded by non-word characters.
// Escape any special regex characters in text.
var textRE = new RegExp('(^|\\W)' + text.replace(/[\\^$*+.?[\]{}()|]/, '\\$&') + '($|\\W)', 'm');
var nodeText;
var nodeStack = [];
// Remove empty text nodes and combine adjacent text nodes.
container.normalize();
// Iterate through the container's child elements, looking for text nodes.
var curNode = container.firstChild;
while (curNode != null) {
if (curNode.nodeType == Node.TEXT_NODE) {
// Get node text in a cross-browser compatible fashion.
if (typeof curNode.textContent == 'string')
nodeText = curNode.textContent;
else
nodeText = curNode.innerText;
// Use a regular expression to check if this text node contains the target text.
var match = textRE.exec(nodeText);
if (match != null) {
// Create a document fragment to hold the new nodes.
var fragment = document.createDocumentFragment();
// Create a new text node for any preceding text.
if (match.index > 0)
fragment.appendChild(document.createTextNode(match.input.substr(0, match.index)));
// Create the wrapper span and add the matched text to it.
var spanNode = document.createElement('span');
spanNode.appendChild(document.createTextNode(match[0]));
fragment.appendChild(spanNode);
// Create a new text node for any following text.
if (match.index + match[0].length < match.input.length)
fragment.appendChild(document.createTextNode(match.input.substr(match.index + match[0].length)));
// Replace the existing text node with the fragment.
curNode.parentNode.replaceChild(fragment, curNode);
curNode = spanNode;
}
} else if (curNode.nodeType == Node.ELEMENT_NODE && curNode.firstChild != null) {
nodeStack.push(curNode);
curNode = curNode.firstChild;
// Skip the normal node advancement code.
continue;
}
// If there's no more siblings at this level, pop back up the stack until we find one.
while (curNode != null && curNode.nextSibling == null)
curNode = nodeStack.pop();
// If curNode is null, that means we've completed our scan of the DOM tree.
// If not, we need to advance to the next sibling.
if (curNode != null)
curNode = curNode.nextSibling;
}
}