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.
290 lines
10 KiB
290 lines
10 KiB
9 months ago
|
import 'package:flutter/services.dart';
|
||
|
import 'package:flutter_quill/flutter_quill.dart';
|
||
|
import 'package:flutter_quill/quill_delta.dart';
|
||
|
import 'package:flutter_quill/src/rules/insert.dart';
|
||
|
import 'package:test/test.dart';
|
||
|
|
||
|
void main() {
|
||
|
group('PreserveInlineStylesRule', () {
|
||
|
const rule = PreserveInlineStylesRule();
|
||
|
|
||
|
test('Data does not apply', () {
|
||
|
final delta = Delta()
|
||
|
..insert('data\n')
|
||
|
..insert('second\n', <String, dynamic>{'bold': true})
|
||
|
..insert('\n\nplain\n');
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 1), null);
|
||
|
expect(rule.apply(document, 0, data: '\n'), null);
|
||
|
});
|
||
|
|
||
|
test('Insert in text', () {
|
||
|
final delta = Delta()
|
||
|
..insert('data\n')
|
||
|
..insert('second\n', <String, dynamic>{'bold': true})
|
||
|
..insert('\n\nplain\n');
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 1, data: 'X', len: 0), null);
|
||
|
expect(
|
||
|
rule.apply(document, 6, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(6)
|
||
|
..insert('X', <String, dynamic>{'bold': true}));
|
||
|
expect(rule.apply(document, 16, data: 'X', len: 0), null,
|
||
|
reason: 'insertion with no attributes');
|
||
|
});
|
||
|
|
||
|
test('Insert at start of line', () {
|
||
|
final delta = Delta()
|
||
|
..insert('data\n')
|
||
|
..insert('second\n', <String, dynamic>{'bold': true})
|
||
|
..insert('\n\nplain\n');
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 'a', len: 0), null);
|
||
|
expect(
|
||
|
rule.apply(document, 5, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(5)
|
||
|
..insert('X', <String, dynamic>{'bold': true}));
|
||
|
expect(
|
||
|
rule.apply(document, 12, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(12)
|
||
|
..insert('X', <String, dynamic>{'bold': true}));
|
||
|
expect(
|
||
|
rule.apply(document, 13, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(13)
|
||
|
..insert('X', <String, dynamic>{'bold': true}));
|
||
|
expect(rule.apply(document, 14, data: 'X', len: 0), null,
|
||
|
reason: 'insertion before "plain" has no attributes');
|
||
|
});
|
||
|
|
||
|
test('Insert on first line of document with bold text', () {
|
||
|
final delta = Delta()..insert('data\n', <String, dynamic>{'bold': true});
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 'X', len: 0),
|
||
|
Delta()..insert('X', <String, dynamic>{'bold': true}),
|
||
|
reason: 'Insert at document start must pickup style for the line');
|
||
|
expect(
|
||
|
rule.apply(document, 1, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(1)
|
||
|
..insert('X', <String, dynamic>{'bold': true}));
|
||
|
});
|
||
|
|
||
|
test('Insert around image', () {
|
||
|
final delta = Delta()
|
||
|
..insert(<String, String>{'image': 'url'})
|
||
|
..insert('data\n');
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 'X', len: 0), null);
|
||
|
expect(rule.apply(document, 1, data: 'X', len: 0), null);
|
||
|
});
|
||
|
|
||
|
test('Insert around image with bold text', () {
|
||
|
final delta = Delta()
|
||
|
..insert(<String, String>{'image': 'url'})
|
||
|
..insert('data\n', <String, dynamic>{'bold': true});
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 'X', len: 0), null,
|
||
|
reason:
|
||
|
'Insert before image must pickup inline attribute for the image');
|
||
|
expect(
|
||
|
rule.apply(document, 1, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(1)
|
||
|
..insert('X', <String, dynamic>{'bold': true}),
|
||
|
reason:
|
||
|
'Insert after image must pickup style for text following the image');
|
||
|
});
|
||
|
|
||
|
test('Insert around image with inline attribute', () {
|
||
|
final delta = Delta()
|
||
|
..insert(
|
||
|
<String, String>{'image': 'url'}, <String, dynamic>{'bold': true})
|
||
|
..insert('data\n', <String, dynamic>{'bold': true});
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 'X', len: 0),
|
||
|
Delta()..insert('X', <String, dynamic>{'bold': true}),
|
||
|
reason: 'Insert before image must pickup style for the image');
|
||
|
expect(
|
||
|
rule.apply(document, 1, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(1)
|
||
|
..insert('X', <String, dynamic>{'bold': true}));
|
||
|
});
|
||
|
|
||
|
test('Replace in text', () {
|
||
|
final delta = Delta()
|
||
|
..insert('data\n')
|
||
|
..insert('second\n', <String, dynamic>{'bold': true})
|
||
|
..insert('\n\nplain\n');
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 'X', len: 1), null);
|
||
|
expect(
|
||
|
rule.apply(document, 5, data: 'X', len: 1),
|
||
|
Delta()
|
||
|
..retain(6)
|
||
|
..insert('X', <String, dynamic>{'bold': true}));
|
||
|
});
|
||
|
|
||
|
test('Insert around multiple images', () {
|
||
|
final delta = Delta()
|
||
|
..insert(
|
||
|
<String, String>{'image': 'url'}, <String, dynamic>{'bold': true})
|
||
|
..insert(<String, String>{'image': 'url2'},
|
||
|
<String, dynamic>{'italic': true})
|
||
|
..insert('data\n', <String, dynamic>{'underline': true});
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 'X', len: 0),
|
||
|
Delta()..insert('X', <String, dynamic>{'bold': true}));
|
||
|
expect(
|
||
|
rule.apply(document, 1, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(1)
|
||
|
..insert('X', <String, dynamic>{'italic': true}));
|
||
|
expect(
|
||
|
rule.apply(document, 2, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(2)
|
||
|
..insert('X', <String, dynamic>{'underline': true}));
|
||
|
});
|
||
|
|
||
|
test('Insert around mix of text and images', () {
|
||
|
final delta = Delta()
|
||
|
..insert(
|
||
|
<String, String>{'image': 'url'}, <String, dynamic>{'bold': true})
|
||
|
..insert('p\n')
|
||
|
..insert(<String, String>{'image': 'url2'},
|
||
|
<String, dynamic>{'italic': true})
|
||
|
..insert('data\n', <String, dynamic>{'underline': true});
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(
|
||
|
rule.apply(document, 3, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(3)
|
||
|
..insert('X', <String, dynamic>{'italic': true}));
|
||
|
});
|
||
|
|
||
|
test('Insert around images with NL', () {
|
||
|
final delta = Delta()
|
||
|
..insert('\n\n\n', <String, dynamic>{'strike': true})
|
||
|
..insert(
|
||
|
<String, String>{'image': 'url'}, <String, dynamic>{'bold': true})
|
||
|
..insert('\n\n\n', <String, dynamic>{'strike': true})
|
||
|
..insert(<String, String>{'image': 'url2'},
|
||
|
<String, dynamic>{'italic': true})
|
||
|
..insert('data\n', <String, dynamic>{'underline': true});
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(
|
||
|
rule.apply(document, 2, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(2)
|
||
|
..insert('X', <String, dynamic>{'strike': true}));
|
||
|
expect(
|
||
|
rule.apply(document, 6, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(6)
|
||
|
..insert('X', <String, dynamic>{'strike': true}));
|
||
|
expect(
|
||
|
rule.apply(document, 7, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(7)
|
||
|
..insert('X', <String, dynamic>{'italic': true}));
|
||
|
});
|
||
|
|
||
|
test('Exclude non-inline styles', () {
|
||
|
final delta = Delta()..insert('\n', <String, dynamic>{'list': 'ordered'});
|
||
|
final document = Document.fromDelta(delta);
|
||
|
expect(rule.apply(document, 0, data: 'X', len: 0), null);
|
||
|
});
|
||
|
|
||
|
test('Insert around non-inline styles', () {
|
||
|
final delta = Delta()
|
||
|
..insert('data\n')
|
||
|
..insert('first')
|
||
|
..insert('\n', <String, dynamic>{'list': 'ordered'})
|
||
|
..insert('A', <String, dynamic>{'bold': true})
|
||
|
..insert('B')
|
||
|
..insert('C', <String, dynamic>{'italic': true})
|
||
|
..insert('\n\n', <String, dynamic>{'list': 'ordered'})
|
||
|
..insert('D', <String, dynamic>{'strike': true})
|
||
|
..insert('\n', <String, dynamic>{'list': 'ordered'})
|
||
|
..insert(
|
||
|
<String, String>{'image': 'url'}, <String, dynamic>{'bold': true})
|
||
|
..insert('\n', <String, dynamic>{'list': 'ordered'})
|
||
|
..insert(' plain\n');
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 'X', len: 0), null);
|
||
|
expect(rule.apply(document, 5, data: 'X', len: 0), null,
|
||
|
reason: '1. plain text');
|
||
|
expect(
|
||
|
rule.apply(document, 11, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(11)
|
||
|
..insert('X', <String, dynamic>{'bold': true}),
|
||
|
reason: '2. bold text at start');
|
||
|
expect(
|
||
|
rule.apply(document, 15, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(15)
|
||
|
..insert('X', <String, dynamic>{'italic': true}),
|
||
|
reason: '3. blank entry gets style from end of previous line');
|
||
|
expect(
|
||
|
rule.apply(document, 16, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(16)
|
||
|
..insert('X', <String, dynamic>{'strike': true}),
|
||
|
reason: '4. strike text');
|
||
|
expect(
|
||
|
rule.apply(document, 18, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(18)
|
||
|
..insert('X', <String, dynamic>{'bold': true}),
|
||
|
reason: '5. bold image');
|
||
|
expect(rule.apply(document, 20, data: 'X', len: 0), null);
|
||
|
//
|
||
|
expect(rule.apply(document, 16, data: LogicalKeyboardKey.enter, len: 0),
|
||
|
null);
|
||
|
});
|
||
|
|
||
|
test('Insert around link, insert within link label', () {
|
||
|
final delta = Delta()
|
||
|
..insert(<String, String>{'image': 'imageUrl'},
|
||
|
<String, dynamic>{'link': 'linkURL'})
|
||
|
..insert('data\n')
|
||
|
..insert('link', <String, dynamic>{'link': 'linkURL', 'bold': true})
|
||
|
..insert('\n');
|
||
|
|
||
|
final document = Document.fromDelta(delta);
|
||
|
//
|
||
|
expect(rule.apply(document, 0, data: 'X', len: 0), Delta()..insert('X'));
|
||
|
expect(rule.apply(document, 1, data: 'X', len: 0), null);
|
||
|
expect(
|
||
|
rule.apply(document, 6, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(6)
|
||
|
..insert('X', <String, dynamic>{'bold': true}));
|
||
|
expect(
|
||
|
rule.apply(document, 7, data: 'X', len: 0),
|
||
|
Delta()
|
||
|
..retain(7)
|
||
|
..insert('X', <String, dynamic>{'link': 'linkURL', 'bold': true}),
|
||
|
reason: 'Insertion within link label updates label');
|
||
|
});
|
||
|
});
|
||
|
}
|