From f910b9dc61cb757cd992c47f431f368902122f66 Mon Sep 17 00:00:00 2001 From: Vincent Chan Date: Mon, 18 Jul 2022 18:54:08 +0800 Subject: [PATCH] feat: delta to string --- .../flowy_editor/assets/document.json | 5 ++ .../flowy_editor/lib/document/node.dart | 7 +++ .../flowy_editor/lib/document/state_tree.dart | 2 +- .../flowy_editor/lib/document/text_delta.dart | 63 +++++++++++++------ .../flowy_editor/test/delta_test.dart | 33 ++++++++++ 5 files changed, 91 insertions(+), 19 deletions(-) diff --git a/frontend/app_flowy/packages/flowy_editor/assets/document.json b/frontend/app_flowy/packages/flowy_editor/assets/document.json index 31092286f8..fb3628de47 100644 --- a/frontend/app_flowy/packages/flowy_editor/assets/document.json +++ b/frontend/app_flowy/packages/flowy_editor/assets/document.json @@ -4,18 +4,21 @@ "children": [ { "type": "text", + "delta": [], "attributes": { "subtype": "with-heading" } }, { "type": "text", + "delta": [], "attributes": { "tag": "*" }, "children": [ { "type": "text", + "delta": [], "attributes": { "text-type": "heading2", "check": true @@ -23,6 +26,7 @@ }, { "type": "text", + "delta": [], "attributes": { "text-type": "checkbox", "check": true @@ -30,6 +34,7 @@ }, { "type": "text", + "delta": [], "attributes": { "tag": "**" } 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 4d2becf9fe..0220827098 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart @@ -176,4 +176,11 @@ class TextNode extends Node { _delta = v; notifyListeners(); } + + @override + Map toJson() { + final map = super.toJson(); + map['delta'] = _delta.toJson(); + return map; + } } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/document/state_tree.dart b/frontend/app_flowy/packages/flowy_editor/lib/document/state_tree.dart index b6dbd26fff..22f4b88c24 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/document/state_tree.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/document/state_tree.dart @@ -40,7 +40,7 @@ class StateTree { if (path.isEmpty) { return false; } - var node = root.childAtPath(path); + final node = root.childAtPath(path); if (node == null || node is! TextNode) { return false; } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/document/text_delta.dart b/frontend/app_flowy/packages/flowy_editor/lib/document/text_delta.dart index b87ca71b95..ede7d65882 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/document/text_delta.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/document/text_delta.dart @@ -1,6 +1,7 @@ import 'dart:collection'; import 'dart:math'; +import 'package:flowy_editor/document/attributes.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import './attributes.dart'; @@ -8,7 +9,7 @@ import './attributes.dart'; // constant number: 2^53 - 1 const int _maxInt = 9007199254740991; -class TextOperation { +abstract class TextOperation { bool get isEmpty { return length == 0; } @@ -20,6 +21,8 @@ class TextOperation { Attributes? get attributes { return null; } + + Map toJson(); } class TextInsert extends TextOperation { @@ -54,6 +57,18 @@ class TextInsert extends TextOperation { return Object.hash( contentHash, attrs == null ? null : hashAttributes(attrs)); } + + @override + Map toJson() { + final result = { + 'insert': content, + }; + final attrs = _attributes; + if (attrs != null) { + result['attributes'] = {...attrs}; + } + return result; + } } class TextRetain extends TextOperation { @@ -96,6 +111,18 @@ class TextRetain extends TextOperation { final attrs = _attributes; return Object.hash(_length, attrs == null ? null : hashAttributes(attrs)); } + + @override + Map toJson() { + final result = { + 'retain': _length, + }; + final attrs = _attributes; + if (attrs != null) { + result['attributes'] = {...attrs}; + } + return result; + } } class TextDelete extends TextOperation { @@ -129,6 +156,13 @@ class TextDelete extends TextOperation { int get hashCode { return _length.hashCode; } + + @override + Map toJson() { + return { + 'delete': _length, + }; + } } class _OpIterator { @@ -215,28 +249,17 @@ class _OpIterator { } } -Attributes? _attributesFromJSON(Map? json) { - if (json == null) { - return null; - } - final result = {}; - - for (final entry in json.entries) { - result[entry.key] = entry.value; - } - - return result; -} - TextOperation? _textOperationFromJson(Map json) { TextOperation? result; if (json['insert'] is String) { - result = TextInsert(json['insert'] as String, - _attributesFromJSON(json['attributes'] as Map?)); + final attrs = json['attributes'] as Map?; + result = + TextInsert(json['insert'] as String, attrs == null ? null : {...attrs}); } else if (json['retain'] is int) { - result = TextRetain(json['retain'] as int, - _attributesFromJSON(json['attributes'] as Map?)); + final attrs = json['attributes'] as Map?; + result = + TextRetain(json['retain'] as int, attrs == null ? null : {...attrs}); } else if (json['delete'] is int) { result = TextDelete(json['delete'] as int); } @@ -459,4 +482,8 @@ class Delta { }); return inverted.chop(); } + + List toJson() { + return operations.map((e) => e.toJson()).toList(); + } } diff --git a/frontend/app_flowy/packages/flowy_editor/test/delta_test.dart b/frontend/app_flowy/packages/flowy_editor/test/delta_test.dart index bce2517744..9a914888d4 100644 --- a/frontend/app_flowy/packages/flowy_editor/test/delta_test.dart +++ b/frontend/app_flowy/packages/flowy_editor/test/delta_test.dart @@ -197,4 +197,37 @@ void main() { // expect(base.compose(delta).compose(inverted), base); // }); }); + group('json', () { + test('toJson()', () { + final delta = Delta().retain(2).insert('A').delete(3); + expect(delta.toJson(), [ + {'retain': 2}, + {'insert': 'A'}, + {'delete': 3} + ]); + }); + test('attributes', () { + final delta = + Delta().retain(2, {'bold': true}).insert('A', {'italic': true}); + expect(delta.toJson(), [ + { + 'retain': 2, + 'attributes': {'bold': true}, + }, + { + 'insert': 'A', + 'attributes': {'italic': true}, + }, + ]); + }); + test('fromJson()', () { + final delta = Delta.fromJson([ + {'retain': 2}, + {'insert': 'A'}, + {'delete': 3}, + ]); + final expected = Delta().retain(2).insert('A').delete(3); + expect(delta, expected); + }); + }); }