flutter-quill icon indicating copy to clipboard operation
flutter-quill copied to clipboard

Add "Paste as plain text" feature

Open Alspb opened this issue 1 year ago • 14 comments

Is there an existing issue for this?

Use case

It would be great to have "Paste as plain text" feature, as e.g. TextField on Android has. Sometimes format is not needed, like when text is copied from browser. Also, this should help avoid misunderstanding on when formatted or plain text is pasted, see #1772.

Proposal

Implement "Paste as plain text" feature and add it to the context menu for pasting. Maybe there should be an option on whether "Paste as plain text" should be included into that menu or not.

Alspb avatar Jun 23 '24 21:06 Alspb

It looks like to paste plain text one should disable the following code blocks from quill_controller.dart:

if (await _pasteHTML()) {
    updateEditor?.call();
    return true;
}
_applyPasteStyleAndEmbed(insertedText, index, containsEmbed);

But adding "Paste as plain text" to the context menu is not that straightforward, since the menu is implemented using EditableText.getEditableButtonItems.

Alspb avatar Jun 23 '24 21:06 Alspb

@ellet0 Do you have any suggestion?

singerdmx avatar Jun 26 '24 02:06 singerdmx

If the user paste using the paste button above the keyboard, it should alwats paste as text. This behavior is specific to Android and will apply to all apps. As for the paste as plain text, we could also add the option to always paste as plain text and disable rich text pasting feature.

Notice that if you don't use flutter_quill_extensions, it will be displayed by default.

As for paste as plain text, it's might not be common or known by users, I would suggest having this option only if rich text paste is available.

EchoEllet avatar Jun 26 '24 06:06 EchoEllet

Indeed, Android keyboards (though, probably no all) allow to paste as plain text, as it in fact stored in the clipboard. So, it's some kind of an option too: "Paste" button pastes rich text while the keyboard pastes the plain one. However, it doesn't help on other OS.

Notice that if you don't use flutter_quill_extensions, it will be displayed by default.

Not quite sure how to check if flutter_quill_extensions is used. Do you mean that pasting as rich text is only available if flutter_quill_extensions is used? I can double-check but looks like text copied from the editor is always pasted as rich (but not sure about pasting from browser).

As for paste as plain text, it's might not be common or known by users, I would suggest having this option only if rich text paste is available.

Totally agree. But there're some technical problems I see: adding "Paste as plain text" to the context menu on Android, dynamically identifying if "Paste as plain text" button should be in the toolbar, and finding an appropriate icon for "Paste as plain text" button. Though, maybe there's no real need in "Paste as plain text" in the toolbar...

Alspb avatar Jul 05 '24 06:07 Alspb

Not quite sure how to check if flutter_quill_extensions is used.

There are different ways, one of them is to check the type of ClipboardService static instance.

Do you mean that pasting as rich text is only available if flutter_quill_extensions is used? I can double-check but looks like text copied from the editor is always pasted as rich (but not sure about pasting from browser

Starting from 9.4.0, the usages of super_clipboard have been moved from flutter_quill to flutter_quill_extensions.

The rich text, gif, and image features are disabled by default. You will have to use the extensions package and call a function to override the default implementation.

The example already utilized the extensions package and called the FlutterQuillExtensions.useSuperClipboardPlugin.

EchoEllet avatar Jul 05 '24 06:07 EchoEllet

Thanks, I'm able to change clipboard plugins by adding/removing FlutterQuillExtensions.useSuperClipboardPlugin, ClipboardService instance in the code confirms it. However, for some reason I can't reproduce pasting formatted text copied from the browser, no matter which clipboard plugin I use. I mean that getHTML function inside _pasteHTML method always returns null, not sure why.

Nevertheless, if I copy some inline text from the editor (i.e., several words on the same line), the format is preserved (for example, bold words remain bold) after paste, even for the default clipboard plugin. In fact, it looks like clipboard is not used here since the copied text and it's format are stored in the editor itself, see clipboardSelection method. So, at least pasting from the editor is always rich. At the same time, if several paragraphs are copied, the format is not preserved after paste. Maybe there's a reason behind this behavior but looks like a bug.

By the way, "instance" is misspelled in the code, we should correct it in the same PR: ClipboardServiceProvider.instacne.

Alspb avatar Jul 07 '24 08:07 Alspb

However, for some reason I can't reproduce pasting formatted text copied from the browser, no matter which clipboard plugin I use. I mean that getHTML function inside _pasteHTML method always returns null, not sure why.

That's usually because of the browser restrictions on using the clipboard on the Web.

Take a look at Super Clipboard Accessing clipboard on Web

Web browsers impose some restrictions when reading from clipboard. If value in clipboard has been copied from another application, user needs to confirm clipboard access (usually in form of popover). Asynchronous clipboard API is unavailable by default on Firefox. To get around this limitation, super_clipboard provides a way to listen to a browser clipboard event, which is triggered when user presses the appropriate keyboard shortcut in browser window (or selects the option from menu).

Previously the Editor requested permission by default, then later it was disabled by default.

Nevertheless, if I copy some inline text from the editor (i.e., several words on the same line), the format is preserved (for example, bold words remain bold) after paste, even for the default clipboard plugin. In fact, it looks like clipboard is not used here since the copied text and it's format are stored in the editor itself

Yes, this was a feature before ClipboardService and super_clipboard integration. However, we might want to document this to be more specific. Developers might use flutter_quill_extensions for this feature even if they are only interested in it for the Editor itself.

By the way, "instance" is misspelled in the code, we should correct it in the same PR: ClipboardServiceProvider.instacne.

Luckily we haven't exported the ClipboardService or related classes yet, so we can correct and update them at any time, I knew we would make a breaking change after a short time after introducing it in 9.4.0 so I decided not to export them for know.

EchoEllet avatar Jul 07 '24 08:07 EchoEllet

By the way, "instance" is misspelled in the code, we should correct it in the same PR: ClipboardServiceProvider.instacne.

https://github.com/singerdmx/flutter-quill/blob/ce5eb86b10ffc0cbccd1074b24e6028e3b2ea84d/lib/src/services/clipboard/clipboard_service_provider.dart#L7-L19

It seems that static ClipboardService get instacne => _instance; is the only typo.

The private _instance is correct.

EchoEllet avatar Jul 07 '24 16:07 EchoEllet

Do I understand correctly that currently copy+paste is supposed have following features?

  1. Base editor version: no style is preserved, including when a text is copied from the editor itself.
  2. flutter_quill_extensions: style is preserved when text is copied from the editor itself, including embeds.
  3. flutter_quill_extensions + super_clipboard: style is preserved also when copying from web or markdown.

If so, it looks reasonable. Sure, as for me, the most ideal solution would be to preserve text style (but not embeds!) even without using flutter_quill_extensions. So that without flutter_quill_extensions the editor becomes simple but powerful rich text editor, which in particular "remembers" style when text is copied and pasted. However, not sure if it's easy to split styles and embeds in the code. For example, methods like _applyPasteStyleAndEmbed should be split into two, and so on. If it's hard to implement, the approach above looks like literally the only way.

Alspb avatar Jul 13 '24 15:07 Alspb

Base editor version: no style is preserved, including when a text is copied from the editor itself.

If you copy anything from the editor and paste it somewhere else in the document of the editor, it should paste it as it was before since it it will retrive it from the QuillController itself and not from the system Clipboard

flutter_quill_extensions: style is preserved when text is copied from the editor itself, including embeds.

The styles should be already preserved without the extensions package.

flutter_quill_extensions + super_clipboard: style is preserved also when copying from web or markdown.

super_clipboard is a dependency of flutter_quill_extensions, so you don't need to explicitly include it once you include flutter_quill_extensions and call FlutterQuillExtensions.useSuperClipboard()

You should be able to paste HTML and Markdown files. And HTML from other apps and websites.

If you're testing on the web, then it doesn't work and doesn't require super_clipboard, instead, a paste event should be triggered and read the HTML text from the event.

We haven't implemented this feature yet, though.

See PR #2001 and Issue #1998 for details.

EchoEllet avatar Jul 13 '24 16:07 EchoEllet

Thanks, it's much clearer now. Seems that "Paste as plain text" feature might only be useful when using flutter_quill_extensions + super_clipboard.

Alspb avatar Aug 22 '24 21:08 Alspb

flutter_quill_extensions already have super_clipboard as a dependency.

EchoEllet avatar Aug 25 '24 17:08 EchoEllet

Sure, I mean that super_clipboard shouldn't work without running FlutterQuillExtensions.useSuperClipboardPlugin().

Alspb avatar Aug 26 '24 21:08 Alspb

Seems like an android feature, will add it and provide a property that should be enabled and user can enable it on other platforms, by default will be for Android.

EchoEllet avatar Sep 22 '24 13:09 EchoEllet