简体   繁体   中英

How to insert image in UIWebview at caret position?

This is the code I am currently using to insert an image, however, my webview loses its focus after the insertion made. But most oddly, I also have a notification set for keyboardWillShowNotification; and this notification is invoked after the insertion but no keyboard is present.

Can anyone give any solution on this problem?

//allow me to programmatically bring up keyboard
_changWeiBo.keyboardDisplayRequiresUserAction = NO;
[_changWeiBo stringByEvaluatingJavaScriptFromString:@"document.getElementById('content').focus()"];

[_changWeiBo stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.execCommand('insertImage', false, '%@')", imagePath]];

//disallow me to programmatically bring up keyboard
_changWeiBo.keyboardDisplayRequiresUserAction = YES;

Thanks to @alex-i, this solution below (enhanced by myself) perfectly solves the bug when user can't insert an image at caret postion because the UIWebview loses its focus when other views.

This is the most minimal working version to insert an image at caret position.

    this.prepareInsertImage = function(){
        try{
            backuprange();
        }
        catch(exc){
            log('prepareInsertImage: ' + exc);
        }
    }

    this.insertImage = function(imgPath){
        try{
            restorerange();
            document.execCommand("InsertImage",true,imgPath);
        }
        catch(exc){
            log('insertImage: ' + exc);
        }
    }
    var focusRange;
    function backuprange(){
        var selection = window.getSelection();
        focusRange = selection.getRangeAt(0);
        focusRange.setEnd(focusRange.startContainer, focusRange.startOffset);
    }
    function restorerange(){
        var selection = window.getSelection();
        selection.removeAllRanges();
        selection.addRange(focusRange);
    }

For anyone who wants to use this code in the future, simply call this:

    //Before UIImagePicker pops up
    [yourWebView stringByEvaluatingJavaScriptFromString:@"prepareInsertImage()"];

    //After UIImagePicker selects a image and you edit and store the image elsewhere
    NSString* imagePath = @"the path for your image....";
    [yourWebView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"insertImage('%@')",imagePath]];

I didn'tuse the 'insertImage' command, sice I needed specific formatting of the image (in my case, the html will hold a thumb, when tapped will open in full screen). It should work correctly with the insertImage command as well. Here's the objective-c code:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    NSAssert([[info objectForKey:UIImagePickerControllerMediaType] isEqualToString:(NSString *)kUTTypeImage], @"Unhandled type: %@", [info objectForKey:UIImagePickerControllerMediaType]);
    // this is just to gather some paths for the picked image
    [_rtDelegate richEditor:self saveImage:[info objectForKey:UIImagePickerControllerEditedImage] completion:^(NSString *thumbPath, NSString *largePath, CGSize thumbSize) {
        [self stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"docState.insertImage('%@', '%@', %d)", thumbPath, largePath, (int)thumbSize.height/2]];
    }];

    [picker dismissModalViewControllerAnimated:YES];
}
-(void)onTapInsertPhoto:(UIBarButtonItem *)sender{
    [self stringByEvaluatingJavaScriptFromString:@"docState.prepareInsertImage();"];
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
    imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    imagePicker.delegate = self;
    imagePicker.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeImage];
    imagePicker.allowsEditing = YES;

    UIViewController *vc = [[[UIApplication sharedApplication] keyWindow] rootViewController];
    [vc presentViewController:imagePicker animated:YES completion:nil];
    [imagePicker release];
}

Here's the javascript (most important are the focusRange and backupRange):

this.prepareInsertImage = function(){
    try{
        backuprange();
    }
    catch(exc){
        log('prepareInertImage: ' + exc);
    }
}
this.insertImage = function(thumbPath, largePath, displayHeight){
    try{
        restorerange();
        // may work with the insertImage command here
        var imgwrap = document.createElement('a');
        imgwrap.href = largePath;
        imgwrap.setAttribute('href', 'rte:image:'+largePath);
        imgwrap.setAttribute('contenteditable', 'false');
        imgwrap.className = 'imgwrap';
        var img = document.createElement('img');
        img.setAttribute('src', thumbPath);
        img.setAttribute('height', displayHeight);
        imgwrap.appendChild(img);
        window.getSelection().getRangeAt(0).insertNode(imgwrap);
    }
    catch(exc){
        log('insertImage: ' + exc);
    }
}
var focusRange;
function backuprange(){
    var selection = window.getSelection();
    focusRange = selection.getRangeAt(0);
    focusRange.setEnd(focusRange.startContainer, focusRange.startOffset);
}
function restorerange(){
    var selection = window.getSelection();
    selection.removeAllRanges();
    selection.addRange(focusRange);
}

You don't need 'docState' in the objective-c code, and 'this' in the javascript code - I used them because I have a class with more methods in javascript, which also holds some states.

Also note that keyboardDisplayRequiresUserAction only works on iOS 6.0+, so previous iOS systems will not show the keyboard automatically (but still insert the image at the right position).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM