Search code examples
wkwebviewmac-catalystmacos-sonoma

Text selection not working in Catalyst app's WKWebView on macOS Sonoma


Can not select anything within WkWebView editor view of my MacCatalyst app when running on macOS 14 Sonoma.

Any selection gesture or command key fails to select anything in content editable WKWebView, so none of the Editor tools can be activated.

My application uses the nnhubbard / ZSSRichTextEditor WKWebView-based Rich Text Editor: https://github.com/nnhubbard/ZSSRichTextEditor. The app is built with Xcode 15.0 or 15.0.1.

The app is a Catalyst app that implements an editor view with a ZSSRichTextEditor WKWebView.

The problem does not occur if the the app is run in iOS or macOS 11, 12, or 13 (Catalina, Monterey, or Ventura.) The issue only occurs in macOS 14 Sonoma.

The following error message is logged whenever an attempt to select any text in the WKWebView content:

0x1359ecc18 - [pageProxyID=14, webPageID=15, PID=14,932] WebPageProxy::didFailProvisionalLoadForFrame: frameID=1, isMainFrame=1, domain=NSURLErrorDomain, code=18,446,744,073,709,550,614, isMainFrame=1, willInternallyHandleFailure=0


Solution

  • Apple Feedback provided a fix:

    8/29/24, 2:31:25 PM CDT Apple Feedback FB14734097 — macOS - Can't select text in editable WWebView 8/29/24, 2:31:25 PM CDT

    Hi there! It looks like you reported another radar a while back - the HTML page is equally broken in all browsers, including Safari.

    My recommendation is to replace this ZSSRichTextEditor.js code:

    zss_editor.getCaretYPosition = function() {
        var sel = window.getSelection();
        // Next line is comented to prevent deselecting selection. It looks like work but if there are any issues will appear then uconmment it as well as code above.
        //sel.collapseToStart();
        var range = sel.getRangeAt(0);
        var span = document.createElement('span');// something happening here preventing selection of elements
        range.collapse(false);
        range.insertNode(span);
        var topPosition = span.offsetTop;
        span.parentNode.removeChild(span);
        return topPosition;
    }
    

    ...with this:

    zss_editor.getCaretYPosition = function() {
        const sel = window.getSelection();
        if (!getSelection().rangeCount)
            return 0;
    
        const clientRects = getSelection().getRangeAt(0).getClientRects();
        return (clientRects.length ? clientRects[0].top : 0) + pageYOffset;
    }
    

    The latter is (1) more correct, (2) more performant, and (3) more compatible (works in Chrome and Firefox as well).