I am newbie in programming and I have a question that has been asked many times in the past. I need to implement highlight in some fashion. I have seen a jquery plugin ( SearchHighlight). Jquery is using selectors. To be honest I don't whant to use them. What I need is to "feed" the plugin the string to be highlighted and the string that holds the search words via variables ex.
var searchterms = 'lolo loli let';
var searchstring = ' Lolo loves loli and .... Blah, blah';
var highlightedstring = '';
// SearchHighlight plugin
highlightedstring return;
If the above is not possible is there a way in pure JavaScript to do substring highlighting?
With respect,
Tom
Greece
The concept around highlighting is to grab the html from the container where you're searching an wrap the word(s) found with tags that you can style. Simple example with just one word, but this could be extended with an array of words.
function highlight(word, content) {
var html = $(content).html();
var re = new RegExp(word, 'gi');
$(content).html(html.replace(re, '<code>$&</code>'));
}
highlight('pleasure', '#content');
Demo: http://jsfiddle.net/elclanrs/hdYmb/
Related
I want to find and replace text in a HTML document between, say inside the <title> tags. For example,
var str = "<html><head><title>Just a title</title></head><body>Do nothing</body></html>";
var newTitle = "Updated title information";
I tried using parseXML() in jQuery (example below), but it is not working:
var doc= $($.parseXML(str));
doc.find('title').text(newTitle);
str=doc.text();
Is there a different way to find and replace text inside HTML tags? Regex or may be using replaceWith() or something similar?
I did something similar in a question earlier today using regexes:
str = str.replace(/<title>[\s\S]*?<\/title>/, '<title>' + newTitle + '<\/title>');
That should find and replace it. [\s\S]*? means [any character including space and line breaks]any number of times, and the ? makes the asterisk "not greedy," so it will stop (more quickly) when it finds </title>.
You can also do something like this:
var doc = $($.parseXML(str));
doc.find('title').text(newTitle);
// get your new data back to a string
str = (new XMLSerializer()).serializeToString(doc[0]);
Here is a fiddle: http://jsfiddle.net/Z89dL/1/
This would be a wonderful time to use Javascript's stristr(haystack, needle, bool) method. First, you need to get the head of the document using $('head'), then get the contents using .innerHTML.
For the sake of the answer, let's store $('head').innerHTML in a var called head. First, let's get everything before the title with stristr(head, '<title>', true), and what's after the title with stristr(head, '</title>') and store them in vars called before and after, respectively. Now, the final line is simple:
head.innerHTML = before + "<title>" + newTitle + after;
I want to find and replace text in a HTML document between, say inside the <title> tags. For example,
var str = "<html><head><title>Just a title</title></head><body>Do nothing</body></html>";
var newTitle = "Updated title information";
I tried using parseXML() in jQuery (example below), but it is not working:
var doc= $($.parseXML(str));
doc.find('title').text(newTitle);
str=doc.text();
Is there a different way to find and replace text inside HTML tags? Regex or may be using replaceWith() or something similar?
I did something similar in a question earlier today using regexes:
str = str.replace(/<title>[\s\S]*?<\/title>/, '<title>' + newTitle + '<\/title>');
That should find and replace it. [\s\S]*? means [any character including space and line breaks]any number of times, and the ? makes the asterisk "not greedy," so it will stop (more quickly) when it finds </title>.
You can also do something like this:
var doc = $($.parseXML(str));
doc.find('title').text(newTitle);
// get your new data back to a string
str = (new XMLSerializer()).serializeToString(doc[0]);
Here is a fiddle: http://jsfiddle.net/Z89dL/1/
This would be a wonderful time to use Javascript's stristr(haystack, needle, bool) method. First, you need to get the head of the document using $('head'), then get the contents using .innerHTML.
For the sake of the answer, let's store $('head').innerHTML in a var called head. First, let's get everything before the title with stristr(head, '<title>', true), and what's after the title with stristr(head, '</title>') and store them in vars called before and after, respectively. Now, the final line is simple:
head.innerHTML = before + "<title>" + newTitle + after;
I am working on a functionality which will convert matching tags or keywords into links inside particular DIV tag.
Background: I store article body & keywords related to articles in database & while display article in a web page i pass keywords as and array to jQuery function which then search's through the text inside <div id ="article-detail-desc" > ...</div> and converts each matching element into link.
My code works fine but it has flows.
It doen't search for words it search's for any match even if it is part of a word or HTML element which breaks my HTML code.
how can this function be modified so that it also search for matching words
function HighlightKeywords(keywords)
{
var el = $("#article-detail-desc");
var language = "en-US";
var pid = 100;
var issueID = 10;
$(keywords).each(function()
{
var pattern = new RegExp("("+this+")", ["gi"]);
var rs = "<a class='ad-keyword-selected' href='en/search.aspx?Language="+language+"&PageId="+pid+"&issue="+issueID+"&search=$1' title='Seach website for: $1'><span style='color:#990044; tex-decoration:none;'>$1</span></a>";
el.html(el.html().replace(pattern, rs));
});
}
HighlightKeywords(["Amazon","Google","Starbucks","UK","US","tax havens","Singapore","Hong Kong","Dubai","New Jersey"]);
Link on fiddle http://jsfiddle.net/Dgysc/25/
I think the easiest way would be to use word boundaries. So you'd have that:
var pattern = new RegExp("(\\b"+this+"\\b)", ["gi"]);
Edit:
Quick hack to be sure it's not matching the US inside the html elements:
var pattern = new RegExp("(\\b"+this+"\\b)(?![^<]*?>)", ["gi"]);
SInce we are using direct word matching, adding space before and after the keywords may help you,
var pattern = new RegExp("( "+this+" )", ["gi"]);
http://jsfiddle.net/Dgysc/28/
I'm making a highlighting plugin for a client to find things in a page and I decided to test it with a help viewer im still building but I'm having an issue that'll (probably) require some regex.
I do not want to parse HTML, and im totally open on how to do this differently, this just seems like the the best/right way.
http://oscargodson.com/labs/help-viewer
http://oscargodson.com/labs/help-viewer/js/jquery.jhighlight.js
Type something in the search... ok, refresh the page, now type, like, class or class=" or type <a you'll notice it'll search the actual HTML (as expected). How can I only search the text?
If i do .text() it'll vaporize all the HTML and what i get back will just be a big blob of text, but i still want the HTML so I dont lose formatting, links, images, etc. I want this to work like CMD/CTRL+F.
You'd use this plugin like:
$('article').jhighlight({find:'class'});
To remove them:
.jhighlight('remove')
==UPDATE==
While Mike Samuel's idea below does in fact work, it's a tad heavy for this plugin. It's mainly for a client looking to erase bad words and/or MS Word characters during a "publishing" process of a form. I'm looking for a more lightweight fix, any ideas?
You really don't want to use eval, mess with innerHTML or parse the markup "manually". The best way, in my opinion, is to deal with text nodes directly and keep a cache of the original html to erase the highlights. Quick rewrite, 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're doing any manipulation on the page, you might want to replace the caching with another clean-up mechanism, not trivial though.
You can see the code working here: http://jsbin.com/anace5/2/
You also need to add display:block to your new html elements, the layout is broken on a few browsers.
In the javascript code prettifier, I had this problem. I wanted to search the text but preserve tags.
What I did was start with HTML, and decompose that into two bits.
The text content
Pairs of (index into text content where a tag occurs, the tag content)
So given
Lorem <b>ipsum</b>
I end up with
text = 'Lorem ipsum'
tags = [6, '<b>', 10, '</b>']
which allows me to search on the text, and then based on the result start and end indices, produce HTML including only the tags (and only balanced tags) in that range.
Have a look here: getElementsByTagName() equivalent for textNodes.
You can probably adapt one of the proposed solutions to your needs (i.e. iterate over all text nodes, replacing the words as you go - this won't work in cases such as <tag>wo</tag>rd but it's better than nothing, I guess).
I believe you could just do:
$('#article :not(:has(*))').jhighlight({find : 'class'});
Since it grabs all leaf nodes in the article it would require valid xhtml, that is, it would only match link in the following example:
<p>This is some paragraph content with a link</p>
DOM traversal / selector application could slow things down a bit so it might be good to do:
article_nodes = article_nodes || $('#article :not(:has(*))');
article_nodes.jhighlight({find : 'class'});
May be something like that could be helpful
>+[^<]*?(s(<[\s\S]*?>)?e(<[\s\S]*?>)?e)[^>]*?<+
The first part >+[^<]*? finds > of the last preceding tag
The third part [^>]*?<+ finds < of the first subsequent tag
In the middle we have (<[\s\S]*?>)? between characters of our search phrase (in this case - "see").
After regular expression searching you could use the result of the middle part to highlight search phrase for user.
I need to replace some text that is on the page within the body tag. I am using javascript but have jquery available if needed. I basically need to replace test® (test with the registered trademark) with TEST® or tests® with TESTS® and it could even be test with TEST® or tests with TESTS®. I am able to uppercase them but its not liking to work for me with the ® sign, it wants to put duplicates on ones that already have it. Basically anything on the page that has the word test or tests should be TEST® or TESTS® if it is plural. Any help is appreciated.
EDIT:
So now I have this:
var html = $('body').html();
var html = html.replace(/realtor(s)?(®)?/gi, function(m, s1, s2){
var s = s1?s1.toUpperCase():"";
var reg = s2?s2:'®';
return "REALTOR"+s+reg;
});
$('body').html(html);
Its working well other than it is duplicating the ® on the ones that already had them any ideas on how not to?
As others have already said, you will not be able to match the ®, you need to match on
\u00ae.
The code you provided needs to be changed to:
var html = $('body').html();
var html = html.replace(/realtor(s)?(\u00ae)?/gi, function(m, s1, s2){
var s = s1?s1.toUpperCase():"";
var reg = s2?s2:'®';
return "REALTOR"+s+reg;
});
$('body').html(html);
To expand on jAndy's answer, try this:
$("div, p, span").each(function(){
o = $(this);
o.html( o.text().replace(/test(|s)\u00ae/gi, function($1){
return($1.toUpperCase());
}));
});
Using the code you provided, try this:
$(document).ready(function(){
$('body').html( $('body').html().replace(/realtor(|s)\u00ae/gi, function($1){
return($1.toUpperCase() );
}));
})
Instead of creating something from scratch try using an alternate library. I develop with PHP so using a library that has identical methods in JavaScript is a life saver.
PHP.JS Library
var newReplaced = $P.str_replace("find","replace",varSearch);
The tricky part here is to match the ®, which is a Unicode character, I guess...
Have you tried the obvious?
var newStr = str.replace(/test(s)?®?/gi, function(m, s1){
var s = s1?s1.toUpperCase():"";
return "TEST"+s+"®";
});
If the problem is that ® does not match, try with its unicode character number:
/test(s)?\u00ae/
Sorry if the rest does not work, I assume your replacement already works and you just have to also match the ® so that it does not get duplicated.