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.
134 lines
3.6 KiB
134 lines
3.6 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 FormatRule extends Rule { |
|
const FormatRule(); |
|
|
|
@override |
|
RuleType get type => RuleType.FORMAT; |
|
|
|
@override |
|
validateArgs(int len, Object data, Attribute attribute) { |
|
assert(len != null); |
|
assert(data == null); |
|
assert(attribute != null); |
|
} |
|
} |
|
|
|
class ResolveLineFormatRule extends FormatRule { |
|
const ResolveLineFormatRule(); |
|
|
|
@override |
|
Delta applyRule(Delta document, int index, |
|
{int len, Object data, Attribute attribute}) { |
|
if (attribute.scope != AttributeScope.BLOCK) { |
|
return null; |
|
} |
|
|
|
Delta delta = Delta()..retain(index); |
|
DeltaIterator itr = DeltaIterator(document); |
|
itr.skip(index); |
|
Operation op; |
|
for (int cur = 0; cur < len && itr.hasNext; cur += op.length) { |
|
op = itr.next(len - cur); |
|
if (op.data is! String || !(op.data as String).contains('\n')) { |
|
delta.retain(op.length); |
|
continue; |
|
} |
|
String text = op.data; |
|
Delta tmp = Delta(); |
|
int offset = 0; |
|
|
|
for (int lineBreak = text.indexOf('\n'); |
|
lineBreak >= 0; |
|
lineBreak = text.indexOf('\n', offset)) { |
|
tmp..retain(lineBreak - offset)..retain(1, attribute.toJson()); |
|
offset = lineBreak + 1; |
|
} |
|
tmp.retain(text.length - offset); |
|
delta = delta.concat(tmp); |
|
} |
|
|
|
while (itr.hasNext) { |
|
op = itr.next(); |
|
String text = op.data is String ? op.data as String : ''; |
|
int lineBreak = text.indexOf('\n'); |
|
if (lineBreak < 0) { |
|
delta..retain(op.length); |
|
continue; |
|
} |
|
delta..retain(lineBreak)..retain(1, attribute.toJson()); |
|
break; |
|
} |
|
return delta; |
|
} |
|
} |
|
|
|
class FormatLinkAtCaretPositionRule extends FormatRule { |
|
const FormatLinkAtCaretPositionRule(); |
|
|
|
@override |
|
Delta applyRule(Delta document, int index, |
|
{int len, Object data, Attribute attribute}) { |
|
if (attribute.key != Attribute.link.key || len > 0) { |
|
return null; |
|
} |
|
|
|
Delta delta = Delta(); |
|
DeltaIterator itr = DeltaIterator(document); |
|
Operation before = itr.skip(index), after = itr.next(); |
|
int beg = index, retain = 0; |
|
if (before != null && before.hasAttribute(attribute.key)) { |
|
beg -= before.length; |
|
retain = before.length; |
|
} |
|
if (after != null && after.hasAttribute(attribute.key)) { |
|
retain += after.length; |
|
} |
|
if (retain == 0) { |
|
return null; |
|
} |
|
|
|
delta..retain(beg)..retain(retain, attribute.toJson()); |
|
return delta; |
|
} |
|
} |
|
|
|
class ResolveInlineFormatRule extends FormatRule { |
|
const ResolveInlineFormatRule(); |
|
|
|
@override |
|
Delta applyRule(Delta document, int index, |
|
{int len, Object data, Attribute attribute}) { |
|
if (attribute.scope != AttributeScope.INLINE) { |
|
return null; |
|
} |
|
|
|
Delta delta = Delta()..retain(index); |
|
DeltaIterator itr = DeltaIterator(document); |
|
itr.skip(index); |
|
|
|
Operation op; |
|
for (int cur = 0; cur < len && itr.hasNext; cur += op.length) { |
|
op = itr.next(len - cur); |
|
String text = op.data is String ? op.data as String : ''; |
|
int lineBreak = text.indexOf('\n'); |
|
if (lineBreak < 0) { |
|
delta.retain(op.length, attribute.toJson()); |
|
continue; |
|
} |
|
int pos = 0; |
|
while (lineBreak >= 0) { |
|
delta..retain(lineBreak - pos, attribute.toJson())..retain(1); |
|
pos = lineBreak + 1; |
|
lineBreak = text.indexOf('\n', pos); |
|
} |
|
if (pos < op.length) { |
|
delta.retain(op.length - pos, attribute.toJson()); |
|
} |
|
} |
|
|
|
return delta; |
|
} |
|
}
|
|
|