@studysync/draft-js-modifiers 0.4.11 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/insertBlockAfter.js +3 -1
- package/es/insertBlockBefore.js +3 -1
- package/flow/stub/__dev__.js +3 -0
- package/insertBlockAfter.js +3 -1
- package/insertBlockBefore.js +3 -1
- package/package.json +6 -3
- package/script/add-module.js +48 -0
- package/src/addBlock.js +98 -0
- package/src/adjustBlockDepth.js +21 -0
- package/src/atEndOfBlock.js +10 -0
- package/src/atStartOfBlock.js +7 -0
- package/src/changeBlockType.js +19 -0
- package/src/getAllEntities.js +14 -0
- package/src/getEntitiesForBlock.js +29 -0
- package/src/getEntitiesForSelection.js +20 -0
- package/src/getSelectedText.js +11 -0
- package/src/getSimilarAdjacentBlocks.js +53 -0
- package/src/index.js +42 -0
- package/src/insertAtomicBlock.js +23 -0
- package/src/insertBlockAfter.js +42 -0
- package/src/insertBlockBefore.js +42 -0
- package/src/insertEmptyBlock.js +12 -0
- package/src/insertEntity.js +56 -0
- package/src/insertNewBlock.js +61 -0
- package/src/insertText.js +23 -0
- package/src/mergeBlockData.js +13 -0
- package/src/mergeBlockDataByKey.js +12 -0
- package/src/mergeEntityData.js +13 -0
- package/src/modifyBlock.js +20 -0
- package/src/modifyBlockByKey.js +19 -0
- package/src/moveCaretAfterBlock.js +26 -0
- package/src/moveCaretToEnd.js +20 -0
- package/src/removeBlock.js +43 -0
- package/src/removeBlockStyle.js +17 -0
- package/src/removeEntity.js +38 -0
- package/src/removeInlineStyles.js +29 -0
- package/src/resetBlock.js +29 -0
- package/src/selectAll.js +15 -0
- package/src/selectBlockByKey.js +20 -0
- package/src/setBlockData.js +14 -0
- package/src/toggleBlockStyle.js +33 -0
- package/src/toggleBlockType.js +12 -0
- package/src/toggleEntity.js +11 -0
- package/src/toggleInlineStyle.js +11 -0
- package/src/trimEditorState.js +41 -0
- package/src/utils/getCurrentBlock.js +10 -0
- package/src/utils/numbers.js +3 -0
- package/test/adjustBlockDepth.js +45 -0
- package/test/export.js +14 -0
- package/test/fixtures/createEditorState.js +12 -0
- package/test/fixtures/omitBlockKeysFromRawContent.js +9 -0
- package/test/insertAtomicBlock.js +89 -0
- package/test/insertEmptyBlock.js +65 -0
- package/test/insertNewBlock.js +68 -0
- package/test/insertText.js +58 -0
- package/test/mergeBlockData.js +40 -0
- package/test/mergeBlockDataByKey.js +103 -0
- package/test/mergeEntityData.js +49 -0
- package/test/modifyBlock.js +52 -0
- package/test/modifyBlockByKey.js +91 -0
- package/test/removeBlockStyle.js +52 -0
- package/test/removeInlineStyles.js +68 -0
- package/test/resetBlock.js +83 -0
- package/test/toggleBlockType.js +4 -0
- package/test/toggleEntity.js +4 -0
- package/test/toggleInlineStyle.js +4 -0
package/es/insertBlockAfter.js
CHANGED
|
@@ -37,6 +37,7 @@ var insertBlockAfter = function insertBlockAfter(editorState, keyBefore, blockPa
|
|
|
37
37
|
type: 'unstyled',
|
|
38
38
|
text: ''
|
|
39
39
|
}, blockParams));
|
|
40
|
+
var modified = false;
|
|
40
41
|
var contentState = editorState.getCurrentContent();
|
|
41
42
|
var oldBlockMap = contentState.getBlockMap();
|
|
42
43
|
|
|
@@ -54,6 +55,7 @@ var insertBlockAfter = function insertBlockAfter(editorState, keyBefore, blockPa
|
|
|
54
55
|
|
|
55
56
|
if (keyBefore === k) {
|
|
56
57
|
map.set(newBlock.key, newBlock);
|
|
58
|
+
modified = true;
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
} catch (err) {
|
|
@@ -63,7 +65,7 @@ var insertBlockAfter = function insertBlockAfter(editorState, keyBefore, blockPa
|
|
|
63
65
|
}
|
|
64
66
|
});
|
|
65
67
|
|
|
66
|
-
return _draftJs.EditorState.push(editorState, _draftJs.ContentState.createFromBlockArray(Array.from(newBlockMap.values())).set('selectionBefore', contentState.getSelectionBefore()).set('selectionAfter', contentState.getSelectionAfter()));
|
|
68
|
+
return modified ? _draftJs.EditorState.push(editorState, _draftJs.ContentState.createFromBlockArray(Array.from(newBlockMap.values())).set('selectionBefore', contentState.getSelectionBefore()).set('selectionAfter', contentState.getSelectionAfter()), 'split-block') : editorState;
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
var _default = insertBlockAfter;
|
package/es/insertBlockBefore.js
CHANGED
|
@@ -37,6 +37,7 @@ var insertBlockBefore = function insertBlockBefore(editorState, keyBefore, block
|
|
|
37
37
|
type: 'unstyled',
|
|
38
38
|
text: ''
|
|
39
39
|
}, blockParams));
|
|
40
|
+
var modified = false;
|
|
40
41
|
var contentState = editorState.getCurrentContent();
|
|
41
42
|
var oldBlockMap = contentState.getBlockMap();
|
|
42
43
|
|
|
@@ -52,6 +53,7 @@ var insertBlockBefore = function insertBlockBefore(editorState, keyBefore, block
|
|
|
52
53
|
|
|
53
54
|
if (keyBefore === k) {
|
|
54
55
|
map.set(newBlock.key, newBlock);
|
|
56
|
+
modified = true;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
map.set(k, v);
|
|
@@ -63,7 +65,7 @@ var insertBlockBefore = function insertBlockBefore(editorState, keyBefore, block
|
|
|
63
65
|
}
|
|
64
66
|
});
|
|
65
67
|
|
|
66
|
-
return _draftJs.EditorState.push(editorState, _draftJs.ContentState.createFromBlockArray(Array.from(newBlockMap.values())).set('selectionBefore', contentState.getSelectionBefore()).set('selectionAfter', contentState.getSelectionAfter()));
|
|
68
|
+
return modified ? _draftJs.EditorState.push(editorState, _draftJs.ContentState.createFromBlockArray(Array.from(newBlockMap.values())).set('selectionBefore', contentState.getSelectionBefore()).set('selectionAfter', contentState.getSelectionAfter()), 'split-block') : editorState;
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
var _default = insertBlockBefore;
|
package/insertBlockAfter.js
CHANGED
|
@@ -37,6 +37,7 @@ var insertBlockAfter = function insertBlockAfter(editorState, keyBefore, blockPa
|
|
|
37
37
|
type: 'unstyled',
|
|
38
38
|
text: ''
|
|
39
39
|
}, blockParams));
|
|
40
|
+
var modified = false;
|
|
40
41
|
var contentState = editorState.getCurrentContent();
|
|
41
42
|
var oldBlockMap = contentState.getBlockMap();
|
|
42
43
|
|
|
@@ -54,6 +55,7 @@ var insertBlockAfter = function insertBlockAfter(editorState, keyBefore, blockPa
|
|
|
54
55
|
|
|
55
56
|
if (keyBefore === k) {
|
|
56
57
|
map.set(newBlock.key, newBlock);
|
|
58
|
+
modified = true;
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
} catch (err) {
|
|
@@ -63,7 +65,7 @@ var insertBlockAfter = function insertBlockAfter(editorState, keyBefore, blockPa
|
|
|
63
65
|
}
|
|
64
66
|
});
|
|
65
67
|
|
|
66
|
-
return _draftJs.EditorState.push(editorState, _draftJs.ContentState.createFromBlockArray(Array.from(newBlockMap.values())).set('selectionBefore', contentState.getSelectionBefore()).set('selectionAfter', contentState.getSelectionAfter()));
|
|
68
|
+
return modified ? _draftJs.EditorState.push(editorState, _draftJs.ContentState.createFromBlockArray(Array.from(newBlockMap.values())).set('selectionBefore', contentState.getSelectionBefore()).set('selectionAfter', contentState.getSelectionAfter()), 'split-block') : editorState;
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
var _default = insertBlockAfter;
|
package/insertBlockBefore.js
CHANGED
|
@@ -37,6 +37,7 @@ var insertBlockBefore = function insertBlockBefore(editorState, keyBefore, block
|
|
|
37
37
|
type: 'unstyled',
|
|
38
38
|
text: ''
|
|
39
39
|
}, blockParams));
|
|
40
|
+
var modified = false;
|
|
40
41
|
var contentState = editorState.getCurrentContent();
|
|
41
42
|
var oldBlockMap = contentState.getBlockMap();
|
|
42
43
|
|
|
@@ -52,6 +53,7 @@ var insertBlockBefore = function insertBlockBefore(editorState, keyBefore, block
|
|
|
52
53
|
|
|
53
54
|
if (keyBefore === k) {
|
|
54
55
|
map.set(newBlock.key, newBlock);
|
|
56
|
+
modified = true;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
map.set(k, v);
|
|
@@ -63,7 +65,7 @@ var insertBlockBefore = function insertBlockBefore(editorState, keyBefore, block
|
|
|
63
65
|
}
|
|
64
66
|
});
|
|
65
67
|
|
|
66
|
-
return _draftJs.EditorState.push(editorState, _draftJs.ContentState.createFromBlockArray(Array.from(newBlockMap.values())).set('selectionBefore', contentState.getSelectionBefore()).set('selectionAfter', contentState.getSelectionAfter()));
|
|
68
|
+
return modified ? _draftJs.EditorState.push(editorState, _draftJs.ContentState.createFromBlockArray(Array.from(newBlockMap.values())).set('selectionBefore', contentState.getSelectionBefore()).set('selectionAfter', contentState.getSelectionAfter()), 'split-block') : editorState;
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
var _default = insertBlockBefore;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studysync/draft-js-modifiers",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "Modular state modifiers for Draft.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -59,7 +59,10 @@
|
|
|
59
59
|
"eslint-plugin-flowtype": "^2.47.1",
|
|
60
60
|
"flow-bin": "^0.70.0",
|
|
61
61
|
"nyc": "^11.8.0",
|
|
62
|
-
"react": "
|
|
63
|
-
"react-dom": "
|
|
62
|
+
"react": ">=17",
|
|
63
|
+
"react-dom": ">=17"
|
|
64
|
+
},
|
|
65
|
+
"resolutions": {
|
|
66
|
+
"graceful-fs": "4.2.4"
|
|
64
67
|
}
|
|
65
68
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const n = process.argv[2]
|
|
4
|
+
if (!n) {
|
|
5
|
+
throw new Error('should must be called with name. `npm run add -- someModule`')
|
|
6
|
+
}
|
|
7
|
+
const createFile = (name, dir, template) => {
|
|
8
|
+
const file = path.resolve(__dirname, '..', dir, `${name}.js`)
|
|
9
|
+
fs.writeFileSync(file, template.join('\n'))
|
|
10
|
+
console.log(`Successfully ${dir}/${name}.js created.`)
|
|
11
|
+
}
|
|
12
|
+
const addToIndex = name => {
|
|
13
|
+
const indexFilePath = path.resolve(__dirname, '..', 'src', 'index.js')
|
|
14
|
+
const indexFile = fs.readFileSync(indexFilePath, { encoding: 'utf8' })
|
|
15
|
+
fs.writeFileSync(indexFilePath, indexFile + [
|
|
16
|
+
`export { default as ${name} } from './${name}'`,
|
|
17
|
+
'',
|
|
18
|
+
].join('\n'))
|
|
19
|
+
console.log(`Successfully src/${name}.js updated.`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
createFile(n, 'src', [
|
|
23
|
+
'// @flow',
|
|
24
|
+
'',
|
|
25
|
+
'import { EditorState } from \'draft-js\'',
|
|
26
|
+
'',
|
|
27
|
+
`const ${n} = (`,
|
|
28
|
+
' editorState: EditorState',
|
|
29
|
+
'): EditorState => {}',
|
|
30
|
+
'',
|
|
31
|
+
`export default ${n}`,
|
|
32
|
+
'',
|
|
33
|
+
])
|
|
34
|
+
|
|
35
|
+
createFile(n, 'test', [
|
|
36
|
+
'import test from \'ava\'',
|
|
37
|
+
'import { convertToRaw } from \'draft-js\'',
|
|
38
|
+
'import createEditorState from \'./fixtures/createEditorState\'',
|
|
39
|
+
'',
|
|
40
|
+
`import ${n} from '../src/${n}'`,
|
|
41
|
+
'',
|
|
42
|
+
`test.skip('${n}', () => {})`,
|
|
43
|
+
'',
|
|
44
|
+
])
|
|
45
|
+
|
|
46
|
+
addToIndex(n)
|
|
47
|
+
|
|
48
|
+
console.log('Please add documentation to README.md')
|
package/src/addBlock.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Modifier } from "draft-js"
|
|
2
|
+
import { ContentBlock } from "draft-js"
|
|
3
|
+
import { genKey } from "draft-js"
|
|
4
|
+
import { CharacterMetadata } from "draft-js"
|
|
5
|
+
import { BlockMapBuilder } from "draft-js"
|
|
6
|
+
import { List, Repeat } from 'immutable'
|
|
7
|
+
|
|
8
|
+
// from draft-js-plugins/draft-js-plugins/packages/drag-n-drop/src/modifiers/addBlock.ts
|
|
9
|
+
const addBlock = (
|
|
10
|
+
editorState,
|
|
11
|
+
selection,
|
|
12
|
+
type,
|
|
13
|
+
data,
|
|
14
|
+
entityType,
|
|
15
|
+
text = ' '
|
|
16
|
+
) => {
|
|
17
|
+
const currentContentState = editorState.getCurrentContent()
|
|
18
|
+
const currentSelectionState = selection
|
|
19
|
+
|
|
20
|
+
// in case text is selected it is removed and then the block is appended
|
|
21
|
+
const afterRemovalContentState = Modifier.removeRange(
|
|
22
|
+
currentContentState,
|
|
23
|
+
currentSelectionState,
|
|
24
|
+
'backward'
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
// deciding on the position to split the text
|
|
28
|
+
const targetSelection = afterRemovalContentState.getSelectionAfter()
|
|
29
|
+
const blockKeyForTarget = targetSelection.get('focusKey')
|
|
30
|
+
const block = currentContentState.getBlockForKey(blockKeyForTarget)
|
|
31
|
+
let insertionTargetSelection
|
|
32
|
+
let insertionTargetBlock
|
|
33
|
+
|
|
34
|
+
// In case there are no characters or entity or the selection is at the start it
|
|
35
|
+
// is safe to insert the block in the current block.
|
|
36
|
+
// Otherwise a new block is created (the block is always its own block)
|
|
37
|
+
const isEmptyBlock = block.getLength() === 0 && block.getEntityAt(0) === null
|
|
38
|
+
const selectedFromStart = currentSelectionState.getStartOffset() === 0
|
|
39
|
+
if (isEmptyBlock || selectedFromStart) {
|
|
40
|
+
insertionTargetSelection = targetSelection
|
|
41
|
+
insertionTargetBlock = afterRemovalContentState
|
|
42
|
+
} else {
|
|
43
|
+
// the only way to insert a new seems to be by splitting an existing in to two
|
|
44
|
+
insertionTargetBlock = Modifier.splitBlock(
|
|
45
|
+
afterRemovalContentState,
|
|
46
|
+
targetSelection
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
// the position to insert our blocks
|
|
50
|
+
insertionTargetSelection = insertionTargetBlock.getSelectionAfter()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// TODO not sure why we need it …
|
|
54
|
+
const newContentStateAfterSplit = Modifier.setBlockType(
|
|
55
|
+
insertionTargetBlock,
|
|
56
|
+
insertionTargetSelection,
|
|
57
|
+
type
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
// creating a new ContentBlock including the entity with data
|
|
61
|
+
// Entity will be created with a specific type, if defined, else will fall back to the ContentBlock type
|
|
62
|
+
const contentStateWithEntity = newContentStateAfterSplit.createEntity(
|
|
63
|
+
entityType || type,
|
|
64
|
+
'IMMUTABLE',
|
|
65
|
+
data
|
|
66
|
+
)
|
|
67
|
+
const entityKey = contentStateWithEntity.getLastCreatedEntityKey()
|
|
68
|
+
const charData = CharacterMetadata.create({ entity: entityKey })
|
|
69
|
+
|
|
70
|
+
const fragmentArray = [
|
|
71
|
+
new ContentBlock({
|
|
72
|
+
key: genKey(),
|
|
73
|
+
type,
|
|
74
|
+
text,
|
|
75
|
+
characterList: List(Repeat(charData, text.length || 1)), // eslint-disable-line new-cap
|
|
76
|
+
}),
|
|
77
|
+
|
|
78
|
+
// new contentblock so we can continue wrting right away after inserting the block
|
|
79
|
+
new ContentBlock({
|
|
80
|
+
key: genKey(),
|
|
81
|
+
type: 'unstyled',
|
|
82
|
+
text: '',
|
|
83
|
+
characterList: List(), // eslint-disable-line new-cap
|
|
84
|
+
}),
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
// create fragment containing the two content blocks
|
|
88
|
+
const fragment = BlockMapBuilder.createFromArray(fragmentArray)
|
|
89
|
+
|
|
90
|
+
// replace the contentblock we reserved for our insert
|
|
91
|
+
return Modifier.replaceWithFragment(
|
|
92
|
+
newContentStateAfterSplit,
|
|
93
|
+
insertionTargetSelection,
|
|
94
|
+
fragment
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export default addBlock
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import { EditorState } from 'draft-js'
|
|
4
|
+
import adjustBlockDepthForContentState from 'draft-js/lib/adjustBlockDepthForContentState'
|
|
5
|
+
|
|
6
|
+
const adjustBlockDepth = (
|
|
7
|
+
editorState: EditorState,
|
|
8
|
+
adjustment: number,
|
|
9
|
+
maxDepth: number
|
|
10
|
+
): EditorState => {
|
|
11
|
+
const content = adjustBlockDepthForContentState(
|
|
12
|
+
editorState.getCurrentContent(),
|
|
13
|
+
editorState.getSelection(),
|
|
14
|
+
adjustment,
|
|
15
|
+
maxDepth
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
return EditorState.push(editorState, content, 'adjust-depth')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default adjustBlockDepth
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import getCurrentBlock from "./utils/getCurrentBlock"
|
|
2
|
+
|
|
3
|
+
const atEndOfBlock = (editorState) => {
|
|
4
|
+
const currentBlock = getCurrentBlock(editorState)
|
|
5
|
+
const selection = editorState.getSelection()
|
|
6
|
+
const endOffset = selection.getEndOffset()
|
|
7
|
+
return endOffset === currentBlock.getLength()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default atEndOfBlock
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RichUtils } from "draft-js"
|
|
2
|
+
import toggleBlockStyle from "./toggleBlockStyle"
|
|
3
|
+
import getCurrentBlock from "./utils/getCurrentBlock"
|
|
4
|
+
import setBlockData from './setBlockData'
|
|
5
|
+
|
|
6
|
+
const changeBlockType = (editorState, blockType, data) => {
|
|
7
|
+
const block = getCurrentBlock(editorState)
|
|
8
|
+
const currentBlockType = block.get('type')
|
|
9
|
+
|
|
10
|
+
if (currentBlockType === blockType) {
|
|
11
|
+
return setBlockData(editorState, data )
|
|
12
|
+
} else {
|
|
13
|
+
return data
|
|
14
|
+
? toggleBlockStyle(editorState, { type: blockType, data })
|
|
15
|
+
: RichUtils.toggleBlockType(editorState, blockType)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default changeBlockType
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getEntitiesForBlock } from "."
|
|
2
|
+
|
|
3
|
+
export const flatten = arr => arr.reduce((a, b) => a.concat(b), [])
|
|
4
|
+
|
|
5
|
+
const getAllEntities = (editorState, type = null) => {
|
|
6
|
+
const content = editorState.getCurrentContent()
|
|
7
|
+
const entities = []
|
|
8
|
+
content.getBlocksAsArray().forEach((contentBlock) => {
|
|
9
|
+
entities.push(getEntitiesForBlock(editorState, contentBlock, type))
|
|
10
|
+
})
|
|
11
|
+
return flatten(entities)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default getAllEntities
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const getEntitiesForBlock = (editorState, contentBlock, type = null) => {
|
|
2
|
+
const content = editorState.getCurrentContent()
|
|
3
|
+
const entities = []
|
|
4
|
+
|
|
5
|
+
let selectedEntity = null
|
|
6
|
+
contentBlock.findEntityRanges(
|
|
7
|
+
(character) => {
|
|
8
|
+
if (character.getEntity() !== null) {
|
|
9
|
+
const entity = content.getEntity(character.getEntity())
|
|
10
|
+
if (!type || (type && entity.getType() === type)) {
|
|
11
|
+
selectedEntity = {
|
|
12
|
+
entityKey: character.getEntity(),
|
|
13
|
+
blockKey: contentBlock.getKey(),
|
|
14
|
+
entity: content.getEntity(character.getEntity()),
|
|
15
|
+
}
|
|
16
|
+
return true
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return false
|
|
20
|
+
},
|
|
21
|
+
(start, end) => {
|
|
22
|
+
entities.push({ ...selectedEntity, start, end })
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
return entities
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default getEntitiesForBlock
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getCurrentBlock, getEntitiesForBlock } from "."
|
|
2
|
+
import { rangesOverlap } from "./utils/numbers"
|
|
3
|
+
|
|
4
|
+
const getEntitiesForCurrentBlock = (editorState, type = null) => getEntitiesForBlock(
|
|
5
|
+
editorState,
|
|
6
|
+
getCurrentBlock(editorState),
|
|
7
|
+
type
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
const getEntitiesForSelection = (editorState, type = null) => {
|
|
11
|
+
const entities = getEntitiesForCurrentBlock(editorState, type)
|
|
12
|
+
const selection = editorState.getSelection()
|
|
13
|
+
const selectionStart = selection.isCollapsed() ? selection.getStartOffset() - 1 : selection.getStartOffset()
|
|
14
|
+
const selectionEnd = selection.getEndOffset()
|
|
15
|
+
|
|
16
|
+
return entities
|
|
17
|
+
.filter(({ start, end }) => rangesOverlap(selectionStart, selectionEnd, start, end))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default getEntitiesForSelection
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const getSelectedText = (editorState) => {
|
|
2
|
+
const selectionState = editorState.getSelection()
|
|
3
|
+
const anchorKey = selectionState.getAnchorKey()
|
|
4
|
+
const currentContent = editorState.getCurrentContent()
|
|
5
|
+
const currentContentBlock = currentContent.getBlockForKey(anchorKey)
|
|
6
|
+
const start = selectionState.getStartOffset()
|
|
7
|
+
const end = selectionState.getEndOffset()
|
|
8
|
+
return currentContentBlock.getText().slice(start, end)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default getSelectedText
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const getSimilarAdjacentBlocks = (editorState, block, options = {}) => {
|
|
2
|
+
const blockType = block.getType()
|
|
3
|
+
const depth = block.getDepth()
|
|
4
|
+
const variant = block.getData().get('variant')
|
|
5
|
+
|
|
6
|
+
const contentState = editorState.getCurrentContent()
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
includeDepth = true,
|
|
10
|
+
includeVariant = false,
|
|
11
|
+
onlyForBlockTypes = [],
|
|
12
|
+
} = options
|
|
13
|
+
|
|
14
|
+
const matches = aBlock => aBlock && [
|
|
15
|
+
(aBlock.getType() === blockType),
|
|
16
|
+
(!includeDepth || (aBlock.getDepth() === depth)),
|
|
17
|
+
!includeVariant || (aBlock.getData().get('variant') === variant),
|
|
18
|
+
!onlyForBlockTypes.length || onlyForBlockTypes.includes(aBlock.getType()),
|
|
19
|
+
].every(Boolean)
|
|
20
|
+
|
|
21
|
+
const before = []
|
|
22
|
+
const after = []
|
|
23
|
+
|
|
24
|
+
let cursor = block
|
|
25
|
+
while (cursor) {
|
|
26
|
+
const prev = contentState.getBlockBefore(cursor.getKey())
|
|
27
|
+
if (matches(prev)) {
|
|
28
|
+
before.push(prev)
|
|
29
|
+
cursor = prev
|
|
30
|
+
} else {
|
|
31
|
+
cursor = null
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
cursor = block
|
|
36
|
+
while (cursor) {
|
|
37
|
+
const next = contentState.getBlockAfter(cursor.getKey())
|
|
38
|
+
if (matches(next)) {
|
|
39
|
+
after.push(next)
|
|
40
|
+
cursor = next
|
|
41
|
+
} else {
|
|
42
|
+
cursor = null
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
before: before.reverse(),
|
|
48
|
+
after,
|
|
49
|
+
all: [...before.reverse(), block, ...after],
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default getSimilarAdjacentBlocks
|
package/src/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export { default as addBlock } from './addBlock'
|
|
2
|
+
export { default as adjustBlockDepth } from './adjustBlockDepth'
|
|
3
|
+
export { default as atEndOfBlock } from './atEndOfBlock'
|
|
4
|
+
export { default as atStartOfBlock } from './atStartOfBlock'
|
|
5
|
+
export { default as changeBlockType } from './changeBlockType'
|
|
6
|
+
export { default as getAllEntities } from './getAllEntities'
|
|
7
|
+
export { default as getCurrentBlock } from './utils/getCurrentBlock'
|
|
8
|
+
export { default as getEntitiesForBlock } from './getEntitiesForBlock'
|
|
9
|
+
export { default as getEntitiesForSelection } from './getEntitiesForSelection'
|
|
10
|
+
export { default as getSelectedText } from './getSelectedText'
|
|
11
|
+
export { default as getSimilarAdjacentBlocks } from './getSimilarAdjacentBlocks'
|
|
12
|
+
export { default as insertAtomicBlock } from './insertAtomicBlock'
|
|
13
|
+
export { default as insertBlockAfter } from './insertBlockAfter'
|
|
14
|
+
export { default as insertBlockBefore } from './insertBlockBefore'
|
|
15
|
+
export { default as insertEmptyBlock } from './insertEmptyBlock'
|
|
16
|
+
export { default as insertEntity } from './insertEntity'
|
|
17
|
+
export { default as insertNewBlock } from './insertNewBlock'
|
|
18
|
+
export { default as insertText } from './insertText'
|
|
19
|
+
export { default as mergeBlockData } from './mergeBlockData'
|
|
20
|
+
export { default as mergeBlockDataByKey } from './mergeBlockDataByKey'
|
|
21
|
+
export { default as mergeEntityData } from './mergeEntityData'
|
|
22
|
+
export { default as modifyBlock } from './modifyBlock'
|
|
23
|
+
export { default as modifyBlockByKey } from './modifyBlockByKey'
|
|
24
|
+
export { default as moveCaretAfterBlock } from './moveCaretAfterBlock'
|
|
25
|
+
export { default as moveCaretToEnd } from './moveCaretToEnd'
|
|
26
|
+
export { default as removeBlock } from './removeBlock'
|
|
27
|
+
export { default as removeBlockStyle } from './removeBlockStyle'
|
|
28
|
+
export { default as removeEntity } from './removeEntity'
|
|
29
|
+
export { default as removeInlineStyles } from './removeInlineStyles'
|
|
30
|
+
export { default as resetBlock } from './resetBlock'
|
|
31
|
+
export { default as selectAll} from './selectAll'
|
|
32
|
+
export { default as selectBlockByKey } from './selectBlockByKey'
|
|
33
|
+
export { default as setBlockData } from './setBlockData'
|
|
34
|
+
export { default as toggleBlockStyle } from './toggleBlockStyle'
|
|
35
|
+
export { default as toggleBlockType } from './toggleBlockType'
|
|
36
|
+
export { default as toggleEntity } from './toggleEntity'
|
|
37
|
+
export { default as toggleInlineStyle } from './toggleInlineStyle'
|
|
38
|
+
export { default as trimEditorState } from './trimEditorState'
|
|
39
|
+
|
|
40
|
+
export const DRAFTJS_BLOCK_KEY = 'DRAFTJS_BLOCK_KEY'
|
|
41
|
+
export const HANDLED = 'handled'
|
|
42
|
+
export const NOT_HANDLED = 'not-handled'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import { AtomicBlockUtils } from 'draft-js'
|
|
4
|
+
|
|
5
|
+
import type { EditorState } from 'draft-js'
|
|
6
|
+
import type { DraftEntityType } from 'draft-js/lib/DraftEntityType'
|
|
7
|
+
|
|
8
|
+
const insertAtomicBlock = (
|
|
9
|
+
editorState: EditorState,
|
|
10
|
+
entityType: DraftEntityType,
|
|
11
|
+
mutability: 'IMMUTABLE' | 'MUTABLE' | 'SEGMENTED',
|
|
12
|
+
data?: { [id: string]: any },
|
|
13
|
+
character?: string = ' '
|
|
14
|
+
): EditorState => {
|
|
15
|
+
const entityKey = editorState.getCurrentContent().createEntity(entityType, mutability, data).getLastCreatedEntityKey()
|
|
16
|
+
return AtomicBlockUtils.insertAtomicBlock(
|
|
17
|
+
editorState,
|
|
18
|
+
entityKey,
|
|
19
|
+
character
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default insertAtomicBlock
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { EditorState } from "draft-js"
|
|
2
|
+
import { genKey } from "draft-js"
|
|
3
|
+
import { ContentBlock } from "draft-js"
|
|
4
|
+
import { ContentState } from "draft-js"
|
|
5
|
+
import Immutable from "immutable"
|
|
6
|
+
|
|
7
|
+
const insertBlockAfter = (editorState, keyBefore, blockParams) => {
|
|
8
|
+
const newBlock = new ContentBlock({
|
|
9
|
+
key: genKey(),
|
|
10
|
+
type: 'unstyled',
|
|
11
|
+
text: '',
|
|
12
|
+
...blockParams,
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
let modified = false
|
|
16
|
+
|
|
17
|
+
const contentState = editorState.getCurrentContent()
|
|
18
|
+
const oldBlockMap = contentState.getBlockMap()
|
|
19
|
+
const newBlockMap = Immutable.OrderedMap().withMutations((map) => {
|
|
20
|
+
for (const [k, v] of oldBlockMap.entries()) {
|
|
21
|
+
map.set(k, v)
|
|
22
|
+
|
|
23
|
+
if (keyBefore === k) {
|
|
24
|
+
map.set(newBlock.key, newBlock)
|
|
25
|
+
modified=true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
return modified
|
|
31
|
+
? EditorState.push(
|
|
32
|
+
editorState,
|
|
33
|
+
ContentState
|
|
34
|
+
.createFromBlockArray(Array.from(newBlockMap.values()))
|
|
35
|
+
.set('selectionBefore', contentState.getSelectionBefore())
|
|
36
|
+
.set('selectionAfter', contentState.getSelectionAfter()),
|
|
37
|
+
'split-block'
|
|
38
|
+
)
|
|
39
|
+
: editorState
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default insertBlockAfter
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { EditorState } from "draft-js"
|
|
2
|
+
import { genKey } from "draft-js"
|
|
3
|
+
import { ContentBlock } from "draft-js"
|
|
4
|
+
import { ContentState } from "draft-js"
|
|
5
|
+
import Immutable from "immutable"
|
|
6
|
+
|
|
7
|
+
const insertBlockBefore = (editorState, keyBefore, blockParams) => {
|
|
8
|
+
const newBlock = new ContentBlock({
|
|
9
|
+
key: genKey(),
|
|
10
|
+
type: 'unstyled',
|
|
11
|
+
text: '',
|
|
12
|
+
...blockParams,
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
let modified = false
|
|
16
|
+
|
|
17
|
+
const contentState = editorState.getCurrentContent()
|
|
18
|
+
const oldBlockMap = contentState.getBlockMap()
|
|
19
|
+
const newBlockMap = Immutable.OrderedMap().withMutations((map) => {
|
|
20
|
+
for (const [k, v] of oldBlockMap.entries()) {
|
|
21
|
+
if (keyBefore === k) {
|
|
22
|
+
map.set(newBlock.key, newBlock)
|
|
23
|
+
modified = true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
map.set(k, v)
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
return modified
|
|
31
|
+
? EditorState.push(
|
|
32
|
+
editorState,
|
|
33
|
+
ContentState
|
|
34
|
+
.createFromBlockArray(Array.from(newBlockMap.values()))
|
|
35
|
+
.set('selectionBefore', contentState.getSelectionBefore())
|
|
36
|
+
.set('selectionAfter', contentState.getSelectionAfter()),
|
|
37
|
+
'split-block'
|
|
38
|
+
)
|
|
39
|
+
: editorState
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default insertBlockBefore
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import insertNewBlock from './insertNewBlock'
|
|
4
|
+
|
|
5
|
+
import type { EditorState } from 'draft-js'
|
|
6
|
+
import type { DraftBlockType } from 'draft-js/lib/DraftBlockType'
|
|
7
|
+
|
|
8
|
+
const insertEmptyBlock = (editorState: EditorState, blockType?: DraftBlockType = 'unstyled'): EditorState => {
|
|
9
|
+
return insertNewBlock(editorState, blockType)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default insertEmptyBlock
|