Bug 184550 - [Attachment Support] WebEditingDelegate's shouldInsertNode cannot access dragged file content
Summary: [Attachment Support] WebEditingDelegate's shouldInsertNode cannot access drag...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: HTML Editing (show other bugs)
Version: Safari 11
Hardware: Mac macOS 10.13
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-04-12 11:29 PDT by Jonathan Hammer
Modified: 2018-04-12 12:42 PDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Hammer 2018-04-12 11:29:47 PDT
Starting in macOS 10.13.4, the "node" parameter that is passed to -[WebEditingDelegate webView:shouldInsertNode:replacingDOMRange:givenAction:] when a file is dragged from the Finder and dropped into a contenteditable area contains zero children (same is true for an image dragged from Safari). This makes it very difficult for the client to figure out if the user has dropped a file attachment (or image) into the document, which it may need to know in order to import/access that file's data. Prior to macOS 10.13.4, the "node" parameter would include one or more <ATTACHMENT> child nodes that we could use as a strong hint that the user had dropped N file attachments or images (that we could then import off the pasteboard). This behavior is now hidden behind the Apple-private -[WebPreferences setAttachmentElementEnabled:] method.

It would be really helpful if WebKit1 clients had some way of being notified that an attachment was dropped into the document, with some way to access/import the dropped data. I can see that support for this is coming along nicely under WK2 (albeit as SPI), but there are still WK1 clients around like us who are finding it more and more difficult to handle situations like these, especially as the behavior has changed quite a bit from 10.10 -> 10.11 -> 10.12 -> 10.13. Thanks so much for your consideration.

Note: the above is true for copy/paste, as well.
Comment 1 Wenson Hsieh 2018-04-12 11:43:31 PDT
Hmmmm...the attachment element is non-standard, and intended as SPI only for internal Apple use. Might I recommend using the JavaScript API to intercept the `drop` event and perform custom handling by accessing DataTransfer.files? Or at the very least, transitioning to WK2 and using WKWebView's attachment element SPI? (it's still not recommended to use our SPI, since those aren't things we precisely document and ensure compatibility with moving forward).
Comment 2 Jonathan Hammer 2018-04-12 12:25:56 PDT
Yes, we would like to avoid using SPI. Thanks for your suggested workarounds. Some quick feedback as to why they probably aren't feasible for us right now:

1. We use WebKit1 as a WYSIWYG HTML email editor and allow the user to edit the HTML source. We disable JavaScript in the editor because HTML email doesn't support it anyway. We'd like to avoid enabling JS for the purposes of handling this drag, since it means we'd have to fight with any JS the user had written into their document (or sanitize it away). It is cleaner for us to work "one level up" in the ObjC API instead of running our app logic inside the same JS context that the user's code is executing.

2. WK2 is the future, but the ObjC API is not nearly as rich as WK1 (at least when it comes to editing), and we're not able to get the same functionality -- not yet, at least. My feeling is that WK2 would prefer that the developer use JS to do the heavy lifting, rather than ObjC API. That means big rewrites for us and runs us into the same concerns mentioned in #1 above.

It would be great to have a supported solution that didn't rely on SPI. I understand there is probably not appetite to invest time into making this happen in WebKit1.

I think prior to 10.12, the "node" parameter would contain one child node (div? span?) per attachment, with the .textContent of each child node equal to the file URL of the attachment. I don't know if it's possible to go back to that, but it was a serviceable solution for our purposes.

Thanks again.
Comment 3 Wenson Hsieh 2018-04-12 12:42:32 PDT
(In reply to Jonathan Hammer from comment #2)
> Yes, we would like to avoid using SPI. Thanks for your suggested
> workarounds. Some quick feedback as to why they probably aren't feasible for
> us right now:
> 
> 1. We use WebKit1 as a WYSIWYG HTML email editor and allow the user to edit
> the HTML source. We disable JavaScript in the editor because HTML email
> doesn't support it anyway. We'd like to avoid enabling JS for the purposes
> of handling this drag, since it means we'd have to fight with any JS the
> user had written into their document (or sanitize it away). It is cleaner
> for us to work "one level up" in the ObjC API instead of running our app
> logic inside the same JS context that the user's code is executing.
> 

Right — there's no public API to enable only JS supplied from native code (and not page markup). Now...as a workaround, there does exist the `javaScriptMarkupEnabled` property for WebKit1 in WebPreferencesPrivate.h, which would allow you to achieve this behavior (disable JS from the page, but enable any JS injected natively via WebView API/SPI).

> 2. WK2 is the future, but the ObjC API is not nearly as rich as WK1 (at
> least when it comes to editing), and we're not able to get the same
> functionality -- not yet, at least. My feeling is that WK2 would prefer that
> the developer use JS to do the heavy lifting, rather than ObjC API. That
> means big rewrites for us and runs us into the same concerns mentioned in #1
> above.

Indeed. For instance, we support mechanisms such as input events (https://www.w3.org/TR/input-events-2/) which would allow JavaScript developers to customize the behavior of various editing operations by calling preventDefault() on the `beforeinput` event, and using document.execCommand() to carry out DOM mutations as needed.

> 
> It would be great to have a supported solution that didn't rely on SPI. I
> understand there is probably not appetite to invest time into making this
> happen in WebKit1.
> 

Correct. We hope that more clients will be able to make the transition to WebKit2 :)

> I think prior to 10.12, the "node" parameter would contain one child node
> (div? span?) per attachment, with the .textContent of each child node equal
> to the file URL of the attachment. I don't know if it's possible to go back
> to that, but it was a serviceable solution for our purposes.

The fact that we were exposing raw file paths to web content was actually a security/privacy bug that we fixed recently, in 10.13.4. That we were accidentally exposing our own non-standard <attachment> elements to web developers in general was also an issue that we fixed in this time frame.

> 
> Thanks again.