Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

MythicFrost

macrumors 68040
Original poster
Mar 11, 2009
3,944
40
Australia
Hi,

I'm currently working in a test project trying to figure out how to implement a custom context menu for a UIWebView. That way I can have menu items that say for example, "open in a new tab", or "save image".

I've been following this tutorial: http://www.icab.de/blog/2010/07/11/customize-the-contextual-menu-of-uiwebview/

However, after having followed the instructions, nothing happens. I'm sure I've made some mistake somewhere, but I've no idea what it is. I'll post the relevant code below:

AppDelegate.h
Code:
#import <UIKit/UIKit.h>
#import "MyWindow.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) MyWindow *window;
@end
(This previously said UIWindow instead of MyWindow.)

ViewController.m
Code:
#import "ViewController.h"
#include "WebViewAdditions.h"

@implementation ViewController
@synthesize myWebView;

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    myWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
    myWebView.scalesPageToFit = YES;

    myWebView.delegate = self;
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextualMenuAction:) name:@"TapAndHoldNotification" object:nil];
    
    
    NSURL *url = [[NSURL alloc] initWithString:@"http://www.apple.com"];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
    [myWebView loadRequest:request];
    
    [self.view addSubview:myWebView];
}

- (void)contextualMenuAction:(NSNotification*)notification
{
    CGPoint pt;
    NSDictionary *coord = [notification object];
    pt.x = [[coord objectForKey:@"x"] floatValue];
    pt.y = [[coord objectForKey:@"y"] floatValue];
    
    // convert point from window to view coordinate system
    pt = [myWebView convertPoint:pt fromView:nil];
    
    // convert point from view to HTML coordinate system
    CGPoint offset  = [myWebView scrollOffset];
    CGSize viewSize = [myWebView frame].size;
    CGSize windowSize = [myWebView windowSize];
    
    CGFloat f = windowSize.width / viewSize.width;
    pt.x = pt.x * f + offset.x;
    pt.y = pt.y * f + offset.y;
    
    [self openContextualMenuAt:pt];
}

- (void)openContextualMenuAt:(CGPoint)pt
{
    // Load the JavaScript code from the Resources and inject it into the web page
    NSString *path = [[NSBundle mainBundle] pathForResource:@"JSTools" ofType:@"js"];
    NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    [myWebView stringByEvaluatingJavaScriptFromString: jsCode];
    
    // get the Tags at the touch location
    NSString *tags = [myWebView stringByEvaluatingJavaScriptFromString:
                      [NSString stringWithFormat:@"MyAppGetHTMLElementsAtPoint(%i,%i);",(NSInteger)pt.x,(NSInteger)pt.y]];
    
    // create the UIActionSheet and populate it with buttons related to the tags
    UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Contextual Menu" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:nil];
    
    // If a link was touched, add link-related buttons
    if ([tags rangeOfString:@",A,"].location != NSNotFound) {
        [sheet addButtonWithTitle:@"Open Link"];
        [sheet addButtonWithTitle:@"Open Link in Tab"];
        [sheet addButtonWithTitle:@"Download Link"];
    }
    // If an image was touched, add image-related buttons
    if ([tags rangeOfString:@",IMG,"].location != NSNotFound) {
        [sheet addButtonWithTitle:@"Save Picture"];
    }
    // Add buttons which should be always available
    [sheet addButtonWithTitle:@"Save Page as Bookmark"];
    [sheet addButtonWithTitle:@"Open Page in Safari"];
    
    [sheet showInView:myWebView];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    [webView stringByEvaluatingJavaScriptFromString:@"document.body.style.webkitTouchCallout='none';"];
}

None of the methods I've added to ViewController.m from the tutorial work at all. An exception to webViewDidFinishLoad which runs as expected. I used break points to determine that they don't load after I tap and hold on a link at Apple.com. Also, the app compiles without error or warning.

You can find the contents of MyWindow.h/m at the tutorial. I haven't changed any of it, although I did add break points to see if any code in .h/m runs, which it doesn't.

Does anyone have any idea of my mistake? Any help would be appreciated! Thanks.
 
Does anyone have any idea? There's not a bit of code that runs, and I really have no idea why or what to try to figure this out. This looks promising but without help I don't think I'll be able to solve this, so if anyone knows the answer or knows a better or easier way to do this please let me know. Thanks.
 
Does anyone have any idea? There's not a bit of code that runs, and I really have no idea why or what to try to figure this out. This looks promising but without help I don't think I'll be able to solve this, so if anyone knows the answer or knows a better or easier way to do this please let me know. Thanks.

That's kinda of confusing. The article talks about a context menu however implements a UISheet. LOL.

Are you using iOS 5? If so read the comments below the article.
 
That's kinda of confusing. The article talks about a context menu however implements a UISheet. LOL.

Are you using iOS 5? If so read the comments below the article.
Mmm, I see. Yes I am using iOS 5, and I have read the comments. I replied as Yoffa, lol... I'll keep in mind the comment about iOS 5 calculating things different as soon as I actually get any code running.

What he said seems to be correct, that is to make sure that I'm using the subclassed window rather than the standard one. That seems to be the problem since SendEvent in MyWindow (my subclassed window) doesn't seem to run.

I'm using a project that has a storyboard instead of a XIB file, so I'm unsure how to change the window it loads. I changed a line in my AppDelegate.h from UIWindow to:

@property (strong, nonatomic) MyWindow *window;

But that's the only place I've found to change anything relating to the window.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.