diff --git a/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/text_node_widget.dart b/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/text_node_widget.dart index dd504305ca..df2039fbd0 100644 --- a/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/text_node_widget.dart +++ b/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/text_node_widget.dart @@ -23,98 +23,6 @@ class TextNodeBuilder extends NodeWidgetBuilder { } } -extension on Attributes { - TextStyle toTextStyle() { - return TextStyle( - color: this['color'] != null ? Colors.red : Colors.black, - fontSize: this['font-size'] != null ? 30 : 15, - ); - } -} - -TextSpan _textInsertToTextSpan(TextInsert textInsert) { - FontWeight? fontWeight; - FontStyle? fontStyle; - TextDecoration? decoration; - GestureRecognizer? gestureRecognizer; - Color? color; - final attributes = textInsert.attributes; - if (attributes?['bold'] == true) { - fontWeight = FontWeight.bold; - } - if (attributes?['italic'] == true) { - fontStyle = FontStyle.italic; - } - if (attributes?["underline"] == true) { - decoration = TextDecoration.underline; - } - if (attributes?["href"] is String) { - color = const Color.fromARGB(255, 55, 120, 245); - decoration = TextDecoration.underline; - gestureRecognizer = TapGestureRecognizer() - ..onTap = () { - // TODO: open the link - }; - } - return TextSpan( - text: textInsert.content, - style: TextStyle( - fontWeight: fontWeight, - fontStyle: fontStyle, - decoration: decoration, - color: color, - ), - recognizer: gestureRecognizer); -} - -extension on TextNode { - List toTextSpans() { - final result = []; - - for (final op in delta.operations) { - if (op is TextInsert) { - result.add(_textInsertToTextSpan(op)); - } - } - - return result; - } -} - -TextSelection? _globalSelectionToLocal(Node node, Selection? globalSel) { - if (globalSel == null) { - return null; - } - final nodePath = node.path; - - if (!pathEquals(nodePath, globalSel.start.path)) { - return null; - } - if (globalSel.isCollapsed()) { - return TextSelection( - baseOffset: globalSel.start.offset, extentOffset: globalSel.end.offset); - } else { - if (pathEquals(globalSel.start.path, globalSel.end.path)) { - return TextSelection( - baseOffset: globalSel.start.offset, - extentOffset: globalSel.end.offset); - } - } - return null; -} - -Selection? _localSelectionToGlobal(Node node, TextSelection? sel) { - if (sel == null) { - return null; - } - final nodePath = node.path; - - return Selection( - start: Position(path: nodePath, offset: sel.baseOffset), - end: Position(path: nodePath, offset: sel.extentOffset), - ); -} - class _TextNodeWidget extends StatefulWidget { final Node node; final EditorState editorState; @@ -144,10 +52,6 @@ class __TextNodeWidgetState extends State<_TextNodeWidget> TextNode get node => widget.node as TextNode; EditorState get editorState => widget.editorState; - TextEditingValue get textEditingValue => TextEditingValue( - text: node.toRawString(), - ); - TextInputConnection? _textInputConnection; _backDeleteTextAtSelection(TextSelection? sel) { @@ -190,7 +94,7 @@ class __TextNodeWidgetState extends State<_TextNodeWidget> _setEditingStateFromGlobal() { _textInputConnection?.setEditingState(TextEditingValue( - text: _textContentOfDelta(node.delta), + text: node.toString(), selection: _globalSelectionToLocal(node, editorState.cursorSelection) ?? const TextSelection.collapsed(offset: 0))); } @@ -236,9 +140,12 @@ class __TextNodeWidgetState extends State<_TextNodeWidget> _localSelectionToGlobal(node, selection); _textInputConnection ?..show() - ..setEditingState(TextEditingValue( - text: _textContentOfDelta(node.delta), - selection: selection)); + ..setEditingState( + TextEditingValue( + text: node.toString(), + selection: selection, + ), + ); }), ), ), @@ -271,7 +178,7 @@ class __TextNodeWidgetState extends State<_TextNodeWidget> @override // TODO: implement currentTextEditingValue TextEditingValue? get currentTextEditingValue => TextEditingValue( - text: _textContentOfDelta(node.delta), + text: node.toString(), selection: _globalSelectionToLocal(node, editorState.cursorSelection) ?? const TextSelection.collapsed(offset: 0)); @@ -336,67 +243,98 @@ class __TextNodeWidgetState extends State<_TextNodeWidget> extension on TextNode { List toTextSpans() => delta.operations .whereType() - .map((op) => _textInsertToTextSpan(op)) + .map((op) => op.toTextSpan()) .toList(); - - String toRawString() => delta.operations - .whereType() - .map((op) => op.content) - .toString(); } -TextSpan _textInsertToTextSpan(TextInsert textInsert) { - FontWeight? fontWeight; - FontStyle? fontStyle; - TextDecoration? decoration; - GestureRecognizer? gestureRecognizer; - Color? color; - Color highLightColor = Colors.transparent; - double fontSize = 16.0; - final attributes = textInsert.attributes; - if (attributes?['bold'] == true) { - fontWeight = FontWeight.bold; - } - if (attributes?['italic'] == true) { - fontStyle = FontStyle.italic; - } - if (attributes?['underline'] == true) { - decoration = TextDecoration.underline; - } - if (attributes?['strikethrough'] == true) { - decoration = TextDecoration.lineThrough; - } - if (attributes?['highlight'] is String) { - highLightColor = Color(int.parse(attributes!['highlight'])); - } - if (attributes?['href'] is String) { - color = const Color.fromARGB(255, 55, 120, 245); - decoration = TextDecoration.underline; - gestureRecognizer = TapGestureRecognizer() - ..onTap = () { - launchUrlString(attributes?['href']); - }; - } - final heading = attributes?['heading'] as String?; - if (heading != null) { - // TODO: make it better - if (heading == 'h1') { - fontSize = 30.0; - } else if (heading == 'h2') { - fontSize = 20.0; +extension on TextInsert { + TextSpan toTextSpan() { + FontWeight? fontWeight; + FontStyle? fontStyle; + TextDecoration? decoration; + GestureRecognizer? gestureRecognizer; + Color? color; + Color highLightColor = Colors.transparent; + double fontSize = 16.0; + final attributes = this.attributes; + if (attributes?['bold'] == true) { + fontWeight = FontWeight.bold; } - fontWeight = FontWeight.bold; + if (attributes?['italic'] == true) { + fontStyle = FontStyle.italic; + } + if (attributes?['underline'] == true) { + decoration = TextDecoration.underline; + } + if (attributes?['strikethrough'] == true) { + decoration = TextDecoration.lineThrough; + } + if (attributes?['highlight'] is String) { + highLightColor = Color(int.parse(attributes!['highlight'])); + } + if (attributes?['href'] is String) { + color = const Color.fromARGB(255, 55, 120, 245); + decoration = TextDecoration.underline; + gestureRecognizer = TapGestureRecognizer() + ..onTap = () { + launchUrlString(attributes?['href']); + }; + } + final heading = attributes?['heading'] as String?; + if (heading != null) { + // TODO: make it better + if (heading == 'h1') { + fontSize = 30.0; + } else if (heading == 'h2') { + fontSize = 20.0; + } + fontWeight = FontWeight.bold; + } + return TextSpan( + text: content, + style: TextStyle( + fontWeight: fontWeight, + fontStyle: fontStyle, + decoration: decoration, + color: color, + fontSize: fontSize, + backgroundColor: highLightColor, + ), + recognizer: gestureRecognizer, + ); } - return TextSpan( - text: textInsert.content, - style: TextStyle( - fontWeight: fontWeight, - fontStyle: fontStyle, - decoration: decoration, - color: color, - fontSize: fontSize, - backgroundColor: highLightColor, - ), - recognizer: gestureRecognizer, +} + +TextSelection? _globalSelectionToLocal(Node node, Selection? globalSel) { + if (globalSel == null) { + return null; + } + final nodePath = node.path; + + if (!pathEquals(nodePath, globalSel.start.path)) { + return null; + } + if (globalSel.isCollapsed()) { + return TextSelection( + baseOffset: globalSel.start.offset, extentOffset: globalSel.end.offset); + } else { + if (pathEquals(globalSel.start.path, globalSel.end.path)) { + return TextSelection( + baseOffset: globalSel.start.offset, + extentOffset: globalSel.end.offset); + } + } + return null; +} + +Selection? _localSelectionToGlobal(Node node, TextSelection? sel) { + if (sel == null) { + return null; + } + final nodePath = node.path; + + return Selection( + start: Position(path: nodePath, offset: sel.baseOffset), + end: Position(path: nodePath, offset: sel.extentOffset), ); } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart b/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart index 0220827098..9d8b9906b0 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart @@ -183,4 +183,11 @@ class TextNode extends Node { map['delta'] = _delta.toJson(); return map; } + + String toString() { + _delta.operations + .whereType() + .map((op) => op.content) + .toString(); + } }