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', {'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', {'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', {'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', {'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', {'bold': true})); expect( rule.apply(document, 12, data: 'X', len: 0), Delta() ..retain(12) ..insert('X', {'bold': true})); expect( rule.apply(document, 13, data: 'X', len: 0), Delta() ..retain(13) ..insert('X', {'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', {'bold': true}); final document = Document.fromDelta(delta); // expect(rule.apply(document, 0, data: 'X', len: 0), Delta()..insert('X', {'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', {'bold': true})); }); test('Insert around image', () { final delta = Delta() ..insert({'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({'image': 'url'}) ..insert('data\n', {'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', {'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( {'image': 'url'}, {'bold': true}) ..insert('data\n', {'bold': true}); final document = Document.fromDelta(delta); // expect(rule.apply(document, 0, data: 'X', len: 0), Delta()..insert('X', {'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', {'bold': true})); }); test('Replace in text', () { final delta = Delta() ..insert('data\n') ..insert('second\n', {'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', {'bold': true})); }); test('Insert around multiple images', () { final delta = Delta() ..insert( {'image': 'url'}, {'bold': true}) ..insert({'image': 'url2'}, {'italic': true}) ..insert('data\n', {'underline': true}); final document = Document.fromDelta(delta); // expect(rule.apply(document, 0, data: 'X', len: 0), Delta()..insert('X', {'bold': true})); expect( rule.apply(document, 1, data: 'X', len: 0), Delta() ..retain(1) ..insert('X', {'italic': true})); expect( rule.apply(document, 2, data: 'X', len: 0), Delta() ..retain(2) ..insert('X', {'underline': true})); }); test('Insert around mix of text and images', () { final delta = Delta() ..insert( {'image': 'url'}, {'bold': true}) ..insert('p\n') ..insert({'image': 'url2'}, {'italic': true}) ..insert('data\n', {'underline': true}); final document = Document.fromDelta(delta); // expect( rule.apply(document, 3, data: 'X', len: 0), Delta() ..retain(3) ..insert('X', {'italic': true})); }); test('Insert around images with NL', () { final delta = Delta() ..insert('\n\n\n', {'strike': true}) ..insert( {'image': 'url'}, {'bold': true}) ..insert('\n\n\n', {'strike': true}) ..insert({'image': 'url2'}, {'italic': true}) ..insert('data\n', {'underline': true}); final document = Document.fromDelta(delta); // expect( rule.apply(document, 2, data: 'X', len: 0), Delta() ..retain(2) ..insert('X', {'strike': true})); expect( rule.apply(document, 6, data: 'X', len: 0), Delta() ..retain(6) ..insert('X', {'strike': true})); expect( rule.apply(document, 7, data: 'X', len: 0), Delta() ..retain(7) ..insert('X', {'italic': true})); }); test('Exclude non-inline styles', () { final delta = Delta()..insert('\n', {'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', {'list': 'ordered'}) ..insert('A', {'bold': true}) ..insert('B') ..insert('C', {'italic': true}) ..insert('\n\n', {'list': 'ordered'}) ..insert('D', {'strike': true}) ..insert('\n', {'list': 'ordered'}) ..insert( {'image': 'url'}, {'bold': true}) ..insert('\n', {'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', {'bold': true}), reason: '2. bold text at start'); expect( rule.apply(document, 15, data: 'X', len: 0), Delta() ..retain(15) ..insert('X', {'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', {'strike': true}), reason: '4. strike text'); expect( rule.apply(document, 18, data: 'X', len: 0), Delta() ..retain(18) ..insert('X', {'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({'image': 'imageUrl'}, {'link': 'linkURL'}) ..insert('data\n') ..insert('link', {'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', {'bold': true})); expect( rule.apply(document, 7, data: 'X', len: 0), Delta() ..retain(7) ..insert('X', {'link': 'linkURL', 'bold': true}), reason: 'Insertion within link label updates label'); }); }); }