ソースを参照

feat: handle HTMLElement

Vincent Chan 2 年 前
コミット
67fd06366e

+ 1 - 2
frontend/app_flowy/packages/flowy_editor/example/lib/plugin/image_node_widget.dart

@@ -90,8 +90,7 @@ class _ImageNodeWidgetState extends State<ImageNodeWidget> with Selectable {
 
   @override
   Position getPositionInOffset(Offset start) {
-    // TODO: implement getPositionInOffset
-    throw UnimplementedError();
+    return Position(path: node.path, offset: 0);
   }
 
   @override

+ 86 - 4
frontend/app_flowy/packages/flowy_editor/lib/infra/html_converter.dart

@@ -1,3 +1,5 @@
+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;
@@ -10,17 +12,97 @@ class HTMLConverter {
 
   List<Node> toNodes() {
     final result = <Node>[];
-    final delta = Delta();
 
     final bodyChildren = _document.body?.children ?? [];
     for (final child in bodyChildren) {
-      delta.insert(child.text);
+      _handleElement(result, child);
+    }
+
+    return result;
+  }
+
+  _handleElement(List<Node> nodes, html.Element element) {
+    if (element.localName == "h1") {
+      _handleHeadingElement(nodes, element, "h1");
+    } else if (element.localName == "h2") {
+      _handleHeadingElement(nodes, element, "h2");
+    } else if (element.localName == "h3") {
+      _handleHeadingElement(nodes, element, "h3");
+    } else if (element.localName == "ul") {
+      _handleUnorderedList(nodes, element);
+    } else if (element.localName == "li") {
+      _handleListElement(nodes, element);
+    } else if (element.localName == "p") {
+      _handleParagraph(nodes, element);
+    } else {
+      final delta = Delta();
+      delta.insert(element.text);
+      if (delta.operations.isNotEmpty) {
+        nodes.add(TextNode(type: "text", delta: delta));
+      }
     }
+  }
 
+  _handleParagraph(List<Node> nodes, html.Element element) {
+    for (final child in element.children) {
+      if (child.localName == "a") {
+        _handleAnchorLink(nodes, child);
+      }
+    }
+
+    final delta = Delta();
+    delta.insert(element.text);
     if (delta.operations.isNotEmpty) {
-      result.add(TextNode(type: "text", delta: delta));
+      nodes.add(TextNode(type: "text", delta: delta));
     }
+  }
 
-    return result;
+  _handleAnchorLink(List<Node> nodes, html.Element element) {
+    for (final child in element.children) {
+      if (child.localName == "img") {
+        _handleImage(nodes, child);
+        return;
+      }
+    }
+  }
+
+  _handleImage(List<Node> nodes, html.Element element) {
+    final src = element.attributes["src"];
+    final attributes = <String, dynamic>{};
+    if (src != null) {
+      attributes["image_src"] = src;
+    }
+    nodes.add(
+        Node(type: "image", attributes: attributes, children: LinkedList()));
+  }
+
+  _handleUnorderedList(List<Node> nodes, html.Element element) {
+    element.children.forEach((child) {
+      _handleListElement(nodes, child);
+    });
+  }
+
+  _handleHeadingElement(
+    List<Node> nodes,
+    html.Element element,
+    String headingStyle,
+  ) {
+    final delta = Delta();
+    delta.insert(element.text);
+    if (delta.operations.isNotEmpty) {
+      nodes.add(TextNode(
+          type: "text",
+          attributes: {"subtype": "heading", "heading": headingStyle},
+          delta: delta));
+    }
+  }
+
+  _handleListElement(List<Node> nodes, html.Element element) {
+    final delta = Delta();
+    delta.insert(element.text);
+    if (delta.operations.isNotEmpty) {
+      nodes.add(TextNode(
+          type: "text", attributes: {"subtype": "bullet-list"}, delta: delta));
+    }
   }
 }