singerdmx / flutter-quill

Rich text editor for Flutter
https://pub.dev/packages/flutter_quill
MIT License
2.59k stars 837 forks source link

[Web] Pasting HTML Doesn't Work Propertly #1998

Open jezell opened 4 months ago

jezell commented 4 months ago

Is there an existing issue for this?

Flutter Quill version

9.5.13

Steps to reproduce

Copy HTML with bullets on web, paste.

A few problems here:

First off the browser won't actually let non plain text formats through using the clipboard API, so the clipboard service always thinks there is no html on the clipboard. On web, non text formats are only available from the paste event.

Steps to fix:

1) Handle "paste" event on window instead of using standard paste hotkey logic (note that the same path is also needed to paste things like images from the clipboard on web). If a quill node is focused, handle the paste event and insert the data into the quill editor. The paste event will contain, files, and multiple clipboard formats that are unavailable to the browser clipboard API. 2) If button action is pressed and initiates a paste, unfortunately, the only way to get the data is using a browser extension (this is what google docs does). Until there is a browser extension for flutter quill, quill should do what google docs does when you don't have the browser extension installed, which is display a dialog when pressing the paste button that explains the limitation and shows the hotkey they need to press in order to paste. Once there is an extension, this dialog can provide a link to install the browser extension.

Expected results

Bullets are preserved

Actual results

Bullets are not preserved

Code sample

Code sample ```dart [Paste your code here] ```

Screenshots or Video

Screenshots / Video demonstration [Upload media here]

Logs

Logs ```console [Paste your logs here] ```
EchoEllet commented 4 months ago

The rich text pasting requires native code, super_clipboard plugin has been moved to flutter_quill_extensions.

The rich text pasting is not available when using flutter_quill without an implementation of ClipboardService that supports HTML and Markdown.

Include flutter_quill_extensions and call FlutterQuillExtensions.useSuperClipboardPlugin

The plugin super_clipboard already supports the web, see Super Clipboard Accessing Clipboard on Web for details.

By default, the package doesn't register the paste event that's specific to the browser. you can register for this event if needed.

However, we should update the docs.

Until there is a browser extension for flutter quill

This is a bit out of scope for the project, we will have to maintain the extension for different browsers, different platforms, and places where the extension is published, the project might already have an extension, requiring the installation of different extensions, also the users usually don't know the app they're installing use, Flutter Quill, so naming the extension Flutter Quill can be confusing and might not what the developer want, they won't be able to change the name and icon of the extension easily without building each version, fork the project, change the name and icon, the developer might want to suggest to installing the extension on first app startup or when first time using the editor, also Quill JS seems to have a similar issue.

which is display a dialog when pressing the paste button that explains the limitation and shows the hotkey they need to press in order to paste. Once there is an extension, this dialog can provide a link to install the browser extension.

This seems to require a specific message that needs to be translated to 40 locals, some developers prefer different custom messages, so we might introduce changes that make it possible for the developer to show this message instead.

The same issue on Android: If you paste using the paste button above the keyboard instead of the context menu, the same issue occurs.

The rich text pasting feature works well for most use cases, though it's not meant to be perfect, especially on Flutter web. It's already disabled by default.

It might not work on all browsers (e.g., Firefox), similar issues on Quill JS and similar frameworks, see Quill JS #2832 as an example.

jezell commented 4 months ago

The rich text pasting requires native code, super_clipboard plugin has been moved to flutter_quill_extensions.

On web it requires no native code. package:web works fine, we've used it to implement this elsewhere. Super clipboard isn't required at all to make this work on web, which is the most likely place that you're going to be having HTML pasted.


EventStreamProviders.pasteEvent
        .forTarget(window.document)
        .listen(onPaste);

The rich text pasting is not available when using flutter_quill without an implementation of ClipboardService that supports HTML and Markdown.

The flutter_quill code that uses ClipboardService won't work on all browsers because FF doesn't support clipboard read until 127 (https://caniuse.com/mdn-api_clipboard_read), so this would have to come from the paste event. While ClipboardService might be a great option outside of the web, it isn't a great option on the web. If restricting to FF > 127 (released only a month ago and currently at 0% globally), then I believe reading html is a now possibility. However, paste event event handler is still useful for image paste, or potentially for pasting raw quill deltas from a native quill editor to a in browser editor.

Now maybe you could argue an extension is the best place for this and that would be fine, but can the extension stop the ctrl+v from being handled by the quill editor so that it can be manually handled in the paste event?

This is a bit out of scope for the project, we will have to maintain the extension for different browsers, different platforms and places to where the extension published, the project might already have an extension, requiring to install different extensions

It's still useful to have an example extension somewhere for receiving non plain text clipboard formats like images or quill deltas. Publishing plugins may be out of scope, but the code is very useful even if people are publishing their own versions of the plugin for their own apps.

This seems to require a specific message that needs to be translated to 40 locals, some developers prefer different custom message, so we might introduce changes that make it possible for the developer to show this message instead.

Even a hook is better than the current state.

The rich text pasting feature works well for most use cases, though it's not meant to be perfect, especially on Flutter web. It's already disabled by default.

Pasting HTML doesn't work at all on web as far as i can tell. It certainly shouldn't be disabled by default on web. Not sure what the argument is for not supporting it out of the box on web, maybe the super_clipboard dependency? But like I said, super_clipboard isn't needed for this of web and isn't actually a good solution for paste on the web anyway due to the browser clipboard api situation.

EchoEllet commented 4 months ago

On web it requires no native code. package:web works fine, we've used it to implement this elsewhere.

Maybe it doesn't require a third-party plugin and only needs package:web, which has been stable in Flutter 3.21, though it still requires JS-specific code.

On web it requires no native code. package:web works fine, we've used it to implement this elsewhere.

The current solution is not designed to support the web and might need to be refactored to support it. Or might be supported without changing the ClipboardService at all, we still need to document the code to explain why we're not using super_clipboard for the web.

It's still useful to have an example extension somewhere for receiving non-plain text Clipboard formats like images or quill deltas. Publishing plugins may be out of scope, but the code is very useful even if people are publishing their own versions of the plugin for their own apps.

Providing an example extension code seems to be useful. Managing it and publishing it might not fit most of the needs and use cases. Even if the developer doesn't have an extension and users only need to install the Flutter Quill extension, it's still quite confusing to the users, it should be related to the app name itself, if there is a bug related to the app code that we don't have access to, users might report it in this repository.

Even a hook is better than the current state.

You're right.

Though I still prefer to do it in a way that prevents using extensive conditional checks for the current platform, it would be very useful if there's a way to remove the code that has an if statement to check the current platform in the final release app.

We should make the code extensible in an efficient way rather than solving a problem by showing a UI message.

Pasting HTML doesn't work at all on web as far as i can tell.

Most of the developers use the package for Mobile or Desktop, which is why we have limited support for the Web, I suggest solving this issue in a way that doesn't affect the other platforms.

This seems to require a platform-specific code. All platforms support retrieving the Clipboard content in HTML at any time from anywhere.

Thank you for the suggestions for fixing the issue.

EchoEllet commented 4 months ago

This issue seems to be easy to fix

Screenshot ![Screenshot](https://github.com/singerdmx/flutter-quill/assets/73608287/d8fc106e-1c0e-4725-87cd-277dbaf36d4a)

Just a minor thing to keep in mind, with each feature we implement, most of the features are configurations/options that are disabled or enabled by default, we depend heavily on conditional checks, and a lot of the time it will be more performance efficient if it's implemented into the app project itself, for example

which is display a dialog when pressing the paste button that explains the limitation and shows the hotkey they need to press in order to paste.

This dialog, might not be something all developers want, or they might want to customize some things like the barrierColor, what if they want to use CupertinoDialog? or with a different message, different behavior, or they might have an extension already or planning on developing one, if they want to show the dialog somewhere else, maybe at the start of the web application or the quick setup screen/dialog, flutter itself provide a lot of options, we just need a way to delegate rather than copying the options of the showDialog and put them into the code and pass them with a default value, what if the default value changed or they added new parameters which they do that all the time, a lot of options, and a lot of customization that is easier and more effective to implement into the app code itself, we should make the project extensible rather than focus on implementing customization options, the QuillSimpleToolbar for example, have a conditional check for almost all buttons, configurations, usually the developer wants to show a few buttons without depending on the conditional check, we depend on it just to provide options to customize, usually creating a custom toolbar is easier and more effective, we just need to provide functions, helpers, classes or something that make it easier to implement this specific feature, or the buttons themselves.

For now, I will document how to implement this feature in the README of flutter_quill_extensions

EchoEllet commented 1 month ago

As an update, the issue of registering the paste event was an issue only on Firefox.

The reason why the rich text paste not working properly is that the paste logic on the web seems to be separated from non-web platforms, but this is not documented. It might be a bug as well.

So even if you comment on everything related to clipboard paste in QuillController, QuillRawEditorState and related classes.

The plain text functionality still works, and the rich text paste (that's already a feature before this issue and recent changes) doesn't even trigger. The paste event (introduced in #2009) will conflict with the plain text, causing the content to be pasted twice (#2220).

EchoEllet commented 1 month ago

While trying out the Flutter/WASM application with the Clipboard API implementation on Firefox (on macOS):

image

It seems to be working fine, the following returns true:

window.navigator.getProperty('clipboard'.toJS) != null &&
    window.navigator.hasProperty('clipboard'.toJS).toDart

When retrieving HTML from the clipboard, it shows a button that says paste (from the browser) to confirm the paste:

image

It work perfectly without having to use the Clipboard events. @jezell Can you clarify or provide more details about the issue if I'm missing something?

Retrieving the HTML work on the web, even on Firefox, is the issue with identifying the method that's responsible for the paste on the web since it's separated from non-web platforms. Commenting everything related to the clipboard and paste, paste text, plain text paste in QuillRawEditor and QuillController and other classes only disable this feature on non-web platforms, plain text still works on the web.

When discussing the paste method, we’re not referring to the local clipboard managed by the editor or the controller. Instead, we focus on the logic that triggers the paste action, regardless of whether it reads from the local/system clipboard.