feat: paste html rich text inside text

This commit is contained in:
Vincent Chan
2022-08-03 15:30:00 +08:00
parent aba84a3ccd
commit e73465170a
2 changed files with 58 additions and 20 deletions

View File

@ -15,12 +15,13 @@ class HTMLConverter {
final result = <Node>[]; final result = <Node>[];
final delta = Delta(); final delta = Delta();
for (final child in _document.body?.nodes.toList() ?? <html.Node>[]) { final childNodes = _document.body?.nodes.toList() ?? <html.Node>[];
for (final child in childNodes) {
if (child is html.Element) { if (child is html.Element) {
if (child.localName == "span") { if (child.localName == "a" ||
delta.insert(child.text); child.localName == "span" ||
} else if (child.localName == "strong") { child.localName == "strong") {
delta.insert(child.text, {"bold": true}); _handleRichTextElement(delta, child);
} else { } else {
_handleElement(result, child); _handleElement(result, child);
} }
@ -59,6 +60,25 @@ class HTMLConverter {
} }
_handleParagraph(List<Node> nodes, html.Element element) { _handleParagraph(List<Node> nodes, html.Element element) {
_handleRichText(nodes, element);
}
_handleRichTextElement(Delta delta, html.Element element) {
if (element.localName == "span") {
delta.insert(element.text);
} else if (element.localName == "a") {
final hyperLink = element.attributes["href"];
Map<String, dynamic>? attributes;
if (hyperLink != null) {
attributes = {"href": hyperLink};
}
delta.insert(element.text, attributes);
} else if (element.localName == "strong") {
delta.insert(element.text, {"bold": true});
}
}
_handleRichText(List<Node> nodes, html.Element element) {
final image = element.querySelector("img"); final image = element.querySelector("img");
if (image != null) { if (image != null) {
_handleImage(nodes, image); _handleImage(nodes, image);
@ -69,13 +89,10 @@ class HTMLConverter {
for (final child in element.nodes.toList()) { for (final child in element.nodes.toList()) {
if (child is html.Element) { if (child is html.Element) {
if (child.localName == "a") { if (child.localName == "a" ||
final hyperLink = child.attributes["href"]; child.localName == "span" ||
Map<String, dynamic>? attributes; child.localName == "strong") {
if (hyperLink != null) { _handleRichTextElement(delta, element);
attributes = {"href": hyperLink};
}
delta.insert(child.text, attributes);
} else { } else {
delta.insert(child.text); delta.insert(child.text);
} }
@ -122,11 +139,11 @@ class HTMLConverter {
} }
_handleListElement(List<Node> nodes, html.Element element) { _handleListElement(List<Node> nodes, html.Element element) {
final delta = Delta(); final childNodes = element.nodes.toList();
delta.insert(element.text); for (final child in childNodes) {
if (delta.operations.isNotEmpty) { if (child is html.Element) {
nodes.add(TextNode( _handleRichText(nodes, child);
type: "text", attributes: {"subtype": "bullet-list"}, delta: delta)); }
} }
} }
} }

View File

@ -10,8 +10,6 @@ _handleCopy() async {
} }
_pasteHTML(EditorState editorState, String html) { _pasteHTML(EditorState editorState, String html) {
final converter = HTMLConverter(html);
final nodes = converter.toNodes();
final selection = editorState.cursorSelection; final selection = editorState.cursorSelection;
if (selection == null) { if (selection == null) {
return; return;
@ -21,9 +19,31 @@ _pasteHTML(EditorState editorState, String html) {
if (path.isEmpty) { if (path.isEmpty) {
return; return;
} }
path[path.length - 1]++;
final converter = HTMLConverter(html);
final nodes = converter.toNodes();
if (nodes.isEmpty) {
return;
} else if (nodes.length == 1) {
final firstNode = nodes[0];
final nodeAtPath = editorState.document.nodeAtPath(path)!;
final tb = TransactionBuilder(editorState);
final startOffset = selection.start.offset;
if (nodeAtPath.type == "text" && firstNode.type == "text") {
final textNodeAtPath = nodeAtPath as TextNode;
final firstTextNode = firstNode as TextNode;
tb.textEdit(textNodeAtPath,
() => Delta().retain(startOffset).concat(firstTextNode.delta));
tb.setAfterSelection(Selection.collapsed(Position(
path: path, offset: startOffset + firstTextNode.delta.length)));
}
tb.commit();
return;
}
final tb = TransactionBuilder(editorState); final tb = TransactionBuilder(editorState);
path[path.length - 1]++;
tb.insertNodes(path, nodes); tb.insertNodes(path, nodes);
tb.commit(); tb.commit();
} }
@ -98,6 +118,7 @@ _handlePastePlainText(EditorState editorState, String plainText) {
tb.insertNodes(path, nodes); tb.insertNodes(path, nodes);
tb.commit(); tb.commit();
// fixme: don't set the cursor manually
editorState.updateCursorSelection(Selection.collapsed( editorState.updateCursorSelection(Selection.collapsed(
Position(path: nodes.last.path, offset: lines.last.length))); Position(path: nodes.last.path, offset: lines.last.length)));
} }