How to implement text searching inside UIWebView?
Updated tutorial for this can be found here : http://zaldzbugz.posterous.com/how-to-search-a-string-inside-uiwebview
This links provides a more detailed information to implement this with a good example.
See you there!
Does it work for a uiweview which loads a pdf
HI QBurst,
Im afraid not. This is only considering that what you are loading in the UIWebview was an HTML.
If you want, you can convert your PDf files to HTML then you can proceed working with highlighting.
I created an app in which i used an ePub ebook format but i extracted an html source first right before doing anything and viewing pages inside UIWebview.
Regards,
ZaldzBugz
Hi zaldzbugz,
can you send me code for convert pdf files to html with xcode tool?
carmelogallo.home [at] gmail.com
i must search with iphone into pdf file.
Thanks in advance!
See this link PDF to HTML
hi I was luck to find your topic in yahoo
your Topics is excellent
I obtain a lot in your blog really thanks very much
btw the theme of you blog is really splendid
where can find it
Thank you bet365. By the way, this theme is already available in WordPress admin. You can use it anytime there.
ZaldzBugz
I can’t seem to get this to work. It keeps coming back w/ result=0 and nothing get’s highlighted (even when i’ve made sure that the text is there. I’m not sure what i’m doing wrong.
Hi Truedon, Thank you for your comment.
Hope this may help.
1. ) Make sure that youre javascript code is working correctly. Note that javescript is case sensitive.
2.) Make sure that the javascript method names are called correctly.
[NSString stringWithFormat:@"uiWebview_HighlightAllOccurencesOfString('%@')",str]
ZaldzBugz
Hey, thanks for the quick reply. I’ve checked all of that and all seems ok. Here is what I have. ViewController.h file with the following:
#import
#import “search.h”
@interface highlightViewController : UIViewController {
IBOutlet UIWebView *webView;
}
@end
————-
My ViewController.m file looks like this:
#import “highlightViewController.h”
#import “search.h”
@implementation highlightViewController
- (void)viewDidLoad {
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@”test” ofType:@”htm”]isDirectory:NO]]];
NSString *str = @”evidence”
[webView highlightAllOccurencesOfString:@"str"];
[super viewDidLoad];
}
@end
————
I then created the category for the UIWebView class as directed above. I called it search.h, here are contents:
#import
@interface UIWebView (search)
- (NSInteger)highlightAllOccurencesOfString:(NSString*)str;
- (void)removeAllHighlights;
@end
———————-
search.m file looks like this:
#import “search.h”
@implementation UIWebView (search)
- (NSInteger)highlightAllOccurencesOfString:(NSString*)str
{
NSString *path = [[NSBundle mainBundle] pathForResource:@”SearchWebView” ofType:@”js”];
NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[self stringByEvaluatingJavaScriptFromString:jsCode];
NSLog(@”JSCODE=%@”,jsCode);
NSString *startSearch = [NSString stringWithFormat:@"MyApp_HighlightAllOccurencesOfString('%@')",str];
[self stringByEvaluatingJavaScriptFromString:startSearch];
NSString *result = [self stringByEvaluatingJavaScriptFromString:@"MyApp_SearchResultCount"];
return [result integerValue];
}
- (void)removeAllHighlights
{
[self stringByEvaluatingJavaScriptFromString:@"MyApp_RemoveAllHighlights()"];
}
@end
—————-
HTML file loads w/ webview, I can see that javascript does load (using NSLog) but it does not highlight work. It’s almost as IF the function call never gets executed. I’ve traced it and see that it does get executed but doesn’t do anything. What am I doing wrong?? It’s killing me. Pls help.
Thanks,
-Truedon
Hi Truedon,
Ive checked youre code above and i think this might be the problem.
1.) NSString *str = @”evidence” (the “” signs you used here when i copy pasted are invalid, use the double quotes used by objective-c-> “string”);
2.) [webView highlightAllOccurencesOfString:@"str"]; (Youre trying to find a string “str” here not the string “evidence”).
If you want to find a string “evidence”, it should look like this below.
NSString *str = @”evidence”;
[webView highlightAllOccurencesOfString:str];
-ZaldzBugz
hi,i am trying to search text from the pdf file after rendering in iphone through drawLayer.i seen your post post which is great and worth but can you help me to find text location where the search term exactly.
Hi zaldzbugz,
I am having problem while executing this code. It is failing in this condition…
uiWebview_HighlightAllOccurencesOfStringForElement(element,keyword)
{
if(element)// here it is failing for me…
{
}
Pls help me out.
Thanks in advance.
Just check my code:
//SearchWebView.h
#import
@interface UIWebView (SearchWebView)
- (NSInteger)highlightAllOccurencesOfString:(NSString*)str;
- (void)removeAllHighlights;
@end
//SearchWebView.m
- (NSInteger)highlightAllOccurencesOfString:(NSString*)str
{
NSString *path = [[NSBundle mainBundle] pathForResource:@”WebSearch” ofType:@”js”];
NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[self stringByEvaluatingJavaScriptFromString:jsCode];
NSString *startSearch = [NSString stringWithFormat:@"uiWebview_HighlightAllOccurencesOfString('%@')",str];
[self stringByEvaluatingJavaScriptFromString:startSearch];
NSString *result = [self stringByEvaluatingJavaScriptFromString:@"uiWebview_SearchResultCount"];
return [result integerValue];
}
- (void)removeAllHighlights
{
[self stringByEvaluatingJavaScriptFromString:@"uiWebview_RemoveAllHighlights()"];
}
Main Controller :
[mAnnotationWebView highlightAllOccurencesOfString:@"to"];
Hi zaldzbugz,
Thanks dude. I got solution for my problem. Actually i am calling [myWebView highlightAllOccurencesOfString:@"keyword"];
method even before UIWebview is still loading. So for me document.body is coming as nil.
Thanks for code. I appreciate it.
hi i’m also facing same problem.Do you know how to debug the javascript code.
Regards
sagar
I’m a noob at iOS programming. I’m trying to use your code. I’m having two problems:
1. Lots of “Test1ViewController” may not respond to “-stringByEvaluatingJavaScriptFromString:’ warnings.
2. When I run the search on my web view, the app goes dark and terminates.
What have I done wrong?
- JSB
Hi and Thanks for this great help! But my UIWebViewSearch.js seems to have a lot of errors when I copied and pasted as you wrote and then imported to Xcode. Xcode expects several characters etc. Can you upload the UIWebViewSearch.js document? BTW, I do not have experience in Java. And that is why i do not know what I am doing when I created the js file with TextEdit. Please Help because I have been looking for this for a long time. Also, regrading the methods, it says: ViewController may not respond to -stringByEvaluationJavaScript FromString. Thanks in Advance.
Ok, I was importing the document. I think that is why I got the errors. THe problem now is that in the main View Controller, where I declared the WebView, after I put [WebView highlightAllOccurencesOfString:@"keyword"]; within the ViewDidLoad Method, it says that UIWebView may not respond to highlightAllOcurrencesOfString and after I try to run it, it says,. [UIWebView highlightAllOccurencesOfString:]: unrecognized selector sent to instance 0x4b43bb0
2011-06-18 11:17:28.401 WebView[2456:207] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[UIWebView highlightAllOccurencesOfString:]: unrecognized selector sent to instance 0x4b43bb0′
Thanks in advance
HI Nash,
highlightAllOccurencesOfString: is a function under a class of type UIWebView so you need to declare it in the interface file .h.
Thats why youre having problems with this code: [WebView highlightAllOccurencesOfString:@"keyword"]; because maybe youre WebView don’t have a class reference which in that class this “highlightAllOccurencesOfString:” was declared and implemented.
What you need to do:
1.) Have a javascript like the scode above.
2.) Create a class of type UIWebview (@Interface WebView : UIWebView) and put all the methods above.
3.) If you use interface builder to link your WebView, link youre WebView to the class you just created.
That would solve the problem.
Regards,
ZaldzBugz
Thanks for your quick response! I now fixed it and it does not show me warnings. However, although the html loads, it does not highlight the keyword I add. What am I doing wrong?
Best!
BTW, when I debug it, the result is nil, since it says about my keyword that “Variable is not a CFString”, then result = nil. How do I fix this? THanks again!
have you tried already to linkn your UIWebView variable to the class you just created? Or is the UIWebView you just created have been an IBOutlet link to your interface builder?
Hi zaldzbugz
Indeed my WebView is linked as the class WebView I created and is also linked in the IB to the IBOutlet. My code is written as you wrote:
VIEW CONTROLLER H.
#import
#import “WebView.h”
@class WebView;
@interface SearchWebViewViewController : UIViewController {
IBOutlet WebView *webView;
}
@end
VIEWCONTROLLER M.
#import “SearchWebViewViewController.h”
@implementation SearchWebViewViewController
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn’t have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren’t in use.
}
#pragma mark – View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:@”Document” ofType:@”html”]isDirectory:NO]]];
[webView highlightAllOccurencesOfString:@"nonsense"];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
@end
WEBVIEW H.
#import
@interface WebView : UIWebView {
}
- (NSInteger)highlightAllOccurencesOfString:(NSString*)str;
- (void)removeAllHighlights;
@end
WEBVIEW M.
#import “WebView.h”
@implementation WebView
- (NSInteger)highlightAllOccurencesOfString:(NSString*)str
{
NSString *path = [[NSBundle mainBundle] pathForResource:@”UIWebViewSearch” ofType:@”js”];
NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[self stringByEvaluatingJavaScriptFromString:jsCode];
NSString *startSearch = [NSString stringWithFormat:@"uiWebview_HighlightAllOccurencesOfString('%@')",str];
[self stringByEvaluatingJavaScriptFromString:startSearch];
NSString *result = [self stringByEvaluatingJavaScriptFromString:@"uiWebview_SearchResultCount"];
return [result integerValue];
}
- (void)removeAllHighlights
{
[self stringByEvaluatingJavaScriptFromString:@"uiWebview_RemoveAllHighlights()"];
}
@end
HTML
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
This is an Html Document
And it only has nonsense on it
I want to find different words
Let’s see if it works
UIWEBVIEWSEARCH.JS
var uiWebview_SearchResultCount = 0;
/*!
@method uiWebview_HighlightAllOccurencesOfStringForElement
@abstract // helper function, recursively searches in elements and their child nodes
@discussion // helper function, recursively searches in elements and their child nodes
element – HTML elements
keyword – string to search
*/
function uiWebview_HighlightAllOccurencesOfStringForElement(element,keyword) {
if (element) {
if (element.nodeType == 3) { // Text node
while (true) {
//if (counter < 1) {
var value = element.nodeValue; // Search for keyword in text node
var idx = value.toLowerCase().indexOf(keyword);
if (idx =0; i–) {
uiWebview_HighlightAllOccurencesOfStringForElement(element.childNodes[i],keyword);
}
}
}
}
}
// the main entry point to start the search
function uiWebview_HighlightAllOccurencesOfString(keyword) {
uiWebview_RemoveAllHighlights();
uiWebview_HighlightAllOccurencesOfStringForElement(document.body, keyword.toLowerCase());
}
// helper function, recursively removes the highlights in elements and their childs
function uiWebview_RemoveAllHighlightsForElement(element) {
if (element) {
if (element.nodeType == 1) {
if (element.getAttribute(“class”) == “ActiveReaderHighlight”) {
var text = element.removeChild(element.firstChild);
element.parentNode.insertBefore(text,element);
element.parentNode.removeChild(element);
return true;
} else {
var normalize = false;
for (var i=element.childNodes.length-1; i>=0; i–) {
if (uiWebview_RemoveAllHighlightsForElement(element.childNodes[i])) {
normalize = true;
}
}
if (normalize) {
element.normalize();
}
}
}
}
return false;
}
// the main entry point to remove the highlights
function uiWebview_RemoveAllHighlights() {
uiWebview_SearchResultCount = 0;
uiWebview_RemoveAllHighlightsForElement(document.body);
}
Hope all this helps to find what I am missing since it seems everyone else in this forum got it right and wrote the same : (
I see,
You created a class WebView.h/.m and you make it as a type of your variable (IBOutlet WebView *webView;). Try to use IBOutlet with the default UIWebView object like this (IBOutet UIWebView *webView) and in your interface builder Inspector module, have this link reference and there is an option in interface builder to directly link your UIWebView component to the class you just created namely “WebView”..
I just did that, but it now says UIWebView may not respond to highlightAllOccurencesOfString. BTW, I forgot to tell you that there is another warning that says: ]warning: no rule to process file ‘$(PROJECT_DIR)/SearchWebView/UIWebViewSearch.js’ of type sourcecode.javascript for architecture i386. Is it important?
And finally, after debugging it keeps saying that Variable is not a CFString and result is nil.
Can you send me a sample code to my email? nashmusic@me.com. Now it finds the keyword buy I do not see nothing highlighted. Please Help
You have error on remove functionality.
At first you set span class name to “uiWebviewHighlight”
span.setAttribute(“class”,”uiWebviewHighlight”);
but after you check this classname for “ActiveReaderHighlight”..
Write instead this if (element.getAttribute(“class”) == “uiWebviewHighlight”) and all will works fine
@beryllum: thank you for pointing that out. Updated the source code above.
Regards,
ZaldzBugz
thank you for this post!i’m a newbie and i’m not so able to put in place!please can you attach to this post a zip with a simple code for sampe?!!thank you!!
Hi
Thanks for your posting.
I am sure that your code successfully runs on iphone.
But I have one question.
When the keyword that I want to find in webview has a tag in itself, the js code can’t find the keyword.
for example , I want to find a keyword “That is RAYWENDERLICH.” in the webview.
But the keyword is really “That is RAYWENDERLICH“.
in this case, the js code can’t find this keyword.
Thanks for any help.
hi! how i can put info from UITextField to [theWebView highlightAllOccurencesOfString:@"here"];
Thanks for any help.
Hi Guys,
Thank you for your comments.
@Nikita: You need to have an object referencing you UITextField so that you can pass your textField’s info to your webview.
Or you can use any of the UITextFields Delegate methods and within those delegate method you will call your webview to execute your js script since these delegate methods has parameters that is a reference to your UITextField.
@zezhun: I will try my best to find ways to solve your problem.
Anyways, I will be re-posting this tutorial to my other blog and update everything with best example and details.
http://zaldzbugz.posterous.com
Regards,
ZaldzBugz
Guys, I updated this tutorial with a more clearer details with examples to my other blog. See link below.
http://zaldzbugz.posterous.com/how-to-search-a-string-inside-uiwebview
Is it possible in pdf also?
Unfortunately, it’s not possible in PDF files. For PDF files, you need to use QuartzCore framework.
Does it work for a uiweview which loads a Xhtml?