@atlaskit/editor-plugin-block-menu 1.0.11 → 1.0.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/CHANGELOG.md +20 -0
- package/dist/cjs/editor-commands/transforms/block-transforms.js +1 -1
- package/dist/cjs/editor-commands/transforms/container-transforms.js +8 -25
- package/dist/cjs/editor-commands/transforms/inline-node-transforms.js +9 -7
- package/dist/cjs/editor-commands/transforms/layout/utils.js +289 -0
- package/dist/cjs/editor-commands/transforms/layout-transforms.js +40 -2
- package/dist/cjs/editor-commands/transforms/list/transformBetweenListTypes.js +92 -50
- package/dist/cjs/editor-commands/transforms/list-transforms.js +7 -0
- package/dist/cjs/editor-commands/transforms/transformNodeToTargetType.js +3 -0
- package/dist/cjs/editor-commands/transforms/utils.js +40 -1
- package/dist/es2019/editor-commands/transforms/block-transforms.js +2 -2
- package/dist/es2019/editor-commands/transforms/container-transforms.js +8 -23
- package/dist/es2019/editor-commands/transforms/inline-node-transforms.js +8 -6
- package/dist/es2019/editor-commands/transforms/layout/utils.js +272 -0
- package/dist/es2019/editor-commands/transforms/layout-transforms.js +40 -1
- package/dist/es2019/editor-commands/transforms/list/transformBetweenListTypes.js +94 -51
- package/dist/es2019/editor-commands/transforms/list-transforms.js +7 -0
- package/dist/es2019/editor-commands/transforms/transformNodeToTargetType.js +5 -2
- package/dist/es2019/editor-commands/transforms/utils.js +39 -0
- package/dist/esm/editor-commands/transforms/block-transforms.js +2 -2
- package/dist/esm/editor-commands/transforms/container-transforms.js +8 -25
- package/dist/esm/editor-commands/transforms/inline-node-transforms.js +8 -6
- package/dist/esm/editor-commands/transforms/layout/utils.js +282 -0
- package/dist/esm/editor-commands/transforms/layout-transforms.js +38 -1
- package/dist/esm/editor-commands/transforms/list/transformBetweenListTypes.js +92 -49
- package/dist/esm/editor-commands/transforms/list-transforms.js +7 -0
- package/dist/esm/editor-commands/transforms/transformNodeToTargetType.js +5 -2
- package/dist/esm/editor-commands/transforms/utils.js +39 -0
- package/dist/types/editor-commands/transforms/inline-node-transforms.d.ts +3 -3
- package/dist/types/editor-commands/transforms/layout/utils.d.ts +5 -0
- package/dist/types/editor-commands/transforms/layout-transforms.d.ts +1 -0
- package/dist/types/editor-commands/transforms/list/transformBetweenListTypes.d.ts +13 -0
- package/dist/types/editor-commands/transforms/utils.d.ts +13 -0
- package/dist/types-ts4.5/editor-commands/transforms/inline-node-transforms.d.ts +3 -3
- package/dist/types-ts4.5/editor-commands/transforms/layout/utils.d.ts +5 -0
- package/dist/types-ts4.5/editor-commands/transforms/layout-transforms.d.ts +1 -0
- package/dist/types-ts4.5/editor-commands/transforms/list/transformBetweenListTypes.d.ts +13 -0
- package/dist/types-ts4.5/editor-commands/transforms/utils.d.ts +13 -0
- package/package.json +2 -2
|
@@ -52,6 +52,9 @@ function transformNodeToTargetType(tr, sourceNode, sourcePos, targetType) {
|
|
|
52
52
|
if (sourceNode.type.name === 'codeBlock' && (0, _utils.isListNodeType)(targetNodeType)) {
|
|
53
53
|
return (0, _containerTransforms.unwrapAndConvertToList)(transformationContext);
|
|
54
54
|
}
|
|
55
|
+
if ((0, _utils.isLayoutNode)(sourceNode)) {
|
|
56
|
+
return (0, _layoutTransforms.transformLayoutNode)(transformationContext);
|
|
57
|
+
}
|
|
55
58
|
if ((0, _utils.isBlockNode)(sourceNode)) {
|
|
56
59
|
return (0, _blockTransforms.transformBlockNode)(transformationContext);
|
|
57
60
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.isTaskList = exports.isListNodeType = exports.isListNode = exports.isLayoutNodeType = exports.isContainerNodeType = exports.isContainerNode = exports.isBulletOrOrderedList = exports.isBlockNodeType = exports.isBlockNodeForExtraction = exports.isBlockNode = exports.getTargetNodeInfo = exports.getSupportedListTypesSet = exports.getSupportedListTypes = exports.getContentSupportChecker = exports.convertNodeToInlineContent = void 0;
|
|
6
|
+
exports.isTaskList = exports.isListNodeType = exports.isListNode = exports.isLayoutNodeType = exports.isLayoutNode = exports.isHeadingOrParagraphNode = exports.isContainerNodeType = exports.isContainerNode = exports.isBulletOrOrderedList = exports.isBlockNodeType = exports.isBlockNodeForExtraction = exports.isBlockNode = exports.getTargetNodeInfo = exports.getSupportedListTypesSet = exports.getSupportedListTypes = exports.getContentSupportChecker = exports.filterMarksForTargetNodeType = exports.convertNodeToInlineContent = exports.convertCodeBlockContentToParagraphs = void 0;
|
|
7
7
|
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
8
8
|
var getTargetNodeInfo = exports.getTargetNodeInfo = function getTargetNodeInfo(targetType, nodes) {
|
|
9
9
|
switch (targetType) {
|
|
@@ -97,6 +97,9 @@ var getTargetNodeInfo = exports.getTargetNodeInfo = function getTargetNodeInfo(t
|
|
|
97
97
|
var isBlockNode = exports.isBlockNode = function isBlockNode(node) {
|
|
98
98
|
return ['paragraph', 'heading', 'codeBlock'].includes(node.type.name);
|
|
99
99
|
};
|
|
100
|
+
var isHeadingOrParagraphNode = exports.isHeadingOrParagraphNode = function isHeadingOrParagraphNode(node) {
|
|
101
|
+
return ['paragraph', 'heading'].includes(node.type.name);
|
|
102
|
+
};
|
|
100
103
|
var isListNode = exports.isListNode = function isListNode(node) {
|
|
101
104
|
return ['bulletList', 'orderedList', 'taskList'].includes(node.type.name);
|
|
102
105
|
};
|
|
@@ -129,6 +132,9 @@ var getSupportedListTypesSet = exports.getSupportedListTypesSet = function getSu
|
|
|
129
132
|
var isLayoutNodeType = exports.isLayoutNodeType = function isLayoutNodeType(nodeType) {
|
|
130
133
|
return nodeType.name === 'layoutSection';
|
|
131
134
|
};
|
|
135
|
+
var isLayoutNode = exports.isLayoutNode = function isLayoutNode(node) {
|
|
136
|
+
return node.type.name === 'layoutSection';
|
|
137
|
+
};
|
|
132
138
|
|
|
133
139
|
/**
|
|
134
140
|
* Check if a node should be extracted as a standalone block node
|
|
@@ -174,4 +180,37 @@ var convertNodeToInlineContent = exports.convertNodeToInlineContent = function c
|
|
|
174
180
|
return [schema.text(node.textContent)];
|
|
175
181
|
}
|
|
176
182
|
return inlineNodes;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Filter marks from content based on the target node type
|
|
187
|
+
* @param content The content fragment to filter
|
|
188
|
+
* @param targetNodeType The target node type to check against
|
|
189
|
+
* @returns A new fragment with marks filtered for the target node type
|
|
190
|
+
*/
|
|
191
|
+
var filterMarksForTargetNodeType = exports.filterMarksForTargetNodeType = function filterMarksForTargetNodeType(content, targetNodeType) {
|
|
192
|
+
var withValidMarks = [];
|
|
193
|
+
content.forEach(function (node) {
|
|
194
|
+
if (node.marks.length > 0) {
|
|
195
|
+
var allowedMarks = targetNodeType.allowedMarks(node.marks);
|
|
196
|
+
var updatedNode = node.mark(allowedMarks);
|
|
197
|
+
withValidMarks.push(updatedNode);
|
|
198
|
+
} else {
|
|
199
|
+
withValidMarks.push(node);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
return _model.Fragment.from(withValidMarks);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/** * Convert content from a code block node into multiple paragraph nodes
|
|
206
|
+
*/
|
|
207
|
+
var convertCodeBlockContentToParagraphs = exports.convertCodeBlockContentToParagraphs = function convertCodeBlockContentToParagraphs(codeBlockNode, schema) {
|
|
208
|
+
var paragraphNodes = [];
|
|
209
|
+
var codeText = codeBlockNode.textContent;
|
|
210
|
+
var lines = codeText.split('\n');
|
|
211
|
+
lines.forEach(function (line) {
|
|
212
|
+
var paragraphNode = schema.nodes.paragraph.create(null, line ? schema.text(line) : null);
|
|
213
|
+
paragraphNodes.push(paragraphNode);
|
|
214
|
+
});
|
|
215
|
+
return paragraphNodes;
|
|
177
216
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { transformToContainer, unwrapAndConvertToBlockType } from './container-transforms';
|
|
2
|
-
import {
|
|
2
|
+
import { getInlineNodeTextNode } from './inline-node-transforms';
|
|
3
3
|
import { transformBlockToList } from './list-transforms';
|
|
4
4
|
import { isListNodeType, isContainerNodeType, isBlockNodeType } from './utils';
|
|
5
5
|
|
|
@@ -44,7 +44,7 @@ const transformToBlockNode = context => {
|
|
|
44
44
|
} = selection;
|
|
45
45
|
const schema = doc.type.schema;
|
|
46
46
|
if (targetNodeType === schema.nodes.codeBlock) {
|
|
47
|
-
const textContent =
|
|
47
|
+
const textContent = getInlineNodeTextNode(selection.content().content, schema);
|
|
48
48
|
const node = schema.nodes.codeBlock.createChecked(undefined, textContent);
|
|
49
49
|
return tr.replaceRangeWith(selection.from, selection.to, node);
|
|
50
50
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
-
import { isBlockNodeType, isListNodeType, isContainerNodeType, isBlockNodeForExtraction, convertNodeToInlineContent, getContentSupportChecker } from './utils';
|
|
2
|
+
import { isBlockNodeType, isListNodeType, isContainerNodeType, isBlockNodeForExtraction, convertNodeToInlineContent, getContentSupportChecker, convertCodeBlockContentToParagraphs, filterMarksForTargetNodeType } from './utils';
|
|
3
3
|
const convertInvalidNodeToValidNodeType = (sourceContent, sourceNodeType, validNodeType, withMarks) => {
|
|
4
4
|
const validTransformedContent = [];
|
|
5
5
|
// Headings are not valid inside headings so convert heading nodes to paragraphs
|
|
@@ -12,19 +12,6 @@ const convertInvalidNodeToValidNodeType = (sourceContent, sourceNodeType, validN
|
|
|
12
12
|
});
|
|
13
13
|
return Fragment.from(validTransformedContent);
|
|
14
14
|
};
|
|
15
|
-
const filterMarksForTargetNodeType = (content, targetNodeType) => {
|
|
16
|
-
const withValidMarks = [];
|
|
17
|
-
content.forEach(node => {
|
|
18
|
-
if (node.marks.length > 0) {
|
|
19
|
-
const allowedMarks = targetNodeType.allowedMarks(node.marks);
|
|
20
|
-
const updatedNode = node.mark(allowedMarks);
|
|
21
|
-
withValidMarks.push(updatedNode);
|
|
22
|
-
} else {
|
|
23
|
-
withValidMarks.push(node);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
return Fragment.from(withValidMarks);
|
|
27
|
-
};
|
|
28
15
|
|
|
29
16
|
/**
|
|
30
17
|
* Transform selection to container type
|
|
@@ -40,7 +27,8 @@ export const transformToContainer = ({
|
|
|
40
27
|
const content = selection.content().content;
|
|
41
28
|
let transformedContent = content;
|
|
42
29
|
if (sourceNode.type === schema.nodes.codeBlock) {
|
|
43
|
-
|
|
30
|
+
const paragraphNodes = convertCodeBlockContentToParagraphs(sourceNode, schema);
|
|
31
|
+
transformedContent = Fragment.fromArray(paragraphNodes);
|
|
44
32
|
}
|
|
45
33
|
if (targetNodeType === schema.nodes.blockquote) {
|
|
46
34
|
transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.heading, schema.nodes.paragraph, true);
|
|
@@ -157,10 +145,7 @@ export const unwrapAndConvertToBlockType = context => {
|
|
|
157
145
|
|
|
158
146
|
// if the container is a code block, convert text content to multiple paragraphs
|
|
159
147
|
if (sourceNode.type === codeBlock) {
|
|
160
|
-
|
|
161
|
-
const lines = codeText.split('\n');
|
|
162
|
-
const paragraphNodes = lines.map(line => paragraph.create(null, line ? schema.text(line) : null));
|
|
163
|
-
sourceChildren = paragraphNodes;
|
|
148
|
+
sourceChildren = convertCodeBlockContentToParagraphs(sourceNode, schema);
|
|
164
149
|
}
|
|
165
150
|
|
|
166
151
|
// if target node is a paragraph, just do unwrap
|
|
@@ -399,15 +384,15 @@ const splitContentAroundUnsupportedBlocks = (sourceNode, isContentSupported, tar
|
|
|
399
384
|
if (isContentSupported(childNode)) {
|
|
400
385
|
// Supported content - add to current container
|
|
401
386
|
currentContainerContent.push(childNode);
|
|
402
|
-
} else if (isBlockNodeForExtraction(childNode)) {
|
|
403
|
-
// Unsupported block node - flush current container, add block, continue
|
|
404
|
-
flushCurrentContainer();
|
|
405
|
-
splits.push(childNode);
|
|
406
387
|
} else if (childNode.type.name === targetNodeType.name) {
|
|
407
388
|
// Same type of container merge contents
|
|
408
389
|
childNode.content.forEach(child => {
|
|
409
390
|
currentContainerContent.push(child);
|
|
410
391
|
});
|
|
392
|
+
} else if (childNode.isBlock) {
|
|
393
|
+
// Unsupported block node - flush current container, add block, continue
|
|
394
|
+
flushCurrentContainer();
|
|
395
|
+
splits.push(childNode);
|
|
411
396
|
} else {
|
|
412
397
|
// Unsupported inline content - convert to paragraph and add to container
|
|
413
398
|
const inlineContent = convertNodeToInlineContent(childNode, schema);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
export const getInlineNodeTextContent =
|
|
1
|
+
export const getInlineNodeTextContent = sourceContent => {
|
|
2
2
|
let validTransformedContent = '';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return;
|
|
3
|
+
if (sourceContent.content.length < 1) {
|
|
4
|
+
return '';
|
|
6
5
|
}
|
|
7
6
|
// Headings are not valid inside headings so convert heading nodes to paragraphs
|
|
8
7
|
sourceContent.forEach(node => {
|
|
@@ -14,8 +13,11 @@ export const getInlineNodeTextContent = (sourceContent, tr) => {
|
|
|
14
13
|
validTransformedContent += `${inlineNode.textContent}`;
|
|
15
14
|
}
|
|
16
15
|
});
|
|
17
|
-
validTransformedContent;
|
|
18
16
|
}
|
|
19
17
|
});
|
|
20
|
-
return
|
|
18
|
+
return validTransformedContent;
|
|
19
|
+
};
|
|
20
|
+
export const getInlineNodeTextNode = (sourceContent, schema) => {
|
|
21
|
+
const text = getInlineNodeTextContent(sourceContent);
|
|
22
|
+
return schema.text(text);
|
|
21
23
|
};
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { findChildrenByType } from '@atlaskit/editor-prosemirror/utils';
|
|
3
|
+
import { getInlineNodeTextContent } from '../inline-node-transforms';
|
|
4
|
+
import { transformListRecursively } from '../list/transformBetweenListTypes';
|
|
5
|
+
import { getContentSupportChecker, getSupportedListTypesSet, isBlockNode, isBlockNodeForExtraction, isBlockNodeType, isBulletOrOrderedList, isContainerNode, isContainerNodeType, isHeadingOrParagraphNode, isListNode, isListNodeType, isTaskList } from '../utils';
|
|
6
|
+
export const unwrapLayoutNodesToTextNodes = (context, finalTargetNodeType) => {
|
|
7
|
+
const {
|
|
8
|
+
tr,
|
|
9
|
+
sourceNode,
|
|
10
|
+
targetNodeType,
|
|
11
|
+
targetAttrs
|
|
12
|
+
} = context;
|
|
13
|
+
const schema = tr.doc.type.schema || {};
|
|
14
|
+
const isValid = getContentSupportChecker(finalTargetNodeType);
|
|
15
|
+
const createTextNode = node => {
|
|
16
|
+
const isTextNode = node.type.name === 'text';
|
|
17
|
+
if (isValid(node) && !isTextNode) {
|
|
18
|
+
return node;
|
|
19
|
+
}
|
|
20
|
+
return targetNodeType.createChecked(targetAttrs, isTextNode ? node : node.content, node.marks);
|
|
21
|
+
};
|
|
22
|
+
if (isBlockNode(sourceNode)) {
|
|
23
|
+
// code block acts like a container, we need to unwrap it
|
|
24
|
+
if (sourceNode.type === schema.nodes.codeBlock) {
|
|
25
|
+
const textNodes = sourceNode.textContent.split('\n').map(line => targetNodeType.createChecked(undefined, line ? schema.text(line) : null));
|
|
26
|
+
return textNodes;
|
|
27
|
+
}
|
|
28
|
+
return [createTextNode(sourceNode)];
|
|
29
|
+
}
|
|
30
|
+
if (isContainerNode(sourceNode)) {
|
|
31
|
+
var _sourceNode$attrs;
|
|
32
|
+
const containerNodes = [];
|
|
33
|
+
if (sourceNode.type.name === 'expand' && (_sourceNode$attrs = sourceNode.attrs) !== null && _sourceNode$attrs !== void 0 && _sourceNode$attrs.title) {
|
|
34
|
+
containerNodes.push(createTextNode(schema.text(sourceNode.attrs.title)));
|
|
35
|
+
}
|
|
36
|
+
sourceNode.content.forEach(childNode => {
|
|
37
|
+
if (isHeadingOrParagraphNode(childNode)) {
|
|
38
|
+
containerNodes.push(createTextNode(childNode));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
containerNodes.push(childNode);
|
|
42
|
+
});
|
|
43
|
+
return containerNodes;
|
|
44
|
+
}
|
|
45
|
+
if (isListNode(sourceNode)) {
|
|
46
|
+
if (isBlockNodeType(finalTargetNodeType)) {
|
|
47
|
+
if (sourceNode.type.name === 'taskList') {
|
|
48
|
+
const taskItemsResult = findChildrenByType(sourceNode, schema.nodes.taskItem);
|
|
49
|
+
const taskItems = taskItemsResult.map(item => item.node);
|
|
50
|
+
const taskItemFragments = taskItems.map(taskItem => taskItem.content);
|
|
51
|
+
return taskItemFragments.map(fragment => targetNodeType.createChecked(targetAttrs, fragment.content));
|
|
52
|
+
} else {
|
|
53
|
+
const paragraphs = findChildrenByType(sourceNode, schema.nodes.paragraph);
|
|
54
|
+
const paragraphNodes = paragraphs.map(paragraph => paragraph.node);
|
|
55
|
+
if (targetNodeType === schema.nodes.heading) {
|
|
56
|
+
return paragraphNodes.map(paragraphNode => targetNodeType.createChecked(targetAttrs, paragraphNode.content));
|
|
57
|
+
}
|
|
58
|
+
return paragraphNodes;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return [sourceNode];
|
|
62
|
+
}
|
|
63
|
+
return [sourceNode];
|
|
64
|
+
};
|
|
65
|
+
const transformToBlockNode = (nodes, targetNodeType, schema) => {
|
|
66
|
+
if (targetNodeType === schema.nodes.codeBlock) {
|
|
67
|
+
const newNodes = [];
|
|
68
|
+
nodes.forEach(node => {
|
|
69
|
+
if (node.isTextblock) {
|
|
70
|
+
const inlineTextContent = node.type === schema.nodes.codeBlock ? node.textContent : getInlineNodeTextContent(Fragment.from(node));
|
|
71
|
+
|
|
72
|
+
// For first node, add directly
|
|
73
|
+
if (newNodes.length === 0) {
|
|
74
|
+
newNodes.push({
|
|
75
|
+
canBeTransformed: true,
|
|
76
|
+
content: [inlineTextContent]
|
|
77
|
+
});
|
|
78
|
+
} else {
|
|
79
|
+
// Check if last node can also be transformed, if yes then append content
|
|
80
|
+
const lastItem = newNodes[newNodes.length - 1];
|
|
81
|
+
if (lastItem.canBeTransformed) {
|
|
82
|
+
newNodes[newNodes.length - 1] = {
|
|
83
|
+
content: [...lastItem.content, inlineTextContent],
|
|
84
|
+
canBeTransformed: true
|
|
85
|
+
};
|
|
86
|
+
} else {
|
|
87
|
+
newNodes.push({
|
|
88
|
+
content: [inlineTextContent],
|
|
89
|
+
canBeTransformed: true
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
// If not text block, then cannot be transformed
|
|
95
|
+
newNodes.push({
|
|
96
|
+
canBeTransformed: false,
|
|
97
|
+
content: node
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return newNodes.map(({
|
|
102
|
+
canBeTransformed,
|
|
103
|
+
content
|
|
104
|
+
}) => {
|
|
105
|
+
if (canBeTransformed) {
|
|
106
|
+
const text = content.join('\n');
|
|
107
|
+
if (text === '') {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
return targetNodeType.createChecked(null, schema.text(text));
|
|
111
|
+
} else {
|
|
112
|
+
return content;
|
|
113
|
+
}
|
|
114
|
+
}).filter(Boolean);
|
|
115
|
+
}
|
|
116
|
+
return nodes;
|
|
117
|
+
};
|
|
118
|
+
const transformToContainerNode = (nodes, targetNodeType) => {
|
|
119
|
+
const newNodes = [];
|
|
120
|
+
const isNodeValid = getContentSupportChecker(targetNodeType);
|
|
121
|
+
nodes.forEach(node => {
|
|
122
|
+
// If the node is not supported then we append as is
|
|
123
|
+
if (isBlockNodeForExtraction(node)) {
|
|
124
|
+
newNodes.push({
|
|
125
|
+
node: node,
|
|
126
|
+
canBeTransformed: false
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
// Remove alignment marks as container nodes don't support them
|
|
130
|
+
const nodeWithValidAttrs = node.mark(node.marks.filter(mark => mark.type.name !== 'alignment'));
|
|
131
|
+
const isSameNodeType = node.type === targetNodeType;
|
|
132
|
+
|
|
133
|
+
// If the node is not valid and not the same type, we cannot transform it
|
|
134
|
+
if (!isNodeValid(nodeWithValidAttrs) && !isSameNodeType) {
|
|
135
|
+
newNodes.push({
|
|
136
|
+
node: node,
|
|
137
|
+
canBeTransformed: false
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const nodes = isSameNodeType ? node.content.content : [nodeWithValidAttrs];
|
|
142
|
+
if (newNodes.length === 0) {
|
|
143
|
+
newNodes.push({
|
|
144
|
+
node: nodes,
|
|
145
|
+
canBeTransformed: true
|
|
146
|
+
});
|
|
147
|
+
} else {
|
|
148
|
+
const lastItem = newNodes[newNodes.length - 1];
|
|
149
|
+
if (lastItem.canBeTransformed) {
|
|
150
|
+
newNodes[newNodes.length - 1] = {
|
|
151
|
+
node: [...lastItem.node, ...nodes],
|
|
152
|
+
canBeTransformed: true
|
|
153
|
+
};
|
|
154
|
+
} else {
|
|
155
|
+
newNodes.push({
|
|
156
|
+
node: nodes,
|
|
157
|
+
canBeTransformed: true
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return newNodes.map(({
|
|
164
|
+
node,
|
|
165
|
+
canBeTransformed
|
|
166
|
+
}) => {
|
|
167
|
+
if (canBeTransformed) {
|
|
168
|
+
return targetNodeType.createChecked(null, Fragment.fromArray(node));
|
|
169
|
+
} else {
|
|
170
|
+
return node;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
export const transformToListNode = (nodes, targetNodeType, schema) => {
|
|
175
|
+
const isTargetTask = isTaskList(targetNodeType);
|
|
176
|
+
const listItems = [];
|
|
177
|
+
const listItemType = isTargetTask ? schema.nodes.taskItem : schema.nodes.listItem;
|
|
178
|
+
const isValid = getContentSupportChecker(listItemType);
|
|
179
|
+
nodes.forEach(node => {
|
|
180
|
+
// Append unsupported nodes as is
|
|
181
|
+
if (isBlockNodeForExtraction(node)) {
|
|
182
|
+
listItems.push({
|
|
183
|
+
canBeTransformed: false,
|
|
184
|
+
node
|
|
185
|
+
});
|
|
186
|
+
} else {
|
|
187
|
+
let newListItems;
|
|
188
|
+
|
|
189
|
+
// If the node is a list, we may need to transform it
|
|
190
|
+
if (isListNode(node)) {
|
|
191
|
+
const isSourceBulletOrOrdered = isBulletOrOrderedList(node.type);
|
|
192
|
+
const isTargetTask = isTaskList(targetNodeType);
|
|
193
|
+
const isSourceTask = isTaskList(node.type);
|
|
194
|
+
const isTargetBulletOrOrdered = isBulletOrOrderedList(targetNodeType);
|
|
195
|
+
const supportedListTypes = getSupportedListTypesSet(schema.nodes);
|
|
196
|
+
if (node.type === targetNodeType) {
|
|
197
|
+
// For the same list type, we can keep the structure
|
|
198
|
+
newListItems = node.content.content;
|
|
199
|
+
} else {
|
|
200
|
+
const newList = transformListRecursively({
|
|
201
|
+
isSourceBulletOrOrdered,
|
|
202
|
+
isSourceTask,
|
|
203
|
+
isTargetBulletOrOrdered,
|
|
204
|
+
isTargetTask,
|
|
205
|
+
listNode: node,
|
|
206
|
+
schema,
|
|
207
|
+
supportedListTypes,
|
|
208
|
+
targetNodeType
|
|
209
|
+
});
|
|
210
|
+
newListItems = [...newList.content.content];
|
|
211
|
+
}
|
|
212
|
+
} else if (isHeadingOrParagraphNode(node) || isValid(node)) {
|
|
213
|
+
if (isTargetTask) {
|
|
214
|
+
const inlineContent = [...node.content.content];
|
|
215
|
+
if (inlineContent.length > 0) {
|
|
216
|
+
newListItems = [listItemType.create(null, inlineContent)];
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
newListItems = [listItemType.create(null, node)];
|
|
220
|
+
}
|
|
221
|
+
} else if (!isValid(node)) {
|
|
222
|
+
listItems.push({
|
|
223
|
+
canBeTransformed: false,
|
|
224
|
+
node
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
if (newListItems) {
|
|
228
|
+
if (listItems.length === 0) {
|
|
229
|
+
listItems.push({
|
|
230
|
+
canBeTransformed: true,
|
|
231
|
+
node: newListItems
|
|
232
|
+
});
|
|
233
|
+
} else {
|
|
234
|
+
const lastItem = listItems[listItems.length - 1];
|
|
235
|
+
if (lastItem.canBeTransformed) {
|
|
236
|
+
listItems[listItems.length - 1] = {
|
|
237
|
+
node: [...lastItem.node, ...newListItems],
|
|
238
|
+
canBeTransformed: true
|
|
239
|
+
};
|
|
240
|
+
} else {
|
|
241
|
+
listItems.push({
|
|
242
|
+
node: newListItems,
|
|
243
|
+
canBeTransformed: true
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
return listItems.map(({
|
|
251
|
+
node,
|
|
252
|
+
canBeTransformed
|
|
253
|
+
}) => {
|
|
254
|
+
if (canBeTransformed) {
|
|
255
|
+
return targetNodeType.createChecked(null, Fragment.fromArray(node));
|
|
256
|
+
} else {
|
|
257
|
+
return node;
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
export const convertUnwrappedLayoutContent = (nodes, targetNodeType, schema) => {
|
|
262
|
+
if (isBlockNodeType(targetNodeType)) {
|
|
263
|
+
return transformToBlockNode(nodes, targetNodeType, schema);
|
|
264
|
+
}
|
|
265
|
+
if (isContainerNodeType(targetNodeType)) {
|
|
266
|
+
return transformToContainerNode(nodes, targetNodeType);
|
|
267
|
+
}
|
|
268
|
+
if (isListNodeType(targetNodeType)) {
|
|
269
|
+
return transformToListNode(nodes, targetNodeType, schema);
|
|
270
|
+
}
|
|
271
|
+
return [];
|
|
272
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_TWO_COLUMN_LAYOUT_COLUMN_WIDTH } from '@atlaskit/editor-common/styles';
|
|
2
2
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
import { convertUnwrappedLayoutContent, unwrapLayoutNodesToTextNodes } from './layout/utils';
|
|
3
4
|
export const convertToLayout = context => {
|
|
4
5
|
const {
|
|
5
6
|
tr,
|
|
@@ -20,6 +21,44 @@ export const convertToLayout = context => {
|
|
|
20
21
|
const layoutSectionNode = layoutSection.createChecked(undefined, layoutContent);
|
|
21
22
|
|
|
22
23
|
// Replace the original node with the new layout node
|
|
23
|
-
tr.replaceRangeWith(sourcePos
|
|
24
|
+
tr.replaceRangeWith(sourcePos, sourcePos + sourceNode.nodeSize, layoutSectionNode);
|
|
24
25
|
return tr;
|
|
26
|
+
};
|
|
27
|
+
export const transformLayoutNode = context => {
|
|
28
|
+
const {
|
|
29
|
+
tr,
|
|
30
|
+
sourceNode,
|
|
31
|
+
targetNodeType,
|
|
32
|
+
sourcePos,
|
|
33
|
+
targetAttrs
|
|
34
|
+
} = context;
|
|
35
|
+
const schema = tr.doc.type.schema || {};
|
|
36
|
+
const {
|
|
37
|
+
layoutSection,
|
|
38
|
+
layoutColumn,
|
|
39
|
+
paragraph,
|
|
40
|
+
heading
|
|
41
|
+
} = schema.nodes || {};
|
|
42
|
+
const layoutColumnNodes = [];
|
|
43
|
+
const targetTextNodeType = targetNodeType === heading ? heading : paragraph;
|
|
44
|
+
sourceNode.children.forEach(child => {
|
|
45
|
+
if (child.type === layoutColumn) {
|
|
46
|
+
const unwrappedContent = [];
|
|
47
|
+
child.content.forEach(node => {
|
|
48
|
+
// Unwrap all nodes and convert to text nodes
|
|
49
|
+
const context = {
|
|
50
|
+
tr,
|
|
51
|
+
sourceNode: node,
|
|
52
|
+
targetNodeType: targetTextNodeType,
|
|
53
|
+
sourcePos: 0,
|
|
54
|
+
targetAttrs
|
|
55
|
+
};
|
|
56
|
+
const newContent = unwrapLayoutNodesToTextNodes(context, targetNodeType);
|
|
57
|
+
unwrappedContent.push(...newContent);
|
|
58
|
+
});
|
|
59
|
+
const newColumnContent = convertUnwrappedLayoutContent(unwrappedContent, targetNodeType, schema);
|
|
60
|
+
layoutColumnNodes.push(layoutColumn.createChecked(child.attrs, Fragment.fromArray(newColumnContent), child.marks));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return tr.replaceRangeWith(sourcePos, sourcePos + sourceNode.nodeSize, layoutSection.createChecked(sourceNode.attrs, Fragment.fromArray(layoutColumnNodes), sourceNode.marks));
|
|
25
64
|
};
|
|
@@ -16,6 +16,88 @@ const convertBlockToInlineContent = (node, schema) => {
|
|
|
16
16
|
}
|
|
17
17
|
return [node];
|
|
18
18
|
};
|
|
19
|
+
export const transformListRecursively = props => {
|
|
20
|
+
const transformedItems = [];
|
|
21
|
+
const {
|
|
22
|
+
listNode,
|
|
23
|
+
isSourceBulletOrOrdered,
|
|
24
|
+
isTargetBulletOrOrdered,
|
|
25
|
+
isSourceTask,
|
|
26
|
+
isTargetTask,
|
|
27
|
+
supportedListTypes,
|
|
28
|
+
schema,
|
|
29
|
+
targetNodeType
|
|
30
|
+
} = props;
|
|
31
|
+
const {
|
|
32
|
+
taskList,
|
|
33
|
+
listItem,
|
|
34
|
+
taskItem,
|
|
35
|
+
paragraph
|
|
36
|
+
} = schema.nodes;
|
|
37
|
+
listNode.forEach(child => {
|
|
38
|
+
if (isSourceBulletOrOrdered && isTargetTask) {
|
|
39
|
+
// Convert bullet/ordered => task
|
|
40
|
+
if (child.type === listItem) {
|
|
41
|
+
const inlineContent = [];
|
|
42
|
+
const nestedTaskLists = [];
|
|
43
|
+
child.forEach(grandChild => {
|
|
44
|
+
if (supportedListTypes.has(grandChild.type) && grandChild.type !== taskList) {
|
|
45
|
+
nestedTaskLists.push(transformListRecursively({
|
|
46
|
+
...props,
|
|
47
|
+
listNode: grandChild
|
|
48
|
+
}));
|
|
49
|
+
} else {
|
|
50
|
+
inlineContent.push(...convertBlockToInlineContent(grandChild, schema));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
if (inlineContent.length > 0) {
|
|
54
|
+
transformedItems.push(taskItem.create(null, inlineContent));
|
|
55
|
+
}
|
|
56
|
+
transformedItems.push(...nestedTaskLists);
|
|
57
|
+
}
|
|
58
|
+
} else if (isSourceTask && isTargetBulletOrOrdered) {
|
|
59
|
+
// Convert task => bullet/ordered
|
|
60
|
+
if (child.type === taskItem) {
|
|
61
|
+
const inlineContent = [...child.content.content];
|
|
62
|
+
if (inlineContent.length > 0) {
|
|
63
|
+
const paragraphNode = paragraph.create(null, inlineContent);
|
|
64
|
+
transformedItems.push(listItem.create(null, [paragraphNode]));
|
|
65
|
+
}
|
|
66
|
+
} else if (child.type === taskList) {
|
|
67
|
+
const transformedNestedList = transformListRecursively({
|
|
68
|
+
...props,
|
|
69
|
+
listNode: child
|
|
70
|
+
});
|
|
71
|
+
const lastItem = transformedItems[transformedItems.length - 1];
|
|
72
|
+
if ((lastItem === null || lastItem === void 0 ? void 0 : lastItem.type) === listItem) {
|
|
73
|
+
// Attach nested list to previous item
|
|
74
|
+
const updatedContent = [...lastItem.content.content, transformedNestedList];
|
|
75
|
+
transformedItems[transformedItems.length - 1] = listItem.create(lastItem.attrs, updatedContent);
|
|
76
|
+
} else {
|
|
77
|
+
// No previous item, flatten nested items
|
|
78
|
+
transformedItems.push(...transformedNestedList.content.content);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
} else if (isSourceBulletOrOrdered && isTargetBulletOrOrdered) {
|
|
82
|
+
if (child.type === listItem) {
|
|
83
|
+
const convertedNestedLists = [];
|
|
84
|
+
child.forEach(grandChild => {
|
|
85
|
+
if (supportedListTypes.has(grandChild.type) && grandChild.type !== targetNodeType) {
|
|
86
|
+
const convertedNode = transformListRecursively({
|
|
87
|
+
...props,
|
|
88
|
+
listNode: grandChild
|
|
89
|
+
});
|
|
90
|
+
convertedNestedLists.push(convertedNode);
|
|
91
|
+
} else {
|
|
92
|
+
convertedNestedLists.push(grandChild);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
transformedItems.push(listItem.create(null, convertedNestedLists));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return targetNodeType.create(null, transformedItems);
|
|
100
|
+
};
|
|
19
101
|
|
|
20
102
|
/**
|
|
21
103
|
* Transform list structure between different list types
|
|
@@ -37,62 +119,23 @@ export const transformListStructure = context => {
|
|
|
37
119
|
node: sourceList,
|
|
38
120
|
pos: listPos
|
|
39
121
|
} = listNode;
|
|
40
|
-
const {
|
|
41
|
-
|
|
42
|
-
listItem,
|
|
43
|
-
taskItem,
|
|
44
|
-
paragraph
|
|
45
|
-
} = nodes;
|
|
122
|
+
// const { taskList, listItem, taskItem, paragraph } = nodes;
|
|
123
|
+
|
|
46
124
|
const isSourceBulletOrOrdered = isBulletOrOrderedList(sourceList.type);
|
|
47
125
|
const isTargetTask = isTaskList(targetNodeType);
|
|
48
126
|
const isSourceTask = isTaskList(sourceList.type);
|
|
49
127
|
const isTargetBulletOrOrdered = isBulletOrOrderedList(targetNodeType);
|
|
50
128
|
const supportedListTypes = getSupportedListTypesSet(nodes);
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
nestedTaskLists.push(transformListRecursively(grandChild));
|
|
62
|
-
} else {
|
|
63
|
-
inlineContent.push(...convertBlockToInlineContent(grandChild, tr.doc.type.schema));
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
if (inlineContent.length > 0) {
|
|
67
|
-
transformedItems.push(taskItem.create(null, inlineContent));
|
|
68
|
-
}
|
|
69
|
-
transformedItems.push(...nestedTaskLists);
|
|
70
|
-
}
|
|
71
|
-
} else if (isSourceTask && isTargetBulletOrOrdered) {
|
|
72
|
-
// Convert task => bullet/ordered
|
|
73
|
-
if (child.type === taskItem) {
|
|
74
|
-
const inlineContent = [...child.content.content];
|
|
75
|
-
if (inlineContent.length > 0) {
|
|
76
|
-
const paragraphNode = paragraph.create(null, inlineContent);
|
|
77
|
-
transformedItems.push(listItem.create(null, [paragraphNode]));
|
|
78
|
-
}
|
|
79
|
-
} else if (child.type === taskList) {
|
|
80
|
-
const transformedNestedList = transformListRecursively(child);
|
|
81
|
-
const lastItem = transformedItems[transformedItems.length - 1];
|
|
82
|
-
if ((lastItem === null || lastItem === void 0 ? void 0 : lastItem.type) === listItem) {
|
|
83
|
-
// Attach nested list to previous item
|
|
84
|
-
const updatedContent = [...lastItem.content.content, transformedNestedList];
|
|
85
|
-
transformedItems[transformedItems.length - 1] = listItem.create(lastItem.attrs, updatedContent);
|
|
86
|
-
} else {
|
|
87
|
-
// No previous item, flatten nested items
|
|
88
|
-
transformedItems.push(...transformedNestedList.content.content);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
return targetNodeType.create(null, transformedItems);
|
|
94
|
-
};
|
|
95
|
-
const newList = transformListRecursively(sourceList);
|
|
129
|
+
const newList = transformListRecursively({
|
|
130
|
+
isSourceBulletOrOrdered,
|
|
131
|
+
isSourceTask,
|
|
132
|
+
isTargetBulletOrOrdered,
|
|
133
|
+
isTargetTask,
|
|
134
|
+
listNode: sourceList,
|
|
135
|
+
schema: tr.doc.type.schema,
|
|
136
|
+
supportedListTypes,
|
|
137
|
+
targetNodeType
|
|
138
|
+
});
|
|
96
139
|
tr.replaceWith(listPos, listPos + sourceList.nodeSize, newList);
|
|
97
140
|
return tr;
|
|
98
141
|
} catch {
|