Question

I have a UIWebView which loads a HTML string and content can be added to doing using Javascript.

Is there any way to know when something (text or an image) has been pasted in the web view.

NSString *path = [[NSBundle mainBundle] pathForResource:@"htmlString" ofType:@"txt"];
NSString *htmlString = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[self.ibWebView loadHTMLString:htmlString baseURL:nil];


- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    NSString *jsToEncloseInEditableContainer = [NSString stringWithFormat:@"function contentedited(e){window.location='mpscontentedited://' + e.keyCode;};(function() {var body = document.body;var contentContainer =  document.createElement('div');contentContainer.id = 'content';contentContainer.setAttribute('contenteditable','true');contentContainer.style.fontFamily=' Helvetica';contentContainer.style.marginTop=\"15px\";contentContainer.onkeydown = contentedited;contentContainer.onpaste=contentedited;var node;while(node=body.firstChild) {contentContainer.appendChild(node);}body.appendChild(contentContainer);%@body=undefined;delete body;contentContainer=undefined;delete contentContainer;node=undefined;delete node;})();", @"contentContainer.focus();"];
    [self.ibWebView stringByEvaluatingJavaScriptFromString:jsToEncloseInEditableContainer];
}

I have tried overriding UIResponder's paste: method, but it never gets called.

- (void)paste:(id)sender
{
    NSLog(@"paste not called");
}

I have also tried to creating a custom menu button

UIMenuController *menu = [UIMenuController sharedMenuController];
UIMenuItem *item = [[UIMenuItem alloc] initWithTitle:@"Paste Custom" action:@selector(pasteCustom:)];
[menu setMenuItems:@[item]];
[menu setMenuVisible:YES];

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(pasteCustom:))
    {
        return YES;
    }
    return [super canPerformAction:action withSender:sender];
}

- (void)pasteCustom:(id)sender
{
    NSLog(@"paste custom");
    [super paste:sender]; // --> calling this causes a crash (unrecognized selector sent to instance)
}

What am I doing wrong?

I either want to know when something is pasted or I want to have a custom menu button that behaves similar to default paste button.

Thanks in advance.

Was it helpful?

Solution

Casting is not magic.

I repeat: Casting is not magic!

It does't change the run-time type of an object. If it didn't respond to a selector as a UIWebView, it won't respond to it as a UIMenuItem either. You have to detect the event using JavaScript and bridge your JavaScript function to Objective-C. Use the onpaste JavaScript event handler, then do something like what is described here:

<!-- snippet from your HTML string -->
<script type="text/javascript">

    function call_objc_paste(text)
    {
        window.location.href = "fakescheme://" + text;
    }

</script>

<input type="text" onpaste="call_objc_paste(this.value);" />

// Objective-C code:
webView.delegate = self;
[webView loadHTMLString:htmlStr baseURL:nil];

- (BOOL)           webView:(UIWebView *)wv
shouldStartLoadWithRequest:(NSURLRequest *)rq
            navigationType:(UIWebViewNavigationType)navT
{
    NSString *rqStr = rq.URL.absoluteString;
    NSString *scheme = @"fakescheme://";
    if ([rqStr hasPrefix:scheme]) {
        NSString *pastedText = [rqStr substringFromIndex:scheme.length];
        // potentially do somethin with pastedText, then

        return NO;
    }

    // it's not our fake URL scheme, just normal navigation
    return YES;
}

OTHER TIPS

Resurrecting this question for posterity:

Have a look at my answer here: Manipulate paste content in WKWebView the solution uses method Swizzling and can be used for this case too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top