dartlangeditorflutterflutter-appsflutter-examplesflutter-packageflutter-widgetquillquill-deltaquilljsreactquillrich-textrich-text-editorwysiwygwysiwyg-editor
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
3.0 KiB
117 lines
3.0 KiB
import 'package:charcode/charcode.dart'; |
|
import 'package:markdown/markdown.dart'; |
|
|
|
import '../../../flutter_quill.dart' hide Node; |
|
|
|
/// Parses markdown table and saves the table markdown content into the element attributes. |
|
class EmbeddableTableSyntax extends BlockSyntax { |
|
/// @nodoc |
|
const EmbeddableTableSyntax(); |
|
static const _base = TableSyntax(); |
|
|
|
@override |
|
bool canEndBlock(BlockParser parser) => false; |
|
|
|
@override |
|
RegExp get pattern => _base.pattern; |
|
|
|
@override |
|
bool canParse(BlockParser parser) => _base.canParse(parser); |
|
|
|
/// Parses a table into its three parts: |
|
/// |
|
/// * a head row of head cells (`<th>` cells) |
|
/// * a divider of hyphens and pipes (not rendered) |
|
/// * many body rows of body cells (`<td>` cells) |
|
@override |
|
Node? parse(BlockParser parser) { |
|
final columnCount = _columnCount(parser.next!.content); |
|
final headCells = _columnCount(parser.current.content); |
|
final valBuf = |
|
StringBuffer('${parser.current.content}\n${parser.next!.content}'); |
|
parser.advance(); |
|
if (columnCount != headCells) { |
|
return null; |
|
} |
|
|
|
// advance header and divider of hyphens. |
|
parser.advance(); |
|
|
|
while (!parser.isDone && !BlockSyntax.isAtBlockEnd(parser)) { |
|
valBuf.write('\n${parser.current.content}'); |
|
parser.advance(); |
|
} |
|
|
|
return Element.empty(EmbeddableTable.tableType) |
|
..attributes['data'] = valBuf.toString(); |
|
} |
|
|
|
int _columnCount(String line) { |
|
final startIndex = _walkPastOpeningPipe(line); |
|
|
|
var endIndex = line.length - 1; |
|
while (endIndex > 0) { |
|
final ch = line.codeUnitAt(endIndex); |
|
if (ch == $pipe) { |
|
endIndex--; |
|
break; |
|
} |
|
if (ch != $space && ch != $tab) { |
|
break; |
|
} |
|
endIndex--; |
|
} |
|
|
|
return line.substring(startIndex, endIndex + 1).split('|').length; |
|
} |
|
|
|
int _walkPastWhitespace(String line, int index) { |
|
while (index < line.length) { |
|
final ch = line.codeUnitAt(index); |
|
if (ch != $space && ch != $tab) { |
|
break; |
|
} |
|
//ignore: parameter_assignments |
|
index++; |
|
} |
|
return index; |
|
} |
|
|
|
int _walkPastOpeningPipe(String line) { |
|
var index = 0; |
|
while (index < line.length) { |
|
final ch = line.codeUnitAt(index); |
|
if (ch == $pipe) { |
|
index++; |
|
index = _walkPastWhitespace(line, index); |
|
} |
|
if (ch != $space && ch != $tab) { |
|
// No leading pipe. |
|
break; |
|
} |
|
index++; |
|
} |
|
return index; |
|
} |
|
} |
|
|
|
/// An [Embeddable] table that can used to render a table in quill_editor |
|
class EmbeddableTable extends BlockEmbed { |
|
/// @nodoc |
|
EmbeddableTable(String data) : super(tableType, data); |
|
|
|
/// [Embeddable] type |
|
static const tableType = 'x-embed-table'; |
|
|
|
/// Create from markdown. |
|
//ignore: prefer_constructors_over_static_methods |
|
static EmbeddableTable fromMdSyntax(Map<String, String> attributes) => |
|
EmbeddableTable(attributes['data']!); |
|
|
|
/// Outputs table markdown to output. |
|
static void toMdSyntax(Embed embed, StringSink out) { |
|
out |
|
..writeln(embed.value.data) |
|
..writeln(); |
|
} |
|
}
|
|
|