Customising context menu for UIWebView (following tutorial... help)

Discussion in 'iOS Programming' started by MythicFrost, Sep 26, 2011.

  1. MythicFrost macrumors 68040

    MythicFrost

    Joined:
    Mar 11, 2009
    Location:
    Australia
    #1
    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.
     
  2. MythicFrost thread starter macrumors 68040

    MythicFrost

    Joined:
    Mar 11, 2009
    Location:
    Australia
    #2
    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.
     
  3. Sykte macrumors regular

    Joined:
    Aug 26, 2010
    #3
    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.
     
  4. MythicFrost thread starter macrumors 68040

    MythicFrost

    Joined:
    Mar 11, 2009
    Location:
    Australia
    #4
    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.
     

Share This Page