views:

1855

answers:

2

I have a view controller with a UIWebView controller. I'm trying to get the javascript inside the html content of the web view to pass some information to my objective c code. I came across a number of examples online that set window.location in a javascript function and then catch the event generated by setting the view controller to be the web view's delegate and catching it in the shouldStartLoadWithRequest function. Unfortunately I can't get it to work because for me shouldStartLoadWithRequest is never called even though I'm setting the web view's delegate.

My code is as follows:

The interface:

@interface StoryTextViewController : UIViewController <UIWebViewDelegate>
{
    IBOutlet UIWebView *storyWebView; 
    NSString *information;
}

@property (nonatomic, retain) IBOutlet UIWebView *storyWebView;
@property (nonatomic, retain) NSString *information;

@end

In the interface, the *information variable is set by the previous view that calls StoryTextViewController.

The implementation:

#import "StoryTextViewController.h"

@implementation StoryTextViewController

@synthesize storyWebView;
@synthesize information;

- (NSString *) contructHTMLText
{
    NSString *HTMLText = @"";

    NSArray *words = [information componentsSeparatedByString:@" "];
    NSString *header =
    @"<html>\n"
    "<head>\n"
    "<script type=\"text/javascript\">\n"

    "function marktext(theSpanID)\n"
    "{\n"
    " var theSpan=document.getElementById(theSpanID);\n"
    " if (theSpan.className == \"noHilite\")\n"
    " {\n"
    "  theSpan.className = \"hilite\";\n"
    "  window.location = \"true\";\n"
    " }\n"
    " else\n"
    " {\n"
    "  theSpan.className = \"noHilite\";\n"
    "  window.location = \"false\";\n"
    " }\n"
    "}\n"

    "</script>\n"

    "<style type=\"text/css\">\n"

    ".hilite\n"
    "{\n"
    " background-color:red;\n"
    " color:white;\n"
    " font: bold 60px arial,sans-serif\n"
    "}\n"

    ".noHilite\n"
    "{\n"
    " background-color:white;\n"
    " color:black;\n"
    " font: 60px arial,sans-serif\n"
    "}\n"

    "</style>\n"

    "</head>\n"
    "<body>\n"
    "<div class=\"storyText\">\n";

    NSString *tailer = 
    @"</div>\n"
    "</body>\n"
    "</html>\n";

    HTMLText = [HTMLText stringByAppendingString:header];
    for (NSInteger i = 0; i < [words count]; i ++)
    {
     NSString *tag = [NSString stringWithFormat:@" <span id=\"mytext%d\" class=\"noHilite\" onclick=\"marktext(\'mytext%d\')\">%@</span>&nbsp;\n", i, i, (NSString *)[words objectAtIndex:i]];
     HTMLText = [HTMLText stringByAppendingString:tag];
    }
    HTMLText = [HTMLText stringByAppendingString:tailer];
    NSLog(HTMLText);
    return HTMLText;
}

// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
     storyWebView.delegate = self;
    }
    return self;
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
    [super viewDidLoad];
    NSString *HTMLData = [self contructHTMLText];
    [storyWebView loadHTMLString:HTMLData baseURL:[NSURL URLWithString: @""]]; 
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

- (void)dealloc {
    [super dealloc];
}

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 
{   
    // handle event here 
    return true;
}

@end

Whats happening is that basically, the constructHTML function takes the text inside the *information variable and wraps every word in the text with some html and javascript such that whenever a word is clicked, a css high-lighting is applied on it. What I want to do is to count the number of high-lighted words. I do this by trying to pass something in the function thats called whenever a word is clicked but like i said, the shouldStartLoadWithRequest method thats supposed to be fired is never executed.

I've seen a lot of people do this sort of thing but I cant seem to figure out why its not running for me

A: 
  • Shouldn't window.location be the value of the target URL you are going to? In your marktext function you're setting it to true or false. shouldStartLoadWithRequest gets called only when a URL request has been received and is about to go somewhere. Not sure setting the location to a boolean is enough to trigger a navigation event. You can set it to a magic URL then return FALSE from the shouldStartLoadWithRequest routine if it's asking to navigate to that specific magic URL and prevent it from actually going somewhere. Valid URLs can then be allowed to go through.

  • Also might want to take a look at the response to this SO question. There may be some timing issues with window.location.

Ramin
I'm actually trying to set window.locaton to the strings "true" or "false", not that it matters because my code doesn't work for any string. I also looked at the link you sent me but it wasn't what I needed. His problem is that shouldStartLoadWithRequest works TOO well for him where as in my case it doesn't get called at all!
Not sure why you're trying to set the location value to 'true' or 'false?' That's like typing "http://true" in the URL bar. What happens if you use a valid URL like http://www.stackoverflow.com? My point was I don't think shouldStartLoadWithRequest gets called unless you give it a valid URL to follow.
Ramin
A: 

You can put breakpoint on setting delegate

if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
    storyWebView.delegate = self;
}

I'm pretty sure storyWebView is nil on that moment.

You can fix it in this manner:

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSString *HTMLData = [self contructHTMLText];
    // empty statement
    // the trick is that if the view is not loaded from the .nib yet
    // it will be loaded and all connections established

    if (self.view);

    // here is setting delegate
    storyWebView.delegate = self;
    [storyWebView loadHTMLString:HTMLData baseURL:[NSURL URLWithString: @""]];  
}
Valerii Hiora
I did as you suggested but it didn't make any difference. self wasn't nil to begin with anyway. Anything else you might suggest?
self surely will be not nil, what about storyWebView?
Valerii Hiora
nope. story view displays the html fine too. im completely stumped. if you want maybe i could send you what i coded? my boss is getting a bit impatient and im getting desparate
You can send it. Use my first name dot second name at gmail dot com
Valerii Hiora
OK, the real reason of the problem is that you're loading HTML through loadHTMLString
Valerii Hiora