fix: unable to paste texts contains section or font tag (#3379)

This commit is contained in:
Lucas.Xu 2023-09-12 15:53:39 +08:00 committed by GitHub
parent 043c68a333
commit 5f4e3ecc76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 70 additions and 24 deletions

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,6 @@ import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -243,7 +242,7 @@ class ColorOptionAction extends PopoverActionCell {
} }
final bgColor = final bgColor =
node.attributes[blockComponentBackgroundColor] as String?; node.attributes[blockComponentBackgroundColor] as String?;
final selectedColor = bgColor?.toColor(); final selectedColor = bgColor?.tryToColor();
// get default background color from themeExtension // get default background color from themeExtension
final defaultColor = AFThemeExtension.of(context).calloutBGColor; final defaultColor = AFThemeExtension.of(context).calloutBGColor;
final colors = [ final colors = [

View File

@ -139,7 +139,7 @@ class _CalloutBlockComponentWidgetState
Color get backgroundColor { Color get backgroundColor {
final colorString = final colorString =
node.attributes[CalloutBlockKeys.backgroundColor] as String; node.attributes[CalloutBlockKeys.backgroundColor] as String;
return colorString.toColor() ?? Colors.transparent; return colorString.tryToColor() ?? Colors.transparent;
} }
// get the emoji of the note block from the node's attributes or default to '📌' // get the emoji of the note block from the node's attributes or default to '📌'

View File

@ -43,16 +43,32 @@ CommandShortcutEventHandler _pasteCommandHandler = (editorState) {
// 3. image // 3. image
// 4. plain text // 4. plain text
// try to paste the content in order, if any of them is failed, then try the next one
if (inAppJson != null && inAppJson.isNotEmpty) { if (inAppJson != null && inAppJson.isNotEmpty) {
await editorState.deleteSelectionIfNeeded(); await editorState.deleteSelectionIfNeeded();
await editorState.pasteInAppJson(inAppJson); final result = await editorState.pasteInAppJson(inAppJson);
} else if (html != null && html.isNotEmpty) { if (result) {
return;
}
}
if (html != null && html.isNotEmpty) {
await editorState.deleteSelectionIfNeeded(); await editorState.deleteSelectionIfNeeded();
await editorState.pasteHtml(html); final result = await editorState.pasteHtml(html);
} else if (image != null && image.$2?.isNotEmpty == true) { if (result) {
return;
}
}
if (image != null && image.$2?.isNotEmpty == true) {
await editorState.deleteSelectionIfNeeded(); await editorState.deleteSelectionIfNeeded();
await editorState.pasteImage(image.$1, image.$2!); final result = await editorState.pasteImage(image.$1, image.$2!);
} else if (plainText != null && plainText.isNotEmpty) { if (result) {
return;
}
}
if (plainText != null && plainText.isNotEmpty) {
await editorState.pastePlainText(plainText); await editorState.pastePlainText(plainText);
} }
}(); }();

View File

@ -2,7 +2,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_p
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
extension PasteFromHtml on EditorState { extension PasteFromHtml on EditorState {
Future<void> pasteHtml(String html) async { Future<bool> pasteHtml(String html) async {
final nodes = htmlToDocument(html).root.children.toList(); final nodes = htmlToDocument(html).root.children.toList();
// remove the front and back empty line // remove the front and back empty line
while (nodes.isNotEmpty && nodes.first.delta?.isEmpty == true) { while (nodes.isNotEmpty && nodes.first.delta?.isEmpty == true) {
@ -11,13 +11,15 @@ extension PasteFromHtml on EditorState {
while (nodes.isNotEmpty && nodes.last.delta?.isEmpty == true) { while (nodes.isNotEmpty && nodes.last.delta?.isEmpty == true) {
nodes.removeLast(); nodes.removeLast();
} }
// if there's no nodes being converted successfully, return false
if (nodes.isEmpty) { if (nodes.isEmpty) {
return; return false;
} }
if (nodes.length == 1) { if (nodes.length == 1) {
await pasteSingleLineNode(nodes.first); await pasteSingleLineNode(nodes.first);
} else { } else {
await pasteMultiLineNodes(nodes.toList()); await pasteMultiLineNodes(nodes.toList());
} }
return true;
} }
} }

View File

@ -15,9 +15,9 @@ extension PasteFromImage on EditorState {
'gif', 'gif',
]; ];
Future<void> pasteImage(String format, Uint8List imageBytes) async { Future<bool> pasteImage(String format, Uint8List imageBytes) async {
if (!supportedImageFormats.contains(format)) { if (!supportedImageFormats.contains(format)) {
return; return false;
} }
final path = await getIt<ApplicationDataStorage>().getPath(); final path = await getIt<ApplicationDataStorage>().getPath();
@ -37,8 +37,10 @@ extension PasteFromImage on EditorState {
); );
await File(copyToPath).writeAsBytes(imageBytes); await File(copyToPath).writeAsBytes(imageBytes);
await insertImageNode(copyToPath); await insertImageNode(copyToPath);
return true;
} catch (e) { } catch (e) {
Log.error('cannot copy image file', e); Log.error('cannot copy image file', e);
} }
return false;
} }
} }

View File

@ -5,21 +5,23 @@ import 'package:appflowy_backend/log.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log; import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
extension PasteFromInAppJson on EditorState { extension PasteFromInAppJson on EditorState {
Future<void> pasteInAppJson(String inAppJson) async { Future<bool> pasteInAppJson(String inAppJson) async {
try { try {
final nodes = Document.fromJson(jsonDecode(inAppJson)).root.children; final nodes = Document.fromJson(jsonDecode(inAppJson)).root.children;
if (nodes.isEmpty) { if (nodes.isEmpty) {
return; return false;
} }
if (nodes.length == 1) { if (nodes.length == 1) {
await pasteSingleLineNode(nodes.first); await pasteSingleLineNode(nodes.first);
} else { } else {
await pasteMultiLineNodes(nodes.toList()); await pasteMultiLineNodes(nodes.toList());
} }
return true;
} catch (e) { } catch (e) {
Log.error( Log.error(
'Failed to paste in app json: $inAppJson, error: $e', 'Failed to paste in app json: $inAppJson, error: $e',
); );
} }
return false;
} }
} }

View File

@ -6,7 +6,6 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/button.dart';
@ -536,7 +535,7 @@ class ColorItem extends StatelessWidget {
dimension: 25, dimension: 25,
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: option.colorHex.toColor(), color: option.colorHex.tryToColor(),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: isChecked child: isChecked
@ -548,7 +547,7 @@ class ColorItem extends StatelessWidget {
color: Theme.of(context).cardColor, color: Theme.of(context).cardColor,
width: 3.0, width: 3.0,
), ),
color: option.colorHex.toColor(), color: option.colorHex.tryToColor(),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
), ),

View File

@ -367,7 +367,7 @@ class DocumentCoverState extends State<DocumentCover> {
fit: BoxFit.cover, fit: BoxFit.cover,
); );
case CoverType.color: case CoverType.color:
final color = widget.coverDetails?.toColor() ?? Colors.white; final color = widget.coverDetails?.tryToColor() ?? Colors.white;
return Container(color: color); return Container(color: color);
case CoverType.none: case CoverType.none:
return const SizedBox.shrink(); return const SizedBox.shrink();

View File

@ -84,7 +84,7 @@ class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
if (colorString == null) { if (colorString == null) {
return Colors.transparent; return Colors.transparent;
} }
return colorString.toColor() ?? Colors.transparent; return colorString.tryToColor() ?? Colors.transparent;
} }
late EditorState editorState = context.read<EditorState>(); late EditorState editorState = context.read<EditorState>();

View File

@ -112,7 +112,7 @@ class TableColorOptionAction extends PopoverActionCell {
? TableCellBlockKeys.colBackgroundColor ? TableCellBlockKeys.colBackgroundColor
: TableCellBlockKeys.rowBackgroundColor; : TableCellBlockKeys.rowBackgroundColor;
final bgColor = cell?.attributes[key] as String?; final bgColor = cell?.attributes[key] as String?;
final selectedColor = bgColor?.toColor(); final selectedColor = bgColor?.tryToColor();
// get default background color from themeExtension // get default background color from themeExtension
final defaultColor = AFThemeExtension.of(context).tableCellBGColor; final defaultColor = AFThemeExtension.of(context).tableCellBGColor;
final colors = [ final colors = [

View File

@ -54,8 +54,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "4a92c88" ref: "6d68f90"
resolved-ref: "4a92c88b6611af95909e4618be3970cc20f6d930" resolved-ref: "6d68f9003fa023d215dc5f20e8900f985c2cdaa1"
url: "https://github.com/AppFlowy-IO/appflowy-editor.git" url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git source: git
version: "1.3.0" version: "1.3.0"

View File

@ -48,7 +48,7 @@ dependencies:
appflowy_editor: appflowy_editor:
git: git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: 4a92c88 ref: 6d68f90
appflowy_popover: appflowy_popover:
path: packages/appflowy_popover path: packages/appflowy_popover