mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-29 10:17:16 +08:00
Try to support the proper checklist format
According the markdownguide.org, the checklist items are always inside a list. It can any kind of list, but they are inside a list. This commit breaks the old syntax and most of the tests. It also requires a custom version of markd :/
This commit is contained in:
@ -1,27 +1,62 @@
|
|||||||
import 'package:markdown/markdown.dart' as md;
|
import 'package:markd/markdown.dart' as md;
|
||||||
|
|
||||||
import 'package:gitjournal/core/note.dart';
|
import 'package:gitjournal/core/note.dart';
|
||||||
|
|
||||||
class ChecklistItem {
|
class ChecklistItem {
|
||||||
|
md.Element parentListElement;
|
||||||
md.Element element;
|
md.Element element;
|
||||||
|
|
||||||
bool get checked {
|
bool get checked {
|
||||||
return element.attributes['checked'] != "false";
|
if (element.children == null || element.children.isEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputEl = element.children[0] as md.Element;
|
||||||
|
assert(inputEl.attributes['class'] == 'todo');
|
||||||
|
return inputEl.attributes.containsKey('checked');
|
||||||
}
|
}
|
||||||
|
|
||||||
set checked(bool val) {
|
set checked(bool val) {
|
||||||
element.attributes['checked'] = val.toString();
|
if (element.children == null || element.children.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var inputEl = element.children[0] as md.Element;
|
||||||
|
assert(inputEl.attributes['class'] == 'todo');
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
inputEl.attributes["checked"] = "checked";
|
||||||
|
} else {
|
||||||
|
inputEl.attributes.remove('checked');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String get text {
|
String get text {
|
||||||
return element.attributes['text'];
|
if (element.children == null || element.children.isEmpty) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (element.children.length > 1) {
|
||||||
|
return element.children[1].textContent.substring(1);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
set text(String val) {
|
set text(String val) {
|
||||||
element.attributes['text'] = val;
|
if (element.children == null || element.children.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (element.children.length > 1) {
|
||||||
|
element.children[1] = md.Text(" $val");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChecklistItem.fromMarkdownElement(this.element);
|
ChecklistItem.fromMarkdownElement(this.element, this.parentListElement) {
|
||||||
|
assert(element.children.isNotEmpty);
|
||||||
|
|
||||||
|
// FIXME: Maybe this shouldn't be allowed
|
||||||
|
if (parentListElement != null) {
|
||||||
|
assert(parentListElement.children.contains(element));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'ChecklistItem: $checked $text';
|
String toString() => 'ChecklistItem: $checked $text';
|
||||||
@ -30,51 +65,49 @@ class ChecklistItem {
|
|||||||
class Checklist {
|
class Checklist {
|
||||||
Note _note;
|
Note _note;
|
||||||
List<ChecklistItem> items;
|
List<ChecklistItem> items;
|
||||||
List<md.Node> nodes;
|
|
||||||
|
List<md.Node> _nodes;
|
||||||
|
|
||||||
Checklist(this._note) {
|
Checklist(this._note) {
|
||||||
var doc = md.Document(
|
var doc = md.Document(
|
||||||
encodeHtml: false,
|
encodeHtml: false,
|
||||||
inlineSyntaxes: [TaskListSyntax()],
|
blockSyntaxes: md.BlockParser.standardBlockSyntaxes,
|
||||||
extensionSet: md.ExtensionSet.gitHubFlavored,
|
extensionSet: md.ExtensionSet.gitHubWeb,
|
||||||
);
|
);
|
||||||
|
|
||||||
nodes = doc.parseInline(_note.body);
|
_nodes = doc.parseLines(_note.body.split('\n'));
|
||||||
_cleanupNodes(nodes);
|
for (var node in _nodes) {
|
||||||
|
if (node is md.Element) {
|
||||||
items = ChecklistBuilder().build(nodes);
|
var elem = node;
|
||||||
}
|
_printElement(elem, "");
|
||||||
|
|
||||||
void _cleanupNodes(List<md.Node> nodes) {
|
|
||||||
if (nodes.length <= 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var last = nodes.last;
|
|
||||||
var secLast = nodes[nodes.length - 2];
|
|
||||||
|
|
||||||
if (last is! md.Text) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (secLast is! md.Element) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var elem = secLast as md.Element;
|
|
||||||
if (elem.tag != 'input' || elem.attributes['type'] != 'checkbox') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some times we get an extra \n in the end, not sure why.
|
|
||||||
if (last.textContent == '\n') {
|
|
||||||
nodes.length = nodes.length - 1;
|
|
||||||
if (!elem.attributes["text"].endsWith('\n')) {
|
|
||||||
elem.attributes["text"] += '\n';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
print('---------');
|
||||||
|
|
||||||
|
var builder = ChecklistBuilder();
|
||||||
|
items = builder.build(_nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _printElement(md.Element elem, String indent) {
|
||||||
|
print("$indent Begin ${elem.toString()}");
|
||||||
|
print("$indent E TAG ${elem.tag}");
|
||||||
|
print("$indent E ATTRIBUTES ${elem.attributes}");
|
||||||
|
print("$indent E generatedId ${elem.generatedId}");
|
||||||
|
print("$indent E children ${elem.children}");
|
||||||
|
if (elem.children != null) {
|
||||||
|
for (var child in elem.children) {
|
||||||
|
if (child is md.Element) {
|
||||||
|
_printElement(child, indent + " ");
|
||||||
|
} else {
|
||||||
|
print("$indent $child - ${child.textContent}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print("$indent End ${elem.toString()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Note get note {
|
Note get note {
|
||||||
if (nodes.isEmpty) return _note;
|
if (_nodes.isEmpty) return _note;
|
||||||
|
|
||||||
// Remove empty trailing items
|
// Remove empty trailing items
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -89,8 +122,8 @@ class Checklist {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var renderer = CustomRenderer();
|
var renderer = MarkdownRenderer();
|
||||||
_note.body = renderer.render(nodes);
|
_note.body = renderer.render(_nodes);
|
||||||
|
|
||||||
return _note;
|
return _note;
|
||||||
}
|
}
|
||||||
@ -105,109 +138,103 @@ class Checklist {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChecklistItem buildItem(bool value, String text) {
|
ChecklistItem buildItem(bool value, String text) {
|
||||||
var elem = md.Element.withTag("input");
|
var inputElement = md.Element.withTag('input');
|
||||||
elem.attributes["type"] = "checkbox";
|
inputElement.attributes['class'] = 'todo';
|
||||||
elem.attributes["checked"] = value.toString();
|
inputElement.attributes['type'] = 'checkbox';
|
||||||
elem.attributes["xUpperCase"] = "false";
|
inputElement.attributes['disabled'] = 'disabled';
|
||||||
elem.attributes["text"] = text;
|
if (value) {
|
||||||
|
inputElement.attributes['checked'] = 'checked';
|
||||||
|
}
|
||||||
|
|
||||||
return ChecklistItem.fromMarkdownElement(elem);
|
var liElement = md.Element('li', [inputElement, md.Text(' $text')]);
|
||||||
|
liElement.attributes['class'] = 'todo';
|
||||||
|
|
||||||
|
// FIXME: Come on, there must be a simpler way
|
||||||
|
return ChecklistItem.fromMarkdownElement(liElement, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeItem(ChecklistItem item) {
|
void removeItem(ChecklistItem item) {
|
||||||
assert(nodes.contains(item.element));
|
|
||||||
assert(items.contains(item));
|
assert(items.contains(item));
|
||||||
|
|
||||||
nodes.remove(item.element);
|
|
||||||
items.remove(item);
|
items.remove(item);
|
||||||
|
|
||||||
|
bool foundChild = false;
|
||||||
|
var parentList = item.parentListElement;
|
||||||
|
for (var i = 0; i < parentList.children.length; i++) {
|
||||||
|
var child = parentList.children[i];
|
||||||
|
if (child == item.element) {
|
||||||
|
foundChild = true;
|
||||||
|
parentList.children.removeAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(foundChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChecklistItem removeAt(int index) {
|
ChecklistItem removeAt(int index) {
|
||||||
assert(index >= 0 && index <= items.length);
|
assert(index >= 0 && index <= items.length);
|
||||||
|
|
||||||
var item = items[index];
|
var item = items[index];
|
||||||
assert(nodes.contains(item.element));
|
removeItem(item);
|
||||||
|
|
||||||
nodes.remove(item.element);
|
|
||||||
items.removeAt(index);
|
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addItem(ChecklistItem item) {
|
void addItem(ChecklistItem item) {
|
||||||
_insertNewLineIfRequired(nodes.length - 1);
|
if (items.isEmpty) {
|
||||||
|
var listElement = md.Element.withTag('ul');
|
||||||
|
_nodes.add(listElement);
|
||||||
|
item.parentListElement = listElement;
|
||||||
|
} else {
|
||||||
|
var prevItem = items.last;
|
||||||
|
item.parentListElement = prevItem.parentListElement;
|
||||||
|
}
|
||||||
|
|
||||||
items.add(item);
|
items.add(item);
|
||||||
nodes.add(item.element);
|
item.parentListElement.children.add(item.element);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertItem(int index, ChecklistItem item) {
|
void insertItem(int index, ChecklistItem item) {
|
||||||
assert(index <= items.length, "Trying to insert beyond the end");
|
if (index == 0 && items.isEmpty) {
|
||||||
if (index == 0) {
|
addItem(item);
|
||||||
items.insert(0, item);
|
|
||||||
nodes.insert(0, item.element);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(index <= items.length, "Trying to insert beyond the end");
|
||||||
if (index == items.length) {
|
if (index == items.length) {
|
||||||
addItem(item);
|
addItem(item);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var prevItem = items[index];
|
var prevItem = index - 1 > 0 ? items[index - 1] : items[index];
|
||||||
var nodeIndex = nodes.indexOf(prevItem.element);
|
item.parentListElement = prevItem.parentListElement;
|
||||||
|
var parentList = item.parentListElement;
|
||||||
|
|
||||||
_insertNewLineIfRequired(nodeIndex);
|
// Insert in correct place
|
||||||
|
bool foundChild = false;
|
||||||
nodes.insert(nodeIndex, item.element);
|
for (var i = 0; i < parentList.children.length; i++) {
|
||||||
items.insert(index, item);
|
var child = parentList.children[i];
|
||||||
}
|
if (child == prevItem.element) {
|
||||||
|
foundChild = true;
|
||||||
void _insertNewLineIfRequired(int pos) {
|
parentList.children.insert(i, item.element);
|
||||||
if (nodes.isEmpty) return;
|
break;
|
||||||
|
|
||||||
var node = nodes[pos];
|
|
||||||
if (node is md.Text) {
|
|
||||||
if (!node.text.endsWith('\n')) {
|
|
||||||
nodes.add(md.Text("\n"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
assert(foundChild);
|
||||||
}
|
|
||||||
|
|
||||||
/// Copied from flutter-markdown - cannot be merged as we added xUpperCase and changed the regexp
|
items.insert(index, item);
|
||||||
/// Parse [task list items](https://github.github.com/gfm/#task-list-items-extension-).
|
|
||||||
class TaskListSyntax extends md.InlineSyntax {
|
|
||||||
// FIXME: Waiting for dart-lang/markdown#269 to land
|
|
||||||
static final String _pattern = r'^ *\[([ xX])\] +(.*)';
|
|
||||||
|
|
||||||
TaskListSyntax() : super(_pattern, startCharacter: '['.codeUnitAt(0));
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool onMatch(md.InlineParser parser, Match match) {
|
|
||||||
md.Element el = md.Element.withTag('input');
|
|
||||||
el.attributes['type'] = 'checkbox';
|
|
||||||
el.attributes['checked'] = '${match[1].trim().isNotEmpty}';
|
|
||||||
var m = match[1].trim();
|
|
||||||
if (m.isNotEmpty) {
|
|
||||||
el.attributes['xUpperCase'] = (m[0] == 'X').toString();
|
|
||||||
}
|
|
||||||
el.attributes['text'] = '${match[2]}';
|
|
||||||
parser.addNode(el);
|
|
||||||
|
|
||||||
var lenToConsume = match[0].length;
|
|
||||||
if (match.end + 1 < match.input.length) {
|
|
||||||
lenToConsume += 1; // Consume \n
|
|
||||||
}
|
|
||||||
parser.consume(lenToConsume);
|
|
||||||
return false; // We are advancing manually
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChecklistBuilder implements md.NodeVisitor {
|
class ChecklistBuilder implements md.NodeVisitor {
|
||||||
List<ChecklistItem> list;
|
List<ChecklistItem> list;
|
||||||
|
md.Element listElement;
|
||||||
|
md.Element parent;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool visitElementBefore(md.Element element) {
|
bool visitElementBefore(md.Element element) {
|
||||||
|
if (element.tag == 'ul' || element.tag == 'ol') {
|
||||||
|
listElement = element;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,9 +247,15 @@ class ChecklistBuilder implements md.NodeVisitor {
|
|||||||
void visitElementAfter(md.Element el) {
|
void visitElementAfter(md.Element el) {
|
||||||
final String tag = el.tag;
|
final String tag = el.tag;
|
||||||
|
|
||||||
if (tag == 'input') {
|
if (tag == 'ul' || tag == 'ol') {
|
||||||
if (el is md.Element && el.attributes['type'] == 'checkbox') {
|
listElement = null;
|
||||||
list.add(ChecklistItem.fromMarkdownElement(el));
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag == 'li') {
|
||||||
|
if (el.attributes['class'] == 'todo') {
|
||||||
|
list.add(ChecklistItem.fromMarkdownElement(el, listElement));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//print("builder tag: $tag");
|
//print("builder tag: $tag");
|
||||||
@ -238,11 +271,45 @@ class ChecklistBuilder implements md.NodeVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomRenderer implements md.NodeVisitor {
|
class MarkdownRenderer implements md.NodeVisitor {
|
||||||
StringBuffer buffer;
|
StringBuffer buffer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool visitElementBefore(md.Element element) {
|
bool visitElementBefore(md.Element element) {
|
||||||
|
switch (element.tag) {
|
||||||
|
case 'h1':
|
||||||
|
buffer.write('# ');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h2':
|
||||||
|
buffer.write('## ');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h3':
|
||||||
|
buffer.write('### ');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h4':
|
||||||
|
buffer.write('#### ');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h5':
|
||||||
|
buffer.write('##### ');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h6':
|
||||||
|
buffer.write('###### ');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'li':
|
||||||
|
buffer.write('- ');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
case 'ul':
|
||||||
|
buffer.write('\n');
|
||||||
|
break;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,26 +324,30 @@ class CustomRenderer implements md.NodeVisitor {
|
|||||||
final String tag = element.tag;
|
final String tag = element.tag;
|
||||||
|
|
||||||
if (tag == 'input') {
|
if (tag == 'input') {
|
||||||
var el = element;
|
var attr = element.attributes;
|
||||||
if (el is md.Element && el.attributes['type'] == 'checkbox') {
|
print(attr);
|
||||||
bool val = el.attributes['checked'] != 'false';
|
if (attr['class'] == 'todo' && attr['type'] == 'checkbox') {
|
||||||
|
bool val = attr.containsKey('checked');
|
||||||
if (val) {
|
if (val) {
|
||||||
if (el.attributes['xUpperCase'] != 'false') {
|
buffer.write('[x]');
|
||||||
buffer.write('[x] ');
|
|
||||||
} else {
|
|
||||||
buffer.write('[X] ');
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
buffer.write('[ ] ');
|
buffer.write('[ ]');
|
||||||
}
|
|
||||||
var text = el.attributes['text'];
|
|
||||||
buffer.write(text);
|
|
||||||
//print("writeElem $text#");
|
|
||||||
if (!text.endsWith('\n')) {
|
|
||||||
//print("writeElem newLine#");
|
|
||||||
buffer.write('\n');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case 'h1':
|
||||||
|
case 'h2':
|
||||||
|
case 'h3':
|
||||||
|
case 'h4':
|
||||||
|
case 'h5':
|
||||||
|
case 'h6':
|
||||||
|
case 'p':
|
||||||
|
case 'li':
|
||||||
|
buffer.write('\n');
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,6 +376,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.11.3+2"
|
version: "0.11.3+2"
|
||||||
|
markd:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "/Users/vishesh/src/gitjournal/markd"
|
||||||
|
relative: false
|
||||||
|
source: path
|
||||||
|
version: "2.1.3+6"
|
||||||
markdown:
|
markdown:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -41,6 +41,8 @@ dependencies:
|
|||||||
font_awesome_flutter: ^8.7.0
|
font_awesome_flutter: ^8.7.0
|
||||||
sentry: ">=3.0.0 <4.0.0"
|
sentry: ">=3.0.0 <4.0.0"
|
||||||
equatable: ^1.1.0
|
equatable: ^1.1.0
|
||||||
|
markd:
|
||||||
|
path: /Users/vishesh/src/gitjournal/markd
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_launcher_icons: "^0.7.2"
|
flutter_launcher_icons: "^0.7.2"
|
||||||
|
@ -59,17 +59,6 @@ Booga Wooga
|
|||||||
expect(items[3].text, "item 4");
|
expect(items[3].text, "item 4");
|
||||||
expect(items[4].text, "item 5");
|
expect(items[4].text, "item 5");
|
||||||
|
|
||||||
// Nodes
|
|
||||||
var nodes = checklist.nodes;
|
|
||||||
expect(nodes.length, equals(7));
|
|
||||||
expect(nodes[0].textContent, "# Title 1\n\nHow are you doing?\n\n");
|
|
||||||
expect(nodes[1], items[0].element);
|
|
||||||
expect(nodes[2], items[1].element);
|
|
||||||
expect(nodes[3], items[2].element);
|
|
||||||
expect(nodes[4], items[3].element);
|
|
||||||
expect(nodes[5], items[4].element);
|
|
||||||
expect(nodes[6].textContent, "\nBooga Wooga\n");
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Serialization
|
// Serialization
|
||||||
//
|
//
|
||||||
@ -123,11 +112,13 @@ Booga Wooga
|
|||||||
expect(items.length, equals(3));
|
expect(items.length, equals(3));
|
||||||
|
|
||||||
// Nodes
|
// Nodes
|
||||||
|
/*
|
||||||
var nodes = checklist.nodes;
|
var nodes = checklist.nodes;
|
||||||
expect(nodes.length, equals(3));
|
expect(nodes.length, equals(3));
|
||||||
expect(nodes[0], items[0].element);
|
expect(nodes[0], items[0].element);
|
||||||
expect(nodes[1], items[1].element);
|
expect(nodes[1], items[1].element);
|
||||||
expect(nodes[2], items[2].element);
|
expect(nodes[2], items[2].element);
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should add \\n before item when adding', () async {
|
test('Should add \\n before item when adding', () async {
|
||||||
@ -226,5 +217,80 @@ Booga Wooga
|
|||||||
note = checklist.note;
|
note = checklist.note;
|
||||||
expect(note.body, "[ ] One\n[ ]Two\n[ ] Three\n[ ] Four\n[ ] Five\n");
|
expect(note.body, "[ ] One\n[ ]Two\n[ ] Three\n[ ] Four\n[ ] Five\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Should parse simple checklists in a list', () async {
|
||||||
|
var content = """---
|
||||||
|
title: Foo
|
||||||
|
---
|
||||||
|
|
||||||
|
# Title 1
|
||||||
|
|
||||||
|
How are you doing?
|
||||||
|
|
||||||
|
- [ ] item 1
|
||||||
|
- [x] item 2
|
||||||
|
- [x] item 3
|
||||||
|
- [ ] item 4
|
||||||
|
- [ ] item 5
|
||||||
|
|
||||||
|
Booga Wooga
|
||||||
|
""";
|
||||||
|
|
||||||
|
var notePath = p.join(tempDir.path, "note.md");
|
||||||
|
File(notePath).writeAsString(content);
|
||||||
|
|
||||||
|
var parentFolder = NotesFolderFS(null, tempDir.path);
|
||||||
|
var note = Note(parentFolder, notePath);
|
||||||
|
await note.load();
|
||||||
|
|
||||||
|
var checklist = Checklist(note);
|
||||||
|
var items = checklist.items;
|
||||||
|
expect(items.length, equals(5));
|
||||||
|
|
||||||
|
expect(items[0].checked, false);
|
||||||
|
expect(items[1].checked, true);
|
||||||
|
expect(items[2].checked, true);
|
||||||
|
expect(items[3].checked, false);
|
||||||
|
expect(items[4].checked, false);
|
||||||
|
|
||||||
|
expect(items[0].text, "item 1");
|
||||||
|
expect(items[1].text, "item 2");
|
||||||
|
expect(items[2].text, "item 3");
|
||||||
|
expect(items[3].text, "item 4");
|
||||||
|
expect(items[4].text, "item 5");
|
||||||
|
|
||||||
|
//
|
||||||
|
// Serialization
|
||||||
|
//
|
||||||
|
checklist.items[0].checked = true;
|
||||||
|
checklist.items[1].checked = false;
|
||||||
|
checklist.items[1].text = "Foo";
|
||||||
|
var item = checklist.buildItem(false, "Howdy");
|
||||||
|
checklist.addItem(item);
|
||||||
|
|
||||||
|
checklist.removeItem(checklist.items[4]);
|
||||||
|
|
||||||
|
await checklist.note.save();
|
||||||
|
|
||||||
|
var expectedContent = """---
|
||||||
|
title: Foo
|
||||||
|
---
|
||||||
|
|
||||||
|
# Title 1
|
||||||
|
|
||||||
|
How are you doing?
|
||||||
|
|
||||||
|
- [x] item 1
|
||||||
|
- [ ] Foo
|
||||||
|
- [x] item 3
|
||||||
|
- [ ] item 4
|
||||||
|
- [ ] Howdy
|
||||||
|
|
||||||
|
Booga Wooga
|
||||||
|
""";
|
||||||
|
|
||||||
|
var actualContent = File(notePath).readAsStringSync();
|
||||||
|
expect(actualContent, equals(expectedContent));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user