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.
191 lines
7.4 KiB
191 lines
7.4 KiB
9 months ago
|
import 'package:flutter/material.dart';
|
||
|
import 'package:flutter_quill/flutter_quill.dart';
|
||
|
import 'package:flutter_quill/quill_delta.dart';
|
||
|
import 'package:test/test.dart';
|
||
|
|
||
|
void main() {
|
||
|
WidgetsFlutterBinding.ensureInitialized();
|
||
|
|
||
|
group('copy', () {
|
||
|
const testDocumentContents = 'data';
|
||
|
late QuillController controller;
|
||
|
|
||
|
setUp(() {
|
||
|
controller = QuillController.basic()
|
||
|
..compose(Delta()..insert(testDocumentContents),
|
||
|
const TextSelection.collapsed(offset: 0), ChangeSource.local);
|
||
|
});
|
||
|
|
||
|
test('clipboardSelection empty', () {
|
||
|
expect(controller.clipboardSelection(true), false,
|
||
|
reason: 'No effect when no selection');
|
||
|
expect(controller.clipboardSelection(false), false);
|
||
|
});
|
||
|
|
||
|
test('clipboardSelection', () {
|
||
|
controller
|
||
|
..replaceText(0, 4, 'bold plain italic', null)
|
||
|
..formatText(0, 4, Attribute.bold)
|
||
|
..formatText(11, 17, Attribute.italic)
|
||
|
..updateSelection(const TextSelection(baseOffset: 2, extentOffset: 14),
|
||
|
ChangeSource.local);
|
||
|
//
|
||
|
expect(controller.clipboardSelection(true), true);
|
||
|
expect(controller.document.length, 18,
|
||
|
reason: 'Copy does not change the document');
|
||
|
expect(controller.clipboardSelection(false), true);
|
||
|
expect(controller.document.length, 6, reason: 'Cut changes the document');
|
||
|
//
|
||
|
controller
|
||
|
..readOnly = true
|
||
|
..updateSelection(const TextSelection(baseOffset: 2, extentOffset: 4),
|
||
|
ChangeSource.local);
|
||
|
expect(controller.selection.isCollapsed, false);
|
||
|
expect(controller.clipboardSelection(true), true);
|
||
|
expect(controller.document.length, 6);
|
||
|
expect(controller.clipboardSelection(false), false);
|
||
|
expect(controller.document.length, 6,
|
||
|
reason: 'Cut not permitted on readOnly document');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
group('paste', () {
|
||
|
test('Plain', () async {
|
||
|
final controller = QuillController.basic()
|
||
|
..compose(Delta()..insert('[]'),
|
||
|
const TextSelection.collapsed(offset: 0), ChangeSource.local)
|
||
|
..updateSelection(
|
||
|
const TextSelection.collapsed(offset: 1), ChangeSource.local);
|
||
|
//
|
||
|
expect(controller.document.toPlainText(), '[]\n');
|
||
|
expect(controller.pasteUsingPlainOrDelta('insert'), true);
|
||
|
expect(controller.document.toPlainText(), '[insert]\n');
|
||
|
});
|
||
|
|
||
|
test('Plain lines', () async {
|
||
|
final controller = QuillController.basic()
|
||
|
..compose(Delta()..insert('[]'),
|
||
|
const TextSelection.collapsed(offset: 0), ChangeSource.local)
|
||
|
..updateSelection(
|
||
|
const TextSelection.collapsed(offset: 1), ChangeSource.local);
|
||
|
//
|
||
|
expect(controller.document.toPlainText(), '[]\n');
|
||
|
expect(controller.pasteUsingPlainOrDelta('1\n2\n3\n'), true);
|
||
|
expect(controller.document.toPlainText(), '[1\n2\n3\n]\n');
|
||
|
});
|
||
|
|
||
|
test('Paste from external', () async {
|
||
|
final source = QuillController.basic()
|
||
|
..compose(Delta()..insert('Plain text'),
|
||
|
const TextSelection.collapsed(offset: 0), ChangeSource.local)
|
||
|
..updateSelection(const TextSelection(baseOffset: 4, extentOffset: 8),
|
||
|
ChangeSource.local);
|
||
|
assert(source.clipboardSelection(true));
|
||
|
expect(source.pastePlainText, 'n te');
|
||
|
//
|
||
|
final controller = QuillController.basic()
|
||
|
..compose(Delta()..insert('[]'),
|
||
|
const TextSelection.collapsed(offset: 0), ChangeSource.local)
|
||
|
..updateSelection(
|
||
|
const TextSelection.collapsed(offset: 1), ChangeSource.local);
|
||
|
//
|
||
|
expect(controller.pasteUsingPlainOrDelta('insert'), true,
|
||
|
reason: 'External paste');
|
||
|
expect(controller.document.toPlainText(), '[insert]\n');
|
||
|
});
|
||
|
|
||
|
test('Delta simple', () async {
|
||
|
final source = QuillController.basic()
|
||
|
..compose(Delta()..insert('Plain text'),
|
||
|
const TextSelection.collapsed(offset: 0), ChangeSource.local)
|
||
|
..formatText(6, 8, Attribute.bold)
|
||
|
..updateSelection(const TextSelection(baseOffset: 4, extentOffset: 8),
|
||
|
ChangeSource.local);
|
||
|
assert(source.clipboardSelection(true));
|
||
|
expect(source.pastePlainText, 'n te');
|
||
|
expect(
|
||
|
source.pasteDelta,
|
||
|
Delta()
|
||
|
..insert('n ')
|
||
|
..insert('te', {'bold': true}));
|
||
|
//
|
||
|
final controller = QuillController.basic()
|
||
|
..compose(Delta()..insert('[]'),
|
||
|
const TextSelection.collapsed(offset: 0), ChangeSource.local)
|
||
|
..updateSelection(
|
||
|
const TextSelection.collapsed(offset: 1), ChangeSource.local);
|
||
|
//
|
||
|
expect(controller.pasteUsingPlainOrDelta('n te'), true,
|
||
|
reason: 'Internal paste');
|
||
|
expect(controller.document.toPlainText(), '[n te]\n');
|
||
|
expect(
|
||
|
controller.document.toDelta(),
|
||
|
Delta()
|
||
|
..insert('[n ')
|
||
|
..insert('te', {'bold': true})
|
||
|
..insert(']\n'));
|
||
|
expect(controller.selection, const TextSelection.collapsed(offset: 5));
|
||
|
});
|
||
|
|
||
|
test('Delta multi line', () async {
|
||
|
const blockAttribute = Attribute.ol;
|
||
|
const plainSelection = 'BC\nDEF\nGHI\nJK';
|
||
|
final source = QuillController.basic()
|
||
|
..compose(Delta()..insert('ABC\nDEF\nGHI\nJKL'),
|
||
|
const TextSelection.collapsed(offset: 0), ChangeSource.local)
|
||
|
..formatText(1, 1, Attribute.underline) // ABC with B underlined
|
||
|
..formatText(4, 0, blockAttribute) // 1. DEF with E in italic
|
||
|
..formatText(5, 1, Attribute.italic)
|
||
|
..formatText(8, 0, blockAttribute) // 2. GHI with H as inline code
|
||
|
..formatText(9, 1, Attribute.inlineCode)
|
||
|
..formatText(13, 1, Attribute.strikeThrough) // JKL with K strikethrough
|
||
|
..updateSelection(const TextSelection(baseOffset: 1, extentOffset: 14),
|
||
|
ChangeSource.local);
|
||
|
//
|
||
|
assert(source.clipboardSelection(true));
|
||
|
expect(source.pastePlainText, plainSelection);
|
||
|
expect(
|
||
|
source.pasteDelta,
|
||
|
Delta()
|
||
|
..insert('B', {'underline': true})
|
||
|
..insert('C\nD')
|
||
|
..insert('E', {'italic': true})
|
||
|
..insert('F')
|
||
|
..insert('\n', {'list': 'ordered'})
|
||
|
..insert('G')
|
||
|
..insert('H', {'code': true})
|
||
|
..insert('I')
|
||
|
..insert('\n', {'list': 'ordered'})
|
||
|
..insert('J')
|
||
|
..insert('K', {'strike': true}));
|
||
|
//
|
||
|
final controller = QuillController.basic()
|
||
|
..compose(Delta()..insert('[]'),
|
||
|
const TextSelection.collapsed(offset: 0), ChangeSource.local)
|
||
|
..updateSelection(
|
||
|
const TextSelection.collapsed(offset: 1), ChangeSource.local);
|
||
|
//
|
||
|
expect(controller.pasteUsingPlainOrDelta(plainSelection), true,
|
||
|
reason: 'Internal paste');
|
||
|
expect(controller.document.toPlainText(), '[$plainSelection]\n');
|
||
|
expect(
|
||
|
controller.document.toDelta(),
|
||
|
Delta()
|
||
|
..insert('[')
|
||
|
..insert('B', {'underline': true})
|
||
|
..insert('C\nD')
|
||
|
..insert('E', {'italic': true})
|
||
|
..insert('F')
|
||
|
..insert('\n', {'list': 'ordered'})
|
||
|
..insert('G')
|
||
|
..insert('H', {'code': true})
|
||
|
..insert('I')
|
||
|
..insert('\n', {'list': 'ordered'})
|
||
|
..insert('J')
|
||
|
..insert('K', {'strike': true})
|
||
|
..insert(']\n'));
|
||
|
expect(controller.selection, const TextSelection.collapsed(offset: 14));
|
||
|
});
|
||
|
});
|
||
|
}
|