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 systems.
189 lines (174 loc) • 7.81 kB
JavaScript
import { module } from 'substance-test'
import { documentHelpers } from 'substance'
import fixture from './fixture/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'
const test = module('documentHelpers')
test("Get annotations for selection", (t) => {
let 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})
let 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("Get text for null selection.", (t) => {
let 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("Get text for property selection", (t) => {
let doc = fixture(simple)
let sel = doc.createSelection({
type: "property",
path: ["p1", "content"],
startOffset: 0,
endOffset: 5
})
t.equal(documentHelpers.getTextForSelection(doc, sel), "01234")
t.end()
})
test("Get text for container selection", (t) => {
let doc = fixture(simple)
let sel = doc.createSelection({
type: "container",
containerId: "body",
startPath: ["p1", "content"],
startOffset: 5,
endPath: ["p2", "content"],
endOffset: 5
})
t.equal(documentHelpers.getTextForSelection(doc, sel), "56789\n01234")
t.end()
})
test("Get change from document", (t) => {
let doc = fixture(simple)
doc.create({ type: 'strong', id: 's1', path: ["p1", "content"], startOffset: 0, endOffset: 1})
let change = documentHelpers.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', 's1', 'body'], '.. in correct order')
t.end()
})
test("deleteNode()", (t) => {
let 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.deleteNode(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.deleteNode(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("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("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.nil(doc.get('l1-1'), 'first list item should have been deleted')
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("isContainerAnnotation()", (t) => {
let doc = fixture(simple)
t.ok(documentHelpers.isContainerAnnotation(doc, 'test-container-anno'))
t.notOk(documentHelpers.isContainerAnnotation(doc, 'strong'))
t.end()
})
test("Get container annotations for property selection", (t) => {
let doc = fixture(containerAnnoSample)
let sel = doc.createSelection({
type: 'property',
path: ['p3', 'content'],
startOffset: 1,
endOffset: 6
})
let annos
// without options
annos = documentHelpers.getContainerAnnotationsForSelection(doc, sel, 'body')
t.equal(annos.length, 1, 'There should be one container anno')
// filtered by type
annos = documentHelpers.getContainerAnnotationsForSelection(doc, sel, 'body', {
type: 'test-container-anno'
})
t.equal(annos.length, 1, 'There should be one container anno')
t.end()
})