As a continuation of this post I wanted to share a few things about how I solved the problem of working w/ text in a UIWebView.
I did it mostly thru running Javascript via the stringByEvaluatingJavaScriptFromString: method on the UIWebView which I extended thru another class (e.g., MyWebView).
There’s a few key actions:
- override canPerformAction:withSender: to prevent the built-in menu
- create the JavaScript to get aspects of the selection in the web view
- run the JavaScript to get the info into your app
1. override canPerformAction:withSender: to prevent the built-in menu
Also, I override the canPerformAction:withSender: method to avoid the Copy/Cut/Paste menu from popping up. This is called when the user holds their finger down to select text in a webview. This gives you two things: 1. the chance to prevent the Copy/Cut/Paste menu and 2. it’s the notification that they are selecting text.
So how do you get what they selected?
2. create the JavaScript to get aspects of the selection in the web view
I saved my Javascript in separate files so I can read in the text and run it in the method (mentioned above). The following Javascript returns what is selected…
[code]
function f() {
var txt = window.getSelection();
return (txt.anchorOffset + ‘|’ + txt.anchorNode.textContent + ‘|’ + txt.focusOffset + ‘|’ + txt.focusNode.textContent);
}
f();
[/code]
The values are:
- txt.anchorOffset – the offset, in characters, where the selection begins
- txt.anchorNode.textContent – the text of that node (e.g., paragraph based on <p>)
- txt.focusOffset – the offset, in characters, where the selection ends
- txt.focusNode.TextContent – the text of that node
B/c the selection may go across nodes (e.g., selection starts in one paragraph and into another), you use anchor and focus objects.
From this you can determine what text is selected IF you also have the content the webview is rendering (the html or whatever). And based on that, you can insert font or style tags to alter the text (e.g., highlight, bold, etc.). If you don’t have the content, you can still get what they are selecting, but you probably can’t do anything w/ it in the web view.
3. run the JavaScript to get the info into your app
I store the above JavaScript in a file called getSelection.txt in the project. To run it, I have the following method…
[code]
-(NSString*)webviewGetSelection
{
NSString *js = [UtilString contentsOfFile:@"getSelection" withExt:@"txt"];
NSString *result = [self stringByEvaluatingJavaScriptFromString:js];
NSLog(@"selected: %@", result);
return result;
}
[/code]
You as a result you might get:
0|Here is a paragraph.|3|Here is a paragraph.
This means they selected the 0-3 characters of that paragraph which works out to be the word: Here.
Another example result might be:
4|The middle word.|3|The first word.
This means the 4th character of the paragraph comprised of ‘The middle word.’ thru the 3rd character of the paragraph comprised of ‘The first word.’
This works out to be that they selected ‘middle word. The’
However, there may be a paragraph between those two paragraphs. If so, that entire paragraph is included in the selection.
If you have the content of the web view, you can search for the first paragraph and the second and get everything btwn them too. Otherwise, you’ll need to get more into the anchorNode/focusNode and/or create JavaScript to count the parentNodes and such to determine where the text is.
Some other useful Javascript methods are:
- self.find(<string>); – navigates to the next occurrence of a string
- window.pageYOffset; – basically tells you the scroll position of the webview
- window.scrollTo(x, y); – allows you to effectively set the scroll position
I hope this helps. Feel free to comment/improve/etc.
Pingback: Detecting taps and events on UIWebView « Brainwash Inc. – iPhone/Mobile Development
Thank you for sharing. I think it very useful.
Would you mind sharing some sample code which gets the selected text on UIWebView? Your suggestions are great, but I can’t accomplish them. I am at the point of being able to detect touch inside UIWebView (i used a link u provided) but stuck with getting the selected text. Thank you.
Updated w/ more details and examples.
Very nice. One question. It appears that the copy: selector is never called, so I can’t suppress the Copy popover menu. Did you find a way to do that? Did the SDK change since this post in Feb.?
I see there is a css style, -webkit-touch-callout: “none” — is that required, and if so, won’t that disable the text selection as well?
Would love some help if there is help to be had.
You need to override the canPerformAction:withSender: method to prevent the menu from popping up.
I don’t recall using the webkit-touch-callout: so I don’t think that’s necessary, but that might lead to a better solution than mine??? 🙂
@David Swanson:
Did you solve that problem by any chance? I’m encountering the same thing. For some reason I can’t suppress the Copy-menuItem.
I don’t recall having that problem and I haven’t looked at the code in a while. Let me check… looks like I just remove the menu as soon as the canPerformAction:withSender: method is called…
[sourcecode]
– (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
[UIMenuController sharedMenuController].menuVisible = NO;
return NO;
}
[/sourcecode]
I’m actually adding another menu-item so that won’t work for me, unfortunately.
After disable the UIMenuController and calling the javascript to get the selected text …..I want to implement a custom UIMenucontroller with custom UIMenu.
Can you give me some kind of suggestions……
I’m not sure, but maybe another reader can help???
I want to allow user to highlight the text which he can see when he come back to same page
You should be able to store the results and the url of the page to re-highlight later.
I understand the fact that you are getting the selected text by running the JS. However, how do I highlight the selected text?
Since you have the selected text, you can programmatically change the html content to include font/style tags at the beginning and end of the selected text. Use those tags to highlight or otherwise modify the display of the text.
Comments are closed.