user619891
user619891

Reputation:

find y coordinate for cursor position in div in UIWebView

I have a UIWebView with some basic html that acts as a simple editor.

// in initWithFrame: of UIView subclass.
_editorHTML = [@"<!doctype html>"
                   "<html>"
                   "<head>"
                   "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">"
                   "<style type=\"text/css\">"
                   "#content { font-family:Arial, Helvetica, sans-serif; font-size:1em; } "
                   "</style>"
                   "<script type=\"text/javascript\">"
                   "function load()"
                   "{"
                   "    window.location.href = 'ready://' + document.body.offsetHeight;"
                   "}"
                   "</script>"
                   "</head>"
                   "<body id=\"bodyDiv\" onload=\"load()\">"
                   "<div id=\"content\" contenteditable=\"true\">%@</div>"
                   "</body>"
                   "</html>" retain];

_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
_webView.delegate = self;
_webView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_webView.scrollView.bounces = NO;
[_webView loadHTMLString:[NSString stringWithFormat:_editorHTML, @""] baseURL:[NSURL fileURLWithPath:directory]];

- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSURL *url = [request URL];
    if (navigationType == UIWebViewNavigationTypeOther) {
        if ([[url scheme] isEqualToString:@"ready"]) {

            int height = (int)_webView.frame.size.height;
            [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.getElementById('content').style.minHeight = '%dpx'", height - WEBVIEW_DIVHEIGHT_OFFSET]];

            return NO;
        }
    }
    return YES;
}

So, how can I determine the cursor position in my div so I can update my scrollView to make sure that the content is visible above the UIKeyboard thus not having to make the user manually scroll to keep the text in view?

Upvotes: 4

Views: 5004

Answers (3)

clearscreen
clearscreen

Reputation: 2027

This solution is an evolution of the accepted answer. Fixes the newLine issue in WebKit.

function getCaretClientPosition() {
    var x = 0, y = 0;
    var sel = window.getSelection();
    if (sel.rangeCount) {

        var range = sel.getRangeAt(0);
        var needsToWorkAroundNewlineBug = (range.startContainer.nodeName.toLowerCase() == 'p'
                                           && range.startOffset == 0);

        if (needsToWorkAroundNewlineBug) {
            x = range.startContainer.offsetLeft;
            y = range.startContainer.offsetTop;
        } else {
            if (range.getClientRects) {
                var rects = range.getClientRects();
                if (rects.length > 0) {
                    x = rects[0].left;
                    y = rects[0].top;
                }
            }
        }
    }
    return { x: x, y: y };
}

Upvotes: 1

Dafydd Williams
Dafydd Williams

Reputation: 1232

@timdown Interestingly enough, your script always returns 0,0 for the beginning of a line. The script from [question]: Coordinates of selected text in browser page does return the right Y value, though.

Repeated here for ease of searching:

function getSelectionCoords() {
    var sel = document.selection, range;
    var x = 0, y = 0;
    if (sel) {
        if (sel.type != "Control") {
            range = sel.createRange();
            range.collapse(true);
            x = range.boundingLeft;
            y = range.boundingTop;
        }
    } else if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount) {
            range = sel.getRangeAt(0).cloneRange();
            if (range.getClientRects) {
                range.collapse(true);
                var rect = range.getClientRects()[0];
                x = rect.left;
                y = rect.top;
            }
        }
    }
    return { x: x, y: y };
}

Upvotes: 5

Tim Down
Tim Down

Reputation: 324567

You can get the selected range from the selection and use its getClientRects() method.

Live demo: http://jsfiddle.net/timdown/xMEjD/

Code:

function getCaretClientPosition() {
    var x = 0, y = 0;
    var sel = window.getSelection();
    if (sel.rangeCount) {
        var range = sel.getRangeAt(0);
        if (range.getClientRects) {
            var rects = range.getClientRects();
            if (rects.length > 0) {
                x = rects[0].left;
                y = rects[0].top;
            }
        }
    }
    return { x: x, y: y };
}

Upvotes: 7

Related Questions