import Delta from 'quill-delta'; import { Range } from '../../../core/selection'; import Quill from '../../../core'; describe('Clipboard', function() { describe('events', function() { beforeEach(function() { this.quill = this.initialize(Quill, '
5678
'); this.quill.setSelection(2, 5); }); describe('paste', function() { beforeAll(function() { this.clipboardEvent = { clipboardData: { getData: type => type === 'text/html' ? '|' : '|', }, preventDefault: () => {}, }; }); it('pastes html data', function(done) { this.quill.clipboard.onCapturePaste(this.clipboardEvent); setTimeout(() => { expect(this.quill.root).toEqualHTML( '01|78
', ); expect(this.quill.getSelection()).toEqual(new Range(3)); done(); }, 2); }); it('pastes html data if present with file', function(done) { const upload = spyOn(this.quill.uploader, 'upload'); this.quill.clipboard.onCapturePaste( // eslint-disable-next-line prefer-object-spread Object.assign({}, this.clipboardEvent, { files: ['file '] }), ); setTimeout(() => { expect(upload).not.toHaveBeenCalled(); expect(this.quill.root).toEqualHTML( '01|78
', ); expect(this.quill.getSelection()).toEqual(new Range(3)); done(); }, 2); }); it('does not fire selection-change', function(done) { const change = jasmine.createSpy('change'); this.quill.on('selection-change', change); this.quill.clipboard.onCapturePaste(this.clipboardEvent); setTimeout(function() { expect(change).not.toHaveBeenCalled(); done(); }, 2); }); }); it('dangerouslyPasteHTML(html)', function() { this.quill.clipboard.dangerouslyPasteHTML('abcd'); expect(this.quill.root).toEqualHTML( 'abcd
', ); }); it('dangerouslyPasteHTML(index, html)', function() { this.quill.clipboard.dangerouslyPasteHTML(2, 'ab'); expect(this.quill.root).toEqualHTML( '5678
', ); }); }); describe('convert', function() { beforeEach(function() { const quill = this.initialize(Quill, ''); this.clipboard = quill.clipboard; }); it('plain text', function() { const delta = this.clipboard.convert({ html: 'simple plain text' }); expect(delta).toEqual(new Delta().insert('simple plain text')); }); it('whitespace', function() { const html = '0 1 2
'; const delta = this.clipboard.convert({ html }); expect(delta).toEqual( new Delta() .insert('0 ') .insert('1', { bold: true }) .insert(' 2'), ); }); it('intentional whitespace', function() { const html = '0 1 2'; const delta = this.clipboard.convert({ html }); expect(delta).toEqual( new Delta() .insert('0\u00a0') .insert('1', { bold: true }) .insert('\u00a02'), ); }); it('consecutive intentional whitespace', function() { const html = ' 1 '; const delta = this.clipboard.convert({ html }); expect(delta).toEqual( new Delta().insert('\u00a0\u00a01\u00a0\u00a0', { bold: true }), ); }); it('break', function() { const html = 'Body
'; const delta = this.clipboard.convert({ html }); expect(delta).toEqual( new Delta() .insert('Test\n', { header: 1 }) .insert('\n', { header: 2 }) .insert('Body'), ); }); it('mixed inline and block', function() { const delta = this.clipboard.convert({ html: '01 \n 23'; const delta = this.clipboard.convert({ html }); expect(delta).toEqual( new Delta().insert(' 01 \n 23 \n', { 'code-block': true }), ); }); it('nested list', function() { const delta = this.clipboard.convert({ html: '
A1 | A2 | A3 |
B1 | B3 |
01
34
', }); expect(delta).toEqual( new Delta() .insert('01\n') .insert({ video: '#' }) .insert('34'), ); }); it('block embeds within blocks', function() { const delta = this.clipboard.convert({ html: '67
', }); expect(delta).toEqual( new Delta() .insert('01\n', { header: 1 }) .insert({ video: '#' }, { header: 1 }) .insert('34\n', { header: 1 }) .insert('67'), ); }); it('wrapped block embed', function() { const delta = this.clipboard.convert({ html: '67
', }); expect(delta).toEqual( new Delta() .insert('01\n', { header: 1 }) .insert({ video: '#' }, { link: '/', header: 1 }) .insert('34\n', { header: 1 }) .insert('67'), ); }); it('wrapped block embed with siblings', function() { const delta = this.clipboard.convert({ html: '67
', }); expect(delta).toEqual( new Delta() .insert('01', { header: 1 }) .insert('a\n', { link: '/', header: 1 }) .insert({ video: '#' }, { link: '/', header: 1 }) .insert('b', { link: '/', header: 1 }) .insert('34\n', { header: 1 }) .insert('67'), ); }); it('attributor and style match', function() { const delta = this.clipboard.convert({ html: 'Test
', }); expect(delta).toEqual(new Delta().insert('Test\n', { direction: 'rtl' })); }); it('nested styles', function() { const delta = this.clipboard.convert({ html: 'Test', }); expect(delta).toEqual(new Delta().insert('Test', { color: 'blue' })); }); it('custom matcher', function() { this.clipboard.addMatcher(Node.TEXT_NODE, function(node, delta) { let index = 0; const regex = /https?:\/\/[^\s]+/g; let match = null; const composer = new Delta(); // eslint-disable-next-line no-cond-assign while ((match = regex.exec(node.data))) { composer.retain(match.index - index); index = regex.lastIndex; composer.retain(match[0].length, { link: match[0] }); } return delta.compose(composer); }); const delta = this.clipboard.convert({ html: 'http://github.com https://quilljs.com', }); const expected = new Delta() .insert('http://github.com', { link: 'http://github.com' }) .insert(' ') .insert('https://quilljs.com', { link: 'https://quilljs.com' }); expect(delta).toEqual(expected); }); it('does not execute javascript', function() { window.unsafeFunction = jasmine.createSpy('unsafeFunction'); const html = ""; this.clipboard.convert({ html }); expect(window.unsafeFunction).not.toHaveBeenCalled(); delete window.unsafeFunction; }); it('xss', function() { const delta = this.clipboard.convert({ html: '', }); expect(delta).toEqual(new Delta().insert('')); }); }); });