mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
refactor: html text into class
This commit is contained in:
parent
e34ff50923
commit
a3ffbe2f00
@ -1,4 +1,5 @@
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flowy_editor/src/document/attributes.dart';
|
import 'package:flowy_editor/src/document/attributes.dart';
|
||||||
import 'package:flowy_editor/src/document/node.dart';
|
import 'package:flowy_editor/src/document/node.dart';
|
||||||
@ -8,23 +9,35 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:html/parser.dart' show parse;
|
import 'package:html/parser.dart' show parse;
|
||||||
import 'package:html/dom.dart' as html;
|
import 'package:html/dom.dart' as html;
|
||||||
|
|
||||||
const String tagH1 = "h1";
|
class HTMLTag {
|
||||||
const String tagH2 = "h2";
|
static const h1 = "h1";
|
||||||
const String tagH3 = "h3";
|
static const h2 = "h2";
|
||||||
const String tagOrderedList = "ol";
|
static const h3 = "h3";
|
||||||
const String tagUnorderedList = "ul";
|
static const orderedList = "ol";
|
||||||
const String tagList = "li";
|
static const unorderedList = "ul";
|
||||||
const String tagParagraph = "p";
|
static const list = "li";
|
||||||
const String tagImage = "img";
|
static const paragraph = "p";
|
||||||
const String tagAnchor = "a";
|
static const image = "img";
|
||||||
const String tagItalic = "i";
|
static const anchor = "a";
|
||||||
const String tagBold = "b";
|
static const italic = "i";
|
||||||
const String tagUnderline = "u";
|
static const bold = "b";
|
||||||
const String tagDel = "del";
|
static const underline = "u";
|
||||||
const String tagStrong = "strong";
|
static const del = "del";
|
||||||
const String tagSpan = "span";
|
static const strong = "strong";
|
||||||
const String tagCode = "code";
|
static const span = "span";
|
||||||
const String tagBlockQuote = "blockquote";
|
static const code = "code";
|
||||||
|
static const blockQuote = "blockquote";
|
||||||
|
static const div = "div";
|
||||||
|
|
||||||
|
static bool isTopLevel(String tag) {
|
||||||
|
return tag == h1 ||
|
||||||
|
tag == h2 ||
|
||||||
|
tag == h3 ||
|
||||||
|
tag == paragraph ||
|
||||||
|
tag == div ||
|
||||||
|
tag == blockQuote;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension on Color {
|
extension on Color {
|
||||||
String toRgbaString() {
|
String toRgbaString() {
|
||||||
@ -55,15 +68,15 @@ class HTMLToNodesConverter {
|
|||||||
final result = <Node>[];
|
final result = <Node>[];
|
||||||
for (final child in childNodes) {
|
for (final child in childNodes) {
|
||||||
if (child is html.Element) {
|
if (child is html.Element) {
|
||||||
if (child.localName == tagAnchor ||
|
if (child.localName == HTMLTag.anchor ||
|
||||||
child.localName == tagSpan ||
|
child.localName == HTMLTag.span ||
|
||||||
child.localName == tagCode ||
|
child.localName == HTMLTag.code ||
|
||||||
child.localName == tagStrong ||
|
child.localName == HTMLTag.strong ||
|
||||||
child.localName == tagUnderline ||
|
child.localName == HTMLTag.underline ||
|
||||||
child.localName == tagItalic ||
|
child.localName == HTMLTag.italic ||
|
||||||
child.localName == tagDel) {
|
child.localName == HTMLTag.del) {
|
||||||
_handleRichTextElement(delta, child);
|
_handleRichTextElement(delta, child);
|
||||||
} else if (child.localName == tagBold) {
|
} else if (child.localName == HTMLTag.bold) {
|
||||||
// Google docs wraps the the content inside the `<b></b>` tag.
|
// Google docs wraps the the content inside the `<b></b>` tag.
|
||||||
// It's strange
|
// It's strange
|
||||||
if (!_inParagraph) {
|
if (!_inParagraph) {
|
||||||
@ -71,7 +84,7 @@ class HTMLToNodesConverter {
|
|||||||
} else {
|
} else {
|
||||||
result.add(_handleRichText(child));
|
result.add(_handleRichText(child));
|
||||||
}
|
}
|
||||||
} else if (child.localName == tagBlockQuote) {
|
} else if (child.localName == HTMLTag.blockQuote) {
|
||||||
result.addAll(_handleBlockQuote(child));
|
result.addAll(_handleBlockQuote(child));
|
||||||
} else {
|
} else {
|
||||||
result.addAll(_handleElement(child));
|
result.addAll(_handleElement(child));
|
||||||
@ -105,19 +118,19 @@ class HTMLToNodesConverter {
|
|||||||
|
|
||||||
List<Node> _handleElement(html.Element element,
|
List<Node> _handleElement(html.Element element,
|
||||||
[Map<String, dynamic>? attributes]) {
|
[Map<String, dynamic>? attributes]) {
|
||||||
if (element.localName == tagH1) {
|
if (element.localName == HTMLTag.h1) {
|
||||||
return [_handleHeadingElement(element, tagH1)];
|
return [_handleHeadingElement(element, HTMLTag.h1)];
|
||||||
} else if (element.localName == tagH2) {
|
} else if (element.localName == HTMLTag.h2) {
|
||||||
return [_handleHeadingElement(element, tagH2)];
|
return [_handleHeadingElement(element, HTMLTag.h2)];
|
||||||
} else if (element.localName == tagH3) {
|
} else if (element.localName == HTMLTag.h3) {
|
||||||
return [_handleHeadingElement(element, tagH3)];
|
return [_handleHeadingElement(element, HTMLTag.h3)];
|
||||||
} else if (element.localName == tagUnorderedList) {
|
} else if (element.localName == HTMLTag.unorderedList) {
|
||||||
return _handleUnorderedList(element);
|
return _handleUnorderedList(element);
|
||||||
} else if (element.localName == tagOrderedList) {
|
} else if (element.localName == HTMLTag.orderedList) {
|
||||||
return _handleOrderedList(element);
|
return _handleOrderedList(element);
|
||||||
} else if (element.localName == tagList) {
|
} else if (element.localName == HTMLTag.list) {
|
||||||
return _handleListElement(element);
|
return _handleListElement(element);
|
||||||
} else if (element.localName == tagParagraph) {
|
} else if (element.localName == HTMLTag.paragraph) {
|
||||||
return [_handleParagraph(element, attributes)];
|
return [_handleParagraph(element, attributes)];
|
||||||
} else {
|
} else {
|
||||||
final delta = Delta();
|
final delta = Delta();
|
||||||
@ -236,23 +249,24 @@ class HTMLToNodesConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_handleRichTextElement(Delta delta, html.Element element) {
|
_handleRichTextElement(Delta delta, html.Element element) {
|
||||||
if (element.localName == tagSpan) {
|
if (element.localName == HTMLTag.span) {
|
||||||
delta.insert(element.text,
|
delta.insert(element.text,
|
||||||
_getDeltaAttributesFromHtmlAttributes(element.attributes));
|
_getDeltaAttributesFromHtmlAttributes(element.attributes));
|
||||||
} else if (element.localName == tagAnchor) {
|
} else if (element.localName == HTMLTag.anchor) {
|
||||||
final hyperLink = element.attributes["href"];
|
final hyperLink = element.attributes["href"];
|
||||||
Map<String, dynamic>? attributes;
|
Map<String, dynamic>? attributes;
|
||||||
if (hyperLink != null) {
|
if (hyperLink != null) {
|
||||||
attributes = {"href": hyperLink};
|
attributes = {"href": hyperLink};
|
||||||
}
|
}
|
||||||
delta.insert(element.text, attributes);
|
delta.insert(element.text, attributes);
|
||||||
} else if (element.localName == tagStrong || element.localName == tagBold) {
|
} else if (element.localName == HTMLTag.strong ||
|
||||||
|
element.localName == HTMLTag.bold) {
|
||||||
delta.insert(element.text, {StyleKey.bold: true});
|
delta.insert(element.text, {StyleKey.bold: true});
|
||||||
} else if (element.localName == tagUnderline) {
|
} else if (element.localName == HTMLTag.underline) {
|
||||||
delta.insert(element.text, {StyleKey.underline: true});
|
delta.insert(element.text, {StyleKey.underline: true});
|
||||||
} else if (element.localName == tagItalic) {
|
} else if (element.localName == HTMLTag.italic) {
|
||||||
delta.insert(element.text, {StyleKey.italic: true});
|
delta.insert(element.text, {StyleKey.italic: true});
|
||||||
} else if (element.localName == tagDel) {
|
} else if (element.localName == HTMLTag.del) {
|
||||||
delta.insert(element.text, {StyleKey.strikethrough: true});
|
delta.insert(element.text, {StyleKey.strikethrough: true});
|
||||||
} else {
|
} else {
|
||||||
delta.insert(element.text);
|
delta.insert(element.text);
|
||||||
@ -265,7 +279,7 @@ class HTMLToNodesConverter {
|
|||||||
/// A container contains a <img /> will be regarded as a image block
|
/// A container contains a <img /> will be regarded as a image block
|
||||||
Node _handleRichText(html.Element element,
|
Node _handleRichText(html.Element element,
|
||||||
[Map<String, dynamic>? attributes]) {
|
[Map<String, dynamic>? attributes]) {
|
||||||
final image = element.querySelector(tagImage);
|
final image = element.querySelector(HTMLTag.image);
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
final imageNode = _handleImage(image);
|
final imageNode = _handleImage(image);
|
||||||
return imageNode;
|
return imageNode;
|
||||||
@ -419,10 +433,10 @@ class NodesToHTMLConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_addElement(TextNode textNode, html.Element element) {
|
_addElement(TextNode textNode, html.Element element) {
|
||||||
if (element.localName == tagList) {
|
if (element.localName == HTMLTag.list) {
|
||||||
final isNumbered = textNode.attributes["subtype"] == StyleKey.numberList;
|
final isNumbered = textNode.attributes["subtype"] == StyleKey.numberList;
|
||||||
_stashListContainer ??=
|
_stashListContainer ??= html.Element.tag(
|
||||||
html.Element.tag(isNumbered ? tagOrderedList : tagUnorderedList);
|
isNumbered ? HTMLTag.orderedList : HTMLTag.unorderedList);
|
||||||
_stashListContainer?.append(element);
|
_stashListContainer?.append(element);
|
||||||
} else {
|
} else {
|
||||||
if (_stashListContainer != null) {
|
if (_stashListContainer != null) {
|
||||||
@ -524,10 +538,10 @@ class NodesToHTMLConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final childNodes = <html.Node>[];
|
final childNodes = <html.Node>[];
|
||||||
String tagName = tagParagraph;
|
String tagName = HTMLTag.paragraph;
|
||||||
|
|
||||||
if (subType == StyleKey.bulletedList || subType == StyleKey.numberList) {
|
if (subType == StyleKey.bulletedList || subType == StyleKey.numberList) {
|
||||||
tagName = tagList;
|
tagName = HTMLTag.list;
|
||||||
} else if (subType == StyleKey.checkbox) {
|
} else if (subType == StyleKey.checkbox) {
|
||||||
final node = html.Element.html('<input type="checkbox" />');
|
final node = html.Element.html('<input type="checkbox" />');
|
||||||
if (checked != null && checked) {
|
if (checked != null && checked) {
|
||||||
@ -536,14 +550,14 @@ class NodesToHTMLConverter {
|
|||||||
childNodes.add(node);
|
childNodes.add(node);
|
||||||
} else if (subType == StyleKey.heading) {
|
} else if (subType == StyleKey.heading) {
|
||||||
if (heading == StyleKey.h1) {
|
if (heading == StyleKey.h1) {
|
||||||
tagName = tagH1;
|
tagName = HTMLTag.h1;
|
||||||
} else if (heading == StyleKey.h2) {
|
} else if (heading == StyleKey.h2) {
|
||||||
tagName = tagH2;
|
tagName = HTMLTag.h2;
|
||||||
} else if (heading == StyleKey.h3) {
|
} else if (heading == StyleKey.h3) {
|
||||||
tagName = tagH3;
|
tagName = HTMLTag.h3;
|
||||||
}
|
}
|
||||||
} else if (subType == StyleKey.quote) {
|
} else if (subType == StyleKey.quote) {
|
||||||
tagName = tagBlockQuote;
|
tagName = HTMLTag.blockQuote;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final op in delta) {
|
for (final op in delta) {
|
||||||
@ -551,26 +565,26 @@ class NodesToHTMLConverter {
|
|||||||
final attributes = op.attributes;
|
final attributes = op.attributes;
|
||||||
if (attributes != null) {
|
if (attributes != null) {
|
||||||
if (attributes.length == 1 && attributes[StyleKey.bold] == true) {
|
if (attributes.length == 1 && attributes[StyleKey.bold] == true) {
|
||||||
final strong = html.Element.tag(tagStrong);
|
final strong = html.Element.tag(HTMLTag.strong);
|
||||||
strong.append(html.Text(op.content));
|
strong.append(html.Text(op.content));
|
||||||
childNodes.add(strong);
|
childNodes.add(strong);
|
||||||
} else if (attributes.length == 1 &&
|
} else if (attributes.length == 1 &&
|
||||||
attributes[StyleKey.underline] == true) {
|
attributes[StyleKey.underline] == true) {
|
||||||
final strong = html.Element.tag(tagUnderline);
|
final strong = html.Element.tag(HTMLTag.underline);
|
||||||
strong.append(html.Text(op.content));
|
strong.append(html.Text(op.content));
|
||||||
childNodes.add(strong);
|
childNodes.add(strong);
|
||||||
} else if (attributes.length == 1 &&
|
} else if (attributes.length == 1 &&
|
||||||
attributes[StyleKey.italic] == true) {
|
attributes[StyleKey.italic] == true) {
|
||||||
final strong = html.Element.tag(tagItalic);
|
final strong = html.Element.tag(HTMLTag.italic);
|
||||||
strong.append(html.Text(op.content));
|
strong.append(html.Text(op.content));
|
||||||
childNodes.add(strong);
|
childNodes.add(strong);
|
||||||
} else if (attributes.length == 1 &&
|
} else if (attributes.length == 1 &&
|
||||||
attributes[StyleKey.strikethrough] == true) {
|
attributes[StyleKey.strikethrough] == true) {
|
||||||
final strong = html.Element.tag(tagDel);
|
final strong = html.Element.tag(HTMLTag.del);
|
||||||
strong.append(html.Text(op.content));
|
strong.append(html.Text(op.content));
|
||||||
childNodes.add(strong);
|
childNodes.add(strong);
|
||||||
} else {
|
} else {
|
||||||
final span = html.Element.tag(tagSpan);
|
final span = html.Element.tag(HTMLTag.span);
|
||||||
final cssString = _attributesToCssStyle(attributes);
|
final cssString = _attributesToCssStyle(attributes);
|
||||||
if (cssString.isNotEmpty) {
|
if (cssString.isNotEmpty) {
|
||||||
span.attributes["style"] = cssString;
|
span.attributes["style"] = cssString;
|
||||||
@ -584,24 +598,20 @@ class NodesToHTMLConverter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagName == tagBlockQuote) {
|
if (tagName == HTMLTag.blockQuote) {
|
||||||
final p = html.Element.tag(tagParagraph);
|
final p = html.Element.tag(HTMLTag.paragraph);
|
||||||
for (final node in childNodes) {
|
for (final node in childNodes) {
|
||||||
p.append(node);
|
p.append(node);
|
||||||
}
|
}
|
||||||
final blockQuote = html.Element.tag(tagName);
|
final blockQuote = html.Element.tag(tagName);
|
||||||
blockQuote.append(p);
|
blockQuote.append(p);
|
||||||
return blockQuote;
|
return blockQuote;
|
||||||
} else if (tagName != tagParagraph &&
|
} else if (!HTMLTag.isTopLevel(tagName)) {
|
||||||
tagName != tagH1 &&
|
final p = html.Element.tag(HTMLTag.paragraph);
|
||||||
tagName != tagH2 &&
|
|
||||||
tagName != tagH3 &&
|
|
||||||
tagName != tagBlockQuote) {
|
|
||||||
final p = html.Element.tag(tagParagraph);
|
|
||||||
for (final node in childNodes) {
|
for (final node in childNodes) {
|
||||||
p.append(node);
|
p.append(node);
|
||||||
}
|
}
|
||||||
final result = html.Element.tag(tagList);
|
final result = html.Element.tag(HTMLTag.list);
|
||||||
result.append(p);
|
result.append(p);
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user