1
0
mirror of https://github.com/GitJournal/GitJournal.git synced 2025-07-11 21:12:44 +08:00

Add a Checklist class

This commit is contained in:
Vishesh Handa
2020-02-10 15:43:48 +01:00
parent 4903a95421
commit b98a42543e
2 changed files with 161 additions and 0 deletions

101
lib/core/checklist.dart Normal file

@ -0,0 +1,101 @@
import 'package:flutter/material.dart';
import 'package:markdown/markdown.dart' as md;
import 'package:gitjournal/core/note.dart';
class ChecklistItem {
bool checked;
String text;
md.Element element;
ChecklistItem({
@required this.checked,
@required this.text,
@required this.element,
});
@override
String toString() => 'ChecklistItem: $checked $text';
}
class Checklist {
Note note;
List<ChecklistItem> items;
Checklist(this.note) {
items = ChecklistBuilder().parse(note.body);
}
}
/// Copied from flutter-markdown - cannot be merged as we added xUpperCase and changed the regexp
/// 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);
@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);
return true;
}
}
class ChecklistBuilder implements md.NodeVisitor {
List<ChecklistItem> list;
@override
bool visitElementBefore(md.Element element) {
return true;
}
@override
void visitText(md.Text text) {}
@override
void visitElementAfter(md.Element element) {
final String tag = element.tag;
if (tag == 'input') {
var el = element;
if (el is md.Element && el.attributes['type'] == 'checkbox') {
bool val = el.attributes['checked'] != 'false';
var item = ChecklistItem(
checked: val,
text: el.attributes['text'],
element: el,
);
list.add(item);
}
}
}
List<ChecklistItem> build(List<md.Node> nodes) {
list = <ChecklistItem>[];
for (md.Node node in nodes) {
node.accept(this);
}
return list;
}
List<ChecklistItem> parse(String text) {
var doc = md.Document(
encodeHtml: false,
inlineSyntaxes: [TaskListSyntax()],
extensionSet: md.ExtensionSet.gitHubFlavored,
);
var nodes = doc.parseInline(text);
return build(nodes);
}
}

60
test/checklist_test.dart Normal file

@ -0,0 +1,60 @@
import 'dart:io';
import 'package:gitjournal/core/checklist.dart';
import 'package:gitjournal/core/note.dart';
import 'package:gitjournal/core/notes_folder.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
void main() {
group('Note', () {
Directory tempDir;
setUpAll(() async {
tempDir = await Directory.systemTemp.createTemp('__notes_test__');
});
tearDownAll(() async {
tempDir.deleteSync(recursive: true);
});
test('Should parse simple checklists', () async {
var content = """---
title: Foo
modified: 2017-02-15T22:41:19+01:00
---
# Title 1
How are you doing?
[ ] item 1
[x] item 2
[X] item 3
[ ] item 4
Booga Wooga
""";
var notePath = p.join(tempDir.path, "note.md");
File(notePath).writeAsString(content);
var parentFolder = NotesFolder(null, tempDir.path);
var note = Note(parentFolder, notePath);
await note.load();
var checklist = Checklist(note);
expect(checklist.items.length, equals(4));
expect(checklist.items[0].checked, false);
expect(checklist.items[1].checked, true);
expect(checklist.items[2].checked, true);
expect(checklist.items[3].checked, false);
expect(checklist.items[0].text, "item 1");
expect(checklist.items[1].text, "item 2");
expect(checklist.items[2].text, "item 3");
expect(checklist.items[3].text, "item 4");
});
});
}