feat: open html decoder for custom parser (#1145)

This commit is contained in:
Richard Shiue 2025-10-22 13:45:26 +08:00 • committed by GitHub
commit 1ec9bb7f29
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 37 additions and 4 deletions

View file

@ -9,9 +9,16 @@ import 'package:appflowy_editor/src/plugins/html/html_document_encoder.dart';
import 'encoder/parser/html_parser.dart';
export 'html_document_decoder.dart' show ElementParser;
/// Converts a html to [Document].
Document htmlToDocument(String html) {
return const AppFlowyEditorHTMLCodec().decode(html);
Document htmlToDocument(
String html, {
Map<String, ElementParser> customDecoders = const {},
}) {
return AppFlowyEditorHTMLCodec(
customDecoders: customDecoders,
).decode(html);
}
/// Converts a [Document] to html.
@ -38,12 +45,16 @@ String documentToHTML(
class AppFlowyEditorHTMLCodec extends Codec<Document, String> {
const AppFlowyEditorHTMLCodec({
this.encodeParsers = const [],
this.customDecoders = const {},
});
final List<HTMLNodeParser> encodeParsers;
final Map<String, ElementParser> customDecoders;
@override
Converter<String, Document> get decoder => DocumentHTMLDecoder();
Converter<String, Document> get decoder => DocumentHTMLDecoder(
customDecoders: customDecoders,
);
@override
Converter<Document, String> get encoder => DocumentHTMLEncoder(

View file

@ -5,9 +5,20 @@ import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' show parse;
class DocumentHTMLDecoder extends Converter<String, Document> {
DocumentHTMLDecoder();
typedef ElementParser = Iterable<Node> Function(
dom.Element element,
(Delta, Iterable<Node>) Function(
dom.Element element, {
String? type,
}) parseDeltaElement,
);
class DocumentHTMLDecoder extends Converter<String, Document> {
DocumentHTMLDecoder({
this.customDecoders = const {},
});
final Map<String, ElementParser> customDecoders;
// Set to true to enable parsing color from HTML
static bool enableColorParse = true;
@ -67,6 +78,13 @@ class DocumentHTMLDecoder extends Converter<String, Document> {
type: type ?? ParagraphBlockKeys.type,
),
);
} else if (customDecoders.containsKey(localName)) {
if (delta.isNotEmpty) {
nodes.add(paragraphNode(delta: delta));
}
nodes.addAll(
customDecoders[localName]!(domNode, _parseDeltaElement),
);
}
} else if (domNode is dom.Text) {
// skip the empty text node
@ -395,6 +413,10 @@ class DocumentHTMLDecoder extends Converter<String, Document> {
type: ParagraphBlockKeys.type,
),
);
} else if (customDecoders.containsKey(child.localName)) {
nodes.addAll(
customDecoders[child.localName]!(child, _parseDeltaElement),
);
} else {
final attributes = _parserFormattingElementAttributes(child);
delta.insert(