You can use jQuery to find all text nodes inside an element. Subsequently, you can use the DOM functions (instead of the regular expression) to split the text around the specified word, and then wrap the word inside the tooltip. Here is an example:
function replaceTextWithSpan(node, text, options) { var searchText = text.toLowerCase(), currentNode = node, matchIndex, newTextNode, newSpanNode; while ((matchIndex = currentNode.data.toLowerCase().indexOf(searchText)) >= 0) { newTextNode = currentNode.splitText(matchIndex); currentNode = newTextNode.splitText(searchText.length); newSpanNode = document.createElement("span"); newSpanNode.className = "tooltip"; newSpanNode.setAttribute("data-tooltip", options["data-tooltip"]); currentNode.parentNode.insertBefore(newSpanNode, currentNode); newSpanNode.appendChild(newTextNode); } }
And the test:
<div id="test">Size: 40; Color: 30; <b>Bold Size Test:</b> 20; <span>Another Size Test: 10</span></div>
$("#test, #test *").contents().filter(function () { return this.nodeType == this.TEXT_NODE; }).each(function () { replaceTextWithSpan(this, "Size", { "data-tooltip": "The Size of a Unit is controlled by the Color of the Unit." }); }); $("#test, #test *").contents().filter(function () { return this.nodeType == this.TEXT_NODE; }).each(function () { replaceTextWithSpan(this, "Color", { "data-tooltip": "The Color of a Unit is a standard Setting." }); }); alert($("#test").html());
And the result:
<span class="tooltip" data-tooltip="The Size of a Unit is controlled by the Color of the Unit.">Size</span>: 40; <span class="tooltip" data-tooltip="The Color of a Unit is a standard Setting.">Color</span>: 30; <b>Bold <span class="tooltip" data-tooltip="The Size of a Unit is controlled by the Color of the Unit.">Size</span> Test:</b> 20; <span>Another <span class="tooltip" data-tooltip="The Size of a Unit is controlled by the Color of the Unit.">Size</span> Test: 10</span>
Demo here
Original answer: here is a solution that does not use RegEx:
- Iterate over child text / HTML nodes within an element
- Skip HTML nodes and text nodes that do not contain a search string
- Break text node before and after search string (so you get three text nodes)
- Wrap the middle node inside the span
Here is the code (I don't know what is complicated):
function replaceTextWithSpan(node, text, options) { var searchText = text.toLowerCase(), currentNode = node.firstChild, matchIndex, newTextNode, newSpanNode; while (currentNode) { matchIndex = currentNode.nodeType === currentNode.TEXT_NODE ? currentNode.data.toLowerCase().indexOf(searchText) : -1; if (matchIndex >= 0) { newTextNode = currentNode.splitText(matchIndex); currentNode = newTextNode.splitText(searchText.length); newSpanNode = document.createElement("span");
Here is the test:
var node = document.createElement("div"); node.innerHTML = "Size: 40; Color: 30; Span: For testing"; replaceTextWithSpan(node, "Size", { className: "highlight" }); replaceTextWithSpan(node, "Color", { className: "highlight" }); replaceTextWithSpan(node, "Span", { className: "highlight" }); alert(node.innerHTML);
This produces the following output (fairly printed):
<span class="highlight">Size</span>: 40; <span class="highlight">Color</span>: 30; <span class="highlight">Span</span>: For testing
Demo here