Browse Source

feat: parse html

Vincent Chan 2 years ago
parent
commit
9ceced4648

+ 4 - 0
frontend/app_flowy/packages/flowy_editor/example/linux/flutter/generated_plugin_registrant.cc

@@ -6,9 +6,13 @@
 
 #include "generated_plugin_registrant.h"
 
+#include <rich_clipboard_linux/rich_clipboard_plugin.h>
 #include <url_launcher_linux/url_launcher_plugin.h>
 
 void fl_register_plugins(FlPluginRegistry* registry) {
+  g_autoptr(FlPluginRegistrar) rich_clipboard_linux_registrar =
+      fl_plugin_registry_get_registrar_for_plugin(registry, "RichClipboardPlugin");
+  rich_clipboard_plugin_register_with_registrar(rich_clipboard_linux_registrar);
   g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
       fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
   url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

+ 1 - 0
frontend/app_flowy/packages/flowy_editor/example/linux/flutter/generated_plugins.cmake

@@ -3,6 +3,7 @@
 #
 
 list(APPEND FLUTTER_PLUGIN_LIST
+  rich_clipboard_linux
   url_launcher_linux
 )
 

+ 2 - 0
frontend/app_flowy/packages/flowy_editor/example/macos/Flutter/GeneratedPluginRegistrant.swift

@@ -5,8 +5,10 @@
 import FlutterMacOS
 import Foundation
 
+import rich_clipboard_macos
 import url_launcher_macos
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+  RichClipboardPlugin.register(with: registry.registrar(forPlugin: "RichClipboardPlugin"))
   UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
 }

+ 6 - 0
frontend/app_flowy/packages/flowy_editor/example/macos/Podfile.lock

@@ -1,20 +1,26 @@
 PODS:
   - FlutterMacOS (1.0.0)
+  - rich_clipboard_macos (0.0.1):
+    - FlutterMacOS
   - url_launcher_macos (0.0.1):
     - FlutterMacOS
 
 DEPENDENCIES:
   - FlutterMacOS (from `Flutter/ephemeral`)
+  - rich_clipboard_macos (from `Flutter/ephemeral/.symlinks/plugins/rich_clipboard_macos/macos`)
   - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
 
 EXTERNAL SOURCES:
   FlutterMacOS:
     :path: Flutter/ephemeral
+  rich_clipboard_macos:
+    :path: Flutter/ephemeral/.symlinks/plugins/rich_clipboard_macos/macos
   url_launcher_macos:
     :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
 
 SPEC CHECKSUMS:
   FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
+  rich_clipboard_macos: 43364b66b9dc69d203eb8dd6d758e2d12e02723c
   url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3
 
 PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c

+ 85 - 1
frontend/app_flowy/packages/flowy_editor/example/pubspec.lock

@@ -43,6 +43,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.16.0"
+  csslib:
+    dependency: transitive
+    description:
+      name: csslib
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.17.2"
   cupertino_icons:
     dependency: "direct main"
     description:
@@ -57,6 +64,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.3.0"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.2.1"
   flowy_editor:
     dependency: "direct main"
     description:
@@ -93,6 +107,13 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  html:
+    dependency: transitive
+    description:
+      name: html
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.15.0"
   js:
     dependency: transitive
     description:
@@ -177,6 +198,62 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "6.0.3"
+  rich_clipboard:
+    dependency: transitive
+    description:
+      name: rich_clipboard
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.0"
+  rich_clipboard_android:
+    dependency: transitive
+    description:
+      name: rich_clipboard_android
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.0"
+  rich_clipboard_ios:
+    dependency: transitive
+    description:
+      name: rich_clipboard_ios
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.0"
+  rich_clipboard_linux:
+    dependency: transitive
+    description:
+      name: rich_clipboard_linux
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.0"
+  rich_clipboard_macos:
+    dependency: transitive
+    description:
+      name: rich_clipboard_macos
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.1"
+  rich_clipboard_platform_interface:
+    dependency: transitive
+    description:
+      name: rich_clipboard_platform_interface
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.0"
+  rich_clipboard_web:
+    dependency: transitive
+    description:
+      name: rich_clipboard_web
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.0"
+  rich_clipboard_windows:
+    dependency: transitive
+    description:
+      name: rich_clipboard_windows
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.0"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -287,6 +364,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.1.2"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.6.1"
   xml:
     dependency: transitive
     description:
@@ -296,4 +380,4 @@ packages:
     version: "6.1.0"
 sdks:
   dart: ">=2.17.0 <3.0.0"
-  flutter: ">=2.11.0-0.1.pre"
+  flutter: ">=3.0.0"

+ 29 - 0
frontend/app_flowy/packages/flowy_editor/lib/infra/html_converter.dart

@@ -0,0 +1,29 @@
+import 'dart:collection';
+
+import 'package:flowy_editor/document/node.dart';
+import 'package:flowy_editor/document/text_delta.dart';
+import 'package:html/parser.dart' show parse;
+import 'package:html/dom.dart' as html;
+
+class HTMLConverter {
+  final html.Document _document;
+
+  HTMLConverter(String htmlString) : _document = parse(htmlString);
+
+  List<Node> toNodes() {
+    final result = <Node>[];
+    final delta = Delta();
+
+    final bodyChildren = _document.body?.children ?? [];
+    for (final child in bodyChildren) {
+      delta.insert(child.text);
+    }
+
+    if (delta.operations.isNotEmpty) {
+      result.add(TextNode(
+          type: "text", children: LinkedList(), attributes: {}, delta: delta));
+    }
+
+    return result;
+  }
+}

+ 38 - 3
frontend/app_flowy/packages/flowy_editor/lib/service/internal_key_event_handlers/copy_paste_handler.dart

@@ -1,18 +1,53 @@
+import 'package:flowy_editor/flowy_editor.dart';
 import 'package:flowy_editor/service/keyboard_service.dart';
+import 'package:flowy_editor/infra/html_converter.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
+import 'package:rich_clipboard/rich_clipboard.dart';
+
+_handleCopy() async {
+  debugPrint('copy');
+}
+
+_pasteHTML(EditorState editorState, String html) {
+  final converter = HTMLConverter(html);
+  final nodes = converter.toNodes();
+  final selection = editorState.cursorSelection;
+  if (selection == null) {
+    return;
+  }
+
+  final tb = TransactionBuilder(editorState);
+  for (final node in nodes) {
+    tb.insertNode(selection.end.path, node);
+  }
+  tb.commit();
+}
+
+_handlePaste(EditorState editorState) async {
+  final data = await RichClipboard.getData();
+  if (data.html != null) {
+    _pasteHTML(editorState, data.html!);
+    return;
+  }
+  debugPrint('paste ${data.text ?? ''}');
+}
+
+_handleCut() {
+  debugPrint('cut');
+}
 
 FlowyKeyEventHandler copyPasteKeysHandler = (editorState, event) {
   if (event.isMetaPressed && event.logicalKey == LogicalKeyboardKey.keyC) {
-    debugPrint("copy");
+    _handleCopy();
     return KeyEventResult.handled;
   }
   if (event.isMetaPressed && event.logicalKey == LogicalKeyboardKey.keyV) {
-    debugPrint("paste");
+    _handlePaste(editorState);
     return KeyEventResult.handled;
   }
   if (event.isMetaPressed && event.logicalKey == LogicalKeyboardKey.keyX) {
-    debugPrint("cut");
+    _handleCut();
     return KeyEventResult.handled;
   }
   return KeyEventResult.ignored;

+ 2 - 0
frontend/app_flowy/packages/flowy_editor/pubspec.yaml

@@ -11,6 +11,8 @@ dependencies:
   flutter:
     sdk: flutter
 
+  rich_clipboard: ^1.0.0
+  html: ^0.15.0
   flutter_svg: ^1.1.1+1
   provider: ^6.0.3