Rich text editor for Flutter
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.
 
 
 
 
 

123 lines
3.1 KiB

import 'package:flutter_quill/models/documents/attribute.dart';
import 'package:flutter_quill/models/rules/rule.dart';
import 'package:quill_delta/quill_delta.dart';
abstract class DeleteRule extends Rule {
const DeleteRule();
@override
RuleType get type => RuleType.DELETE;
@override
validateArgs(int len, Object data, Attribute attribute) {
assert(len != null);
assert(data == null);
assert(attribute == null);
}
}
class CatchAllDeleteRule extends DeleteRule {
const CatchAllDeleteRule();
@override
Delta applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) {
return Delta()
..retain(index)
..delete(len);
}
}
class PreserveLineStyleOnMergeRule extends DeleteRule {
const PreserveLineStyleOnMergeRule();
@override
Delta applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) {
DeltaIterator itr = DeltaIterator(document);
itr.skip(index);
Operation op = itr.next(1);
if (op.data != '\n') {
return null;
}
bool isNotPlain = op.isNotPlain;
Map<String, dynamic> attrs = op.attributes;
itr.skip(len - 1);
Delta delta = Delta()
..retain(index)
..delete(len);
while (itr.hasNext) {
op = itr.next();
String text = op.data is String ? op.data as String : '';
int lineBreak = text.indexOf('\n');
if (lineBreak == -1) {
delta..retain(op.length);
continue;
}
Map<String, dynamic> attributes = op.attributes == null
? null
: op.attributes.map<String, dynamic>((String key, dynamic value) =>
MapEntry<String, dynamic>(key, null));
if (isNotPlain) {
attributes ??= <String, dynamic>{};
attributes.addAll(attrs);
}
delta..retain(lineBreak)..retain(1, attributes);
break;
}
return delta;
}
}
class EnsureEmbedLineRule extends DeleteRule {
const EnsureEmbedLineRule();
@override
Delta applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) {
DeltaIterator itr = DeltaIterator(document);
Operation op = itr.skip(index);
int indexDelta = 0, lengthDelta = 0, remain = len;
bool embedFound = op != null && op.data is! String;
bool hasLineBreakBefore =
!embedFound && (op == null || (op?.data as String).endsWith('\n'));
if (embedFound) {
Operation candidate = itr.next(1);
remain--;
if (candidate.data == '\n') {
indexDelta++;
lengthDelta--;
candidate = itr.next(1);
remain--;
if (candidate.data == '\n') {
lengthDelta++;
}
}
}
op = itr.skip(remain);
if (op != null &&
(op?.data is String ? op.data as String : '').endsWith('\n')) {
Operation candidate = itr.next(1);
if (candidate.data is! String && !hasLineBreakBefore) {
embedFound = true;
lengthDelta--;
}
}
if (!embedFound) {
return null;
}
return Delta()
..retain(index + indexDelta)
..delete(len + lengthDelta);
}
}