You really don't want to use eval, mess with innerHTML or parse markup "manually." The best way, in my opinion, is to directly deal with text nodes and save the cache of the original html to erase the main points. Fast rewriting with comments:
(function($){ $.fn.jhighlight = function(opt) { var options = $.extend($.fn.jhighlight.defaults, opt) , txtProp = this[0].textContent ? 'textContent' : 'innerText'; if ($.trim(options.find.length) < 1) return this; return this.each(function(){ var self = $(this); // use a cache to clear the highlights if (!self.data('htmlCache')) self.data('htmlCache', self.html()); if(opt === 'remove'){ return self.html( self.data('htmlCache') ); } // create Tree Walker // https://developer.mozilla.org/en/DOM/treeWalker var walker = document.createTreeWalker( this, // walk only on target element NodeFilter.SHOW_TEXT, null, false ); var node , matches , flags = 'g' + (!options.caseSensitive ? 'i' : '') , exp = new RegExp('('+options.find+')', flags) // capturing , expSplit = new RegExp(options.find, flags) // no capturing , highlights = []; // walk this wayy // and save matched nodes for later while(node = walker.nextNode()){ if (matches = node.nodeValue.match(exp)){ highlights.push([node, matches]); } } // must replace stuff after the walker is finished // otherwise replacing a node will halt the walker for(var nn=0,hln=highlights.length; nn<hln; nn++){ var node = highlights[nn][0] , matches = highlights[nn][1] , parts = node.nodeValue.split(expSplit) // split on matches , frag = document.createDocumentFragment(); // temporary holder // add text + highlighted parts in between // like a .join() but with elements :) for(var i=0,ln=parts.length; i<ln; i++){ // non-highlighted text if (parts[i].length) frag.appendChild(document.createTextNode(parts[i])); // highlighted text // skip last iteration if (i < ln-1){ var h = document.createElement('span'); h.className = options.className; h[txtProp] = matches[i]; frag.appendChild(h); } } // replace the original text node node.parentNode.replaceChild(frag, node); }; }); }; $.fn.jhighlight.defaults = { find:'', className:'jhighlight', color:'#FFF77B', caseSensitive:false, wrappingTag:'span' }; })(jQuery);
If you are doing any kind of manipulation on the page, you might want to replace caching with another cleaning mechanism, but not trivial.
You can see the code that works here: http://jsbin.com/anace5/2/
You also need to add display: block to your new html elements, the layout is split into several browsers.
source share