UNPKG

substance

Version:

Substance is a JavaScript library for web-based content editing. It provides building blocks for realizing custom text editors and web-based publishing system. It is developed to power our online editing platform [Substance](http://substance.io).

189 lines (175 loc) 8.15 kB
import { test } from 'substance-test' import { documentHelpers, getChangeFromDocument } from 'substance' import fixture from './shared/createTestArticle' import simple from './fixture/simple' import containerAnnoSample from './fixture/containerAnnoSample' import { _l1, _l11, _l12, _l13, LI1_TEXT, LI2_TEXT, LI3_TEXT } from './fixture/samples' test('documentHelpers: Get annotations for selection', (t) => { const doc = fixture(simple) const path = ['p1', 'content'] doc.create({ type: 'strong', path, startOffset: 0, endOffset: 1 }) doc.create({ type: 'emphasis', path, startOffset: 2, endOffset: 3 }) doc.create({ type: 'strong', path, startOffset: 5, endOffset: 6 }) // this lies outside of selection doc.create({ type: 'strong', path, startOffset: 6, endOffset: 7 }) const sel = doc.createSelection({ type: 'property', path, startOffset: 0, endOffset: 5 }) let annos = documentHelpers.getPropertyAnnotationsForSelection(doc, sel) t.equal(annos.length, 3, 'should return 3 annos for selection') // filtered by type annos = documentHelpers.getPropertyAnnotationsForSelection(doc, sel, { type: 'emphasis' }) t.equal(annos.length, 1, 'should return one anno') t.equal(annos[0].type, 'emphasis', '.. of type emphasis') t.end() }) test('documentHelpers: Get text for null selection.', (t) => { const doc = fixture(simple) t.equal(documentHelpers.getTextForSelection(doc, null), '', 'Should be empty for null selection.') t.equal(documentHelpers.getTextForSelection(doc, doc.createSelection(null)), '', 'Should be empty for null selection.') t.end() }) test('documentHelpers: Get text for property selection', (t) => { const doc = fixture(simple) const sel = doc.createSelection({ type: 'property', path: ['p1', 'content'], startOffset: 0, endOffset: 5 }) t.equal(documentHelpers.getTextForSelection(doc, sel), '01234') t.end() }) test('documentHelpers: Get text for container selection', (t) => { const doc = fixture(simple) const sel = doc.createSelection({ type: 'container', containerPath: ['body', 'nodes'], startPath: ['p1', 'content'], startOffset: 5, endPath: ['p2', 'content'], endOffset: 5 }) t.equal(documentHelpers.getTextForSelection(doc, sel), '56789\n01234') t.end() }) test('documentHelpers: Get change from document', (t) => { const doc = fixture(simple) doc.create({ type: 'strong', id: 's1', path: ['p1', 'content'], startOffset: 0, endOffset: 1 }) const change = getChangeFromDocument(doc) t.equal(change.ops.length, 6, 'There should be 6 operations') t.deepEqual(change.ops.map(op => op.type), new Array(6).fill('create'), 'all should be create ops') t.deepEqual(change.ops.map(op => op.path[0]), ['p1', 'p2', 'p3', 'p4', 'body', 's1'], '.. in correct order') t.end() }) test('documentHelpers: deepDeleteNode()', (t) => { const doc = fixture(simple) ;[_l1, _l11].forEach(f => f(doc, doc.get('body'))) doc.create({ type: 'strong', id: 's1', path: ['p1', 'content'], startOffset: 0, endOffset: 1 }) documentHelpers.deepDeleteNode(doc, doc.get('p1')) t.nil(doc.get('p1'), 'node should have been deleted') t.nil(doc.get('s1'), 'annotation should have been deleted too') documentHelpers.deepDeleteNode(doc, doc.get('l1')) t.nil(doc.get('l1'), 'node should have been deleted') t.nil(doc.get('l1-1'), 'list item should have been deleted too') t.end() }) test('documentHelpers: deleteTextRange()', (t) => { const path = ['p1', 'content'] // anno is after let doc = fixture(simple) let s1 = doc.create({ type: 'strong', id: 's1', path: ['p1', 'content'], startOffset: 5, endOffset: 6 }) documentHelpers.deleteTextRange(doc, { path, offset: 0 }, { path, offset: 2 }) t.deepEqual([s1.start.offset, s1.end.offset], [3, 4], 'offsets should have been shifted') // anno is inside doc = fixture(simple) s1 = doc.create({ type: 'strong', id: 's1', path: ['p1', 'content'], startOffset: 3, endOffset: 4 }) documentHelpers.deleteTextRange(doc, { path, offset: 2 }, { path, offset: 5 }) t.nil(doc.get('s1'), 'annotation should have been deleted') // anno.start between and anno.end after doc = fixture(simple) s1 = doc.create({ type: 'strong', id: 's1', path: ['p1', 'content'], startOffset: 3, endOffset: 6 }) documentHelpers.deleteTextRange(doc, { path, offset: 2 }, { path, offset: 5 }) t.deepEqual([s1.start.offset, s1.end.offset], [2, 3], 'offsets should have been updated correctly') // anno.start same and anno.end after doc = fixture(simple) s1 = doc.create({ type: 'strong', id: 's1', path: ['p1', 'content'], startOffset: 3, endOffset: 6 }) documentHelpers.deleteTextRange(doc, { path, offset: 3 }, { path, offset: 5 }) t.deepEqual([s1.start.offset, s1.end.offset], [3, 4], 'offsets should have been updated correctly') // anno.start before and anno.end between doc = fixture(simple) s1 = doc.create({ type: 'strong', id: 's1', path: ['p1', 'content'], startOffset: 1, endOffset: 3 }) documentHelpers.deleteTextRange(doc, { path, offset: 2 }, { path, offset: 4 }) t.deepEqual([s1.start.offset, s1.end.offset], [1, 2], 'offsets should have been updated correctly') // anno.start before and anno.end after doc = fixture(simple) s1 = doc.create({ type: 'strong', id: 's1', path: ['p1', 'content'], startOffset: 1, endOffset: 6 }) documentHelpers.deleteTextRange(doc, { path, offset: 2 }, { path, offset: 4 }) t.deepEqual([s1.start.offset, s1.end.offset], [1, 4], 'offsets should have been updated correctly') t.end() }) test('documentHelpers: deleteListRange()', (t) => { // first and last not entirely selected, and no item in between let doc = fixture(simple) ;[_l1, _l11, _l12, _l13].forEach(f => f(doc, doc.get('body'))) let l1 = doc.get('l1') documentHelpers.deleteListRange(doc, l1, { path: ['l1-1', 'content'], offset: 2 }, { path: ['l1-2', 'content'], offset: 3 } ) t.nil(doc.get('l1-2'), 'second list item should have been deleted') t.equal(doc.get('l1-1').getText(), LI1_TEXT.slice(0, 2) + LI2_TEXT.slice(3), 'list items should have been merged') // item in between doc = fixture(simple) ;[_l1, _l11, _l12, _l13].forEach(f => f(doc, doc.get('body'))) l1 = doc.get('l1') documentHelpers.deleteListRange(doc, l1, { path: ['l1-1', 'content'], offset: 2 }, { path: ['l1-3', 'content'], offset: 3 } ) t.nil(doc.get('l1-2'), 'second list item should have been deleted') t.nil(doc.get('l1-3'), 'third list item should have been deleted') t.equal(doc.get('l1-1').getText(), LI1_TEXT.slice(0, 2) + LI3_TEXT.slice(3), 'list items should have been merged') // entirely selected doc = fixture(simple) ;[_l1, _l11, _l12, _l13].forEach(f => f(doc, doc.get('body'))) l1 = doc.get('l1') documentHelpers.deleteListRange(doc, l1, { path: ['l1-1', 'content'], offset: 0 }, { path: ['l1-3', 'content'], offset: LI3_TEXT } ) t.notNil(doc.get('l1-1'), 'first list-item should remain') t.equal(doc.get(['l1-1', 'content']), '', '.. but left empty') t.nil(doc.get('l1-2'), 'second list item should have been deleted') t.nil(doc.get('l1-3'), 'third list item should have been deleted') t.end() }) test('documentHelpers: isContainerAnnotation()', (t) => { const doc = fixture(simple) t.ok(documentHelpers.isContainerAnnotation(doc, 'test-container-anno')) t.notOk(documentHelpers.isContainerAnnotation(doc, 'strong')) t.end() }) test('documentHelpers: Get container annotations for property selection', (t) => { const doc = fixture(containerAnnoSample) const body = doc.get('body') const sel = doc.createSelection({ type: 'property', path: ['p3', 'content'], startOffset: 1, endOffset: 6 }) let annos // without options annos = documentHelpers.getContainerAnnotationsForSelection(doc, sel, body.getContentPath()) t.equal(annos.length, 1, 'There should be one container anno') // filtered by type annos = documentHelpers.getContainerAnnotationsForSelection(doc, sel, body.getContentPath(), { type: 'test-container-anno' }) t.equal(annos.length, 1, 'There should be one container anno') t.end() })