@atlaskit/editor-plugin-block-menu 1.0.10 → 1.0.12
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 +22 -0
- package/dist/cjs/editor-commands/transforms/container-transforms.js +90 -29
- package/dist/cjs/editor-commands/transforms/list-transforms.js +7 -0
- package/dist/cjs/editor-commands/transforms/utils.js +34 -1
- package/dist/cjs/ui/utils/isNestedNode.js +6 -0
- package/dist/es2019/editor-commands/transforms/container-transforms.js +90 -27
- package/dist/es2019/editor-commands/transforms/list-transforms.js +7 -0
- package/dist/es2019/editor-commands/transforms/utils.js +33 -0
- package/dist/es2019/ui/utils/isNestedNode.js +6 -0
- package/dist/esm/editor-commands/transforms/container-transforms.js +90 -29
- package/dist/esm/editor-commands/transforms/list-transforms.js +7 -0
- package/dist/esm/editor-commands/transforms/utils.js +33 -0
- package/dist/esm/ui/utils/isNestedNode.js +6 -0
- package/dist/types/editor-commands/transforms/utils.d.ts +11 -0
- package/dist/types-ts4.5/editor-commands/transforms/utils.d.ts +11 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-block-menu
|
|
2
2
|
|
|
3
|
+
## 1.0.12
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`6e27819feadc7`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6e27819feadc7) -
|
|
8
|
+
ED-29183: Fixed aligned p and heading not able to convert to list
|
|
9
|
+
- [`6a9265f5389db`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6a9265f5389db) -
|
|
10
|
+
Fix container transform with blockquote containing list
|
|
11
|
+
- [`24e0d952943aa`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/24e0d952943aa) -
|
|
12
|
+
ED-29206: Fixed conversion from code block to panel, expand text formatting issue
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
|
|
15
|
+
## 1.0.11
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [`fcef7ff2e1083`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/fcef7ff2e1083) -
|
|
20
|
+
Split unsupported content when converting to codeblock
|
|
21
|
+
- [`1754f5027f568`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1754f5027f568) -
|
|
22
|
+
Fix missing copy link on table node
|
|
23
|
+
- Updated dependencies
|
|
24
|
+
|
|
3
25
|
## 1.0.10
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -20,19 +20,6 @@ var convertInvalidNodeToValidNodeType = function convertInvalidNodeToValidNodeTy
|
|
|
20
20
|
});
|
|
21
21
|
return _model.Fragment.from(validTransformedContent);
|
|
22
22
|
};
|
|
23
|
-
var filterMarksForTargetNodeType = function filterMarksForTargetNodeType(content, targetNodeType) {
|
|
24
|
-
var withValidMarks = [];
|
|
25
|
-
content.forEach(function (node) {
|
|
26
|
-
if (node.marks.length > 0) {
|
|
27
|
-
var allowedMarks = targetNodeType.allowedMarks(node.marks);
|
|
28
|
-
var updatedNode = node.mark(allowedMarks);
|
|
29
|
-
withValidMarks.push(updatedNode);
|
|
30
|
-
} else {
|
|
31
|
-
withValidMarks.push(node);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
return _model.Fragment.from(withValidMarks);
|
|
35
|
-
};
|
|
36
23
|
|
|
37
24
|
/**
|
|
38
25
|
* Transform selection to container type
|
|
@@ -47,7 +34,8 @@ var transformToContainer = exports.transformToContainer = function transformToCo
|
|
|
47
34
|
var content = selection.content().content;
|
|
48
35
|
var transformedContent = content;
|
|
49
36
|
if (sourceNode.type === schema.nodes.codeBlock) {
|
|
50
|
-
|
|
37
|
+
var paragraphNodes = (0, _utils.convertCodeBlockContentToParagraphs)(sourceNode, schema);
|
|
38
|
+
transformedContent = _model.Fragment.fromArray(paragraphNodes);
|
|
51
39
|
}
|
|
52
40
|
if (targetNodeType === schema.nodes.blockquote) {
|
|
53
41
|
transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.heading, schema.nodes.paragraph, true);
|
|
@@ -57,7 +45,7 @@ var transformToContainer = exports.transformToContainer = function transformToCo
|
|
|
57
45
|
// e.g. blocks (heading/ paragraph) with alignment need to remove alignment
|
|
58
46
|
// as panel/ blockQuote/ expands does not support alignment
|
|
59
47
|
if (sourceNode.type === schema.nodes.paragraph || sourceNode.type === schema.nodes.heading) {
|
|
60
|
-
transformedContent = filterMarksForTargetNodeType(transformedContent, targetNodeType);
|
|
48
|
+
transformedContent = (0, _utils.filterMarksForTargetNodeType)(transformedContent, targetNodeType);
|
|
61
49
|
}
|
|
62
50
|
var newNode = targetNodeType.createAndFill(targetAttrs, transformedContent);
|
|
63
51
|
if (!newNode) {
|
|
@@ -82,6 +70,16 @@ var transformContainerNode = exports.transformContainerNode = function transform
|
|
|
82
70
|
|
|
83
71
|
// Transform container to block type - unwrap and convert content
|
|
84
72
|
if ((0, _utils.isBlockNodeType)(targetNodeType)) {
|
|
73
|
+
// special case container to codeblock
|
|
74
|
+
if (targetNodeType.name === 'codeBlock') {
|
|
75
|
+
return transformBetweenContainerTypes({
|
|
76
|
+
tr: tr,
|
|
77
|
+
sourceNode: sourceNode,
|
|
78
|
+
sourcePos: sourcePos,
|
|
79
|
+
targetNodeType: targetNodeType,
|
|
80
|
+
targetAttrs: targetAttrs
|
|
81
|
+
});
|
|
82
|
+
}
|
|
85
83
|
return unwrapAndConvertToBlockType({
|
|
86
84
|
tr: tr,
|
|
87
85
|
sourceNode: sourceNode,
|
|
@@ -148,12 +146,7 @@ var unwrapAndConvertToBlockType = exports.unwrapAndConvertToBlockType = function
|
|
|
148
146
|
|
|
149
147
|
// if the container is a code block, convert text content to multiple paragraphs
|
|
150
148
|
if (sourceNode.type === codeBlock) {
|
|
151
|
-
|
|
152
|
-
var lines = codeText.split('\n');
|
|
153
|
-
var paragraphNodes = lines.map(function (line) {
|
|
154
|
-
return paragraph.create(null, line ? schema.text(line) : null);
|
|
155
|
-
});
|
|
156
|
-
sourceChildren = paragraphNodes;
|
|
149
|
+
sourceChildren = (0, _utils.convertCodeBlockContentToParagraphs)(sourceNode, schema);
|
|
157
150
|
}
|
|
158
151
|
|
|
159
152
|
// if target node is a paragraph, just do unwrap
|
|
@@ -274,18 +267,29 @@ var transformBetweenContainerTypes = exports.transformBetweenContainerTypes = fu
|
|
|
274
267
|
targetNodeType = context.targetNodeType,
|
|
275
268
|
targetAttrs = context.targetAttrs;
|
|
276
269
|
|
|
270
|
+
// Special handling for codeBlock target
|
|
271
|
+
if (targetNodeType.name === 'codeBlock') {
|
|
272
|
+
var _contentSplits = splitContentForCodeBlock(sourceNode, targetNodeType, targetAttrs, tr.doc.type.schema);
|
|
273
|
+
return applySplitsToTransaction(tr, sourcePos, sourceNode.nodeSize, _contentSplits);
|
|
274
|
+
}
|
|
275
|
+
|
|
277
276
|
// Get content validation for target container type
|
|
278
277
|
var isContentSupported = (0, _utils.getContentSupportChecker)(targetNodeType);
|
|
279
278
|
|
|
280
279
|
// Process content and collect splits
|
|
281
280
|
var contentSplits = splitContentAroundUnsupportedBlocks(sourceNode, isContentSupported, targetNodeType, targetAttrs, tr.doc.type.schema);
|
|
281
|
+
return applySplitsToTransaction(tr, sourcePos, sourceNode.nodeSize, contentSplits);
|
|
282
|
+
};
|
|
282
283
|
|
|
283
|
-
|
|
284
|
+
/**
|
|
285
|
+
* Apply content splits to transaction - shared utility for replacing and inserting splits
|
|
286
|
+
*/
|
|
287
|
+
var applySplitsToTransaction = function applySplitsToTransaction(tr, sourcePos, sourceNodeSize, contentSplits) {
|
|
284
288
|
var insertPos = sourcePos;
|
|
285
289
|
contentSplits.forEach(function (splitNode, index) {
|
|
286
290
|
if (index === 0) {
|
|
287
291
|
// Replace the original node with the first split
|
|
288
|
-
tr.replaceWith(sourcePos, sourcePos +
|
|
292
|
+
tr.replaceWith(sourcePos, sourcePos + sourceNodeSize, splitNode);
|
|
289
293
|
insertPos = sourcePos + splitNode.nodeSize;
|
|
290
294
|
} else {
|
|
291
295
|
// Insert additional splits after
|
|
@@ -296,18 +300,75 @@ var transformBetweenContainerTypes = exports.transformBetweenContainerTypes = fu
|
|
|
296
300
|
return tr;
|
|
297
301
|
};
|
|
298
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Split content for codeBlock transformation, creating codeBlocks for text content
|
|
305
|
+
* and preserving unsupported blocks (like tables) separately
|
|
306
|
+
*/
|
|
307
|
+
var splitContentForCodeBlock = function splitContentForCodeBlock(sourceNode, targetNodeType, targetAttrs, schema) {
|
|
308
|
+
var _sourceNode$attrs3;
|
|
309
|
+
var splits = [];
|
|
310
|
+
var children = sourceNode.content.content;
|
|
311
|
+
var currentTextContent = [];
|
|
312
|
+
|
|
313
|
+
// Handle expand title - add as first text if source is expand with title
|
|
314
|
+
if (sourceNode.type.name === 'expand' && (_sourceNode$attrs3 = sourceNode.attrs) !== null && _sourceNode$attrs3 !== void 0 && _sourceNode$attrs3.title) {
|
|
315
|
+
currentTextContent.push(sourceNode.attrs.title);
|
|
316
|
+
}
|
|
317
|
+
var flushCurrentCodeBlock = function flushCurrentCodeBlock() {
|
|
318
|
+
if (currentTextContent.length > 0) {
|
|
319
|
+
var codeText = currentTextContent.join('\n');
|
|
320
|
+
var codeBlockNode = targetNodeType.create(targetAttrs, schema.text(codeText));
|
|
321
|
+
splits.push(codeBlockNode);
|
|
322
|
+
currentTextContent = [];
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
var isCodeBlockCompatible = function isCodeBlockCompatible(node) {
|
|
326
|
+
// Only text blocks (paragraph, heading) can be converted to codeBlock text
|
|
327
|
+
return node.isTextblock || node.type.name === 'codeBlock';
|
|
328
|
+
};
|
|
329
|
+
children.forEach(function (childNode) {
|
|
330
|
+
if (isCodeBlockCompatible(childNode)) {
|
|
331
|
+
// Extract text content from compatible nodes
|
|
332
|
+
if (childNode.type.name === 'codeBlock') {
|
|
333
|
+
// If it's already a codeBlock, extract its text
|
|
334
|
+
currentTextContent.push(childNode.textContent);
|
|
335
|
+
} else if (childNode.isTextblock) {
|
|
336
|
+
// Extract text from text blocks (paragraphs, headings, etc.)
|
|
337
|
+
var text = childNode.textContent;
|
|
338
|
+
if (text.trim()) {
|
|
339
|
+
currentTextContent.push(text);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
} else if ((0, _utils.isBlockNodeForExtraction)(childNode)) {
|
|
343
|
+
// Unsupported block node (table, etc.) - flush current codeBlock, add block, continue
|
|
344
|
+
flushCurrentCodeBlock();
|
|
345
|
+
splits.push(childNode);
|
|
346
|
+
} else {
|
|
347
|
+
// Other unsupported content - try to extract text if possible
|
|
348
|
+
var _text = childNode.textContent;
|
|
349
|
+
if (_text && _text.trim()) {
|
|
350
|
+
currentTextContent.push(_text);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// Flush any remaining text content as a codeBlock
|
|
356
|
+
flushCurrentCodeBlock();
|
|
357
|
+
return splits;
|
|
358
|
+
};
|
|
359
|
+
|
|
299
360
|
/**
|
|
300
361
|
* Split content around unsupported block nodes, creating separate containers
|
|
301
362
|
* for content before and after each unsupported block
|
|
302
363
|
*/
|
|
303
364
|
var splitContentAroundUnsupportedBlocks = function splitContentAroundUnsupportedBlocks(sourceNode, isContentSupported, targetNodeType, targetAttrs, schema) {
|
|
304
|
-
var _sourceNode$
|
|
365
|
+
var _sourceNode$attrs4;
|
|
305
366
|
var splits = [];
|
|
306
367
|
var children = sourceNode.content.content;
|
|
307
368
|
var currentContainerContent = [];
|
|
308
369
|
|
|
309
370
|
// Handle expand title - add as first paragraph if source is expand with title
|
|
310
|
-
if (sourceNode.type.name === 'expand' && (_sourceNode$
|
|
371
|
+
if (sourceNode.type.name === 'expand' && (_sourceNode$attrs4 = sourceNode.attrs) !== null && _sourceNode$attrs4 !== void 0 && _sourceNode$attrs4.title) {
|
|
311
372
|
var titleParagraph = schema.nodes.paragraph.create({}, schema.text(sourceNode.attrs.title));
|
|
312
373
|
currentContainerContent.push(titleParagraph);
|
|
313
374
|
}
|
|
@@ -322,15 +383,15 @@ var splitContentAroundUnsupportedBlocks = function splitContentAroundUnsupported
|
|
|
322
383
|
if (isContentSupported(childNode)) {
|
|
323
384
|
// Supported content - add to current container
|
|
324
385
|
currentContainerContent.push(childNode);
|
|
325
|
-
} else if ((0, _utils.isBlockNodeForExtraction)(childNode)) {
|
|
326
|
-
// Unsupported block node - flush current container, add block, continue
|
|
327
|
-
flushCurrentContainer();
|
|
328
|
-
splits.push(childNode);
|
|
329
386
|
} else if (childNode.type.name === targetNodeType.name) {
|
|
330
387
|
// Same type of container merge contents
|
|
331
388
|
childNode.content.forEach(function (child) {
|
|
332
389
|
currentContainerContent.push(child);
|
|
333
390
|
});
|
|
391
|
+
} else if (childNode.isBlock) {
|
|
392
|
+
// Unsupported block node - flush current container, add block, continue
|
|
393
|
+
flushCurrentContainer();
|
|
394
|
+
splits.push(childNode);
|
|
334
395
|
} else {
|
|
335
396
|
// Unsupported inline content - convert to paragraph and add to container
|
|
336
397
|
var inlineContent = (0, _utils.convertNodeToInlineContent)(childNode, schema);
|
|
@@ -24,6 +24,7 @@ var transformBlockToList = exports.transformBlockToList = function transformBloc
|
|
|
24
24
|
var _tr$selection = tr.selection,
|
|
25
25
|
$from = _tr$selection.$from,
|
|
26
26
|
$to = _tr$selection.$to;
|
|
27
|
+
var schema = tr.doc.type.schema;
|
|
27
28
|
var range = $from.blockRange($to);
|
|
28
29
|
if (!range) {
|
|
29
30
|
return null;
|
|
@@ -36,6 +37,12 @@ var transformBlockToList = exports.transformBlockToList = function transformBloc
|
|
|
36
37
|
return (0, _transformToTaskList.transformToTaskList)(tr, range, targetNodeType, targetAttrs, nodes);
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
// filter marks that are not allowed in the target node type
|
|
41
|
+
if (sourceNode.type === schema.nodes.paragraph || sourceNode.type === schema.nodes.heading) {
|
|
42
|
+
var allowedMarks = targetNodeType.allowedMarks(sourceNode.marks);
|
|
43
|
+
tr.setNodeMarkup(range.start, null, null, allowedMarks);
|
|
44
|
+
}
|
|
45
|
+
|
|
39
46
|
// For headings, convert to paragraph first since headings cannot be direct children of list items
|
|
40
47
|
if (sourceNode && sourceNode.type.name.startsWith('heading')) {
|
|
41
48
|
tr.setBlockType(range.start, range.end, nodes.paragraph);
|
|
@@ -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.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) {
|
|
@@ -174,4 +174,37 @@ var convertNodeToInlineContent = exports.convertNodeToInlineContent = function c
|
|
|
174
174
|
return [schema.text(node.textContent)];
|
|
175
175
|
}
|
|
176
176
|
return inlineNodes;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Filter marks from content based on the target node type
|
|
181
|
+
* @param content The content fragment to filter
|
|
182
|
+
* @param targetNodeType The target node type to check against
|
|
183
|
+
* @returns A new fragment with marks filtered for the target node type
|
|
184
|
+
*/
|
|
185
|
+
var filterMarksForTargetNodeType = exports.filterMarksForTargetNodeType = function filterMarksForTargetNodeType(content, targetNodeType) {
|
|
186
|
+
var withValidMarks = [];
|
|
187
|
+
content.forEach(function (node) {
|
|
188
|
+
if (node.marks.length > 0) {
|
|
189
|
+
var allowedMarks = targetNodeType.allowedMarks(node.marks);
|
|
190
|
+
var updatedNode = node.mark(allowedMarks);
|
|
191
|
+
withValidMarks.push(updatedNode);
|
|
192
|
+
} else {
|
|
193
|
+
withValidMarks.push(node);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
return _model.Fragment.from(withValidMarks);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/** * Convert content from a code block node into multiple paragraph nodes
|
|
200
|
+
*/
|
|
201
|
+
var convertCodeBlockContentToParagraphs = exports.convertCodeBlockContentToParagraphs = function convertCodeBlockContentToParagraphs(codeBlockNode, schema) {
|
|
202
|
+
var paragraphNodes = [];
|
|
203
|
+
var codeText = codeBlockNode.textContent;
|
|
204
|
+
var lines = codeText.split('\n');
|
|
205
|
+
lines.forEach(function (line) {
|
|
206
|
+
var paragraphNode = schema.nodes.paragraph.create(null, line ? schema.text(line) : null);
|
|
207
|
+
paragraphNodes.push(paragraphNode);
|
|
208
|
+
});
|
|
209
|
+
return paragraphNodes;
|
|
177
210
|
};
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.isNestedNode = void 0;
|
|
7
7
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
8
|
+
var _editorTables = require("@atlaskit/editor-tables");
|
|
8
9
|
/**
|
|
9
10
|
* Determines if a node is nested (not at top-level) based on its depth and context.
|
|
10
11
|
*
|
|
@@ -37,6 +38,11 @@ var isNestedNode = exports.isNestedNode = function isNestedNode(selection) {
|
|
|
37
38
|
return true;
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
// Special case for table selection
|
|
42
|
+
if (selection instanceof _editorTables.CellSelection) {
|
|
43
|
+
return depth > 3;
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
// Check parent node type for depth 2-3
|
|
41
47
|
var parentNode = $from.node(depth - 1);
|
|
42
48
|
if (!parentNode) {
|
|
@@ -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);
|
|
@@ -76,6 +64,16 @@ export const transformContainerNode = ({
|
|
|
76
64
|
|
|
77
65
|
// Transform container to block type - unwrap and convert content
|
|
78
66
|
if (isBlockNodeType(targetNodeType)) {
|
|
67
|
+
// special case container to codeblock
|
|
68
|
+
if (targetNodeType.name === 'codeBlock') {
|
|
69
|
+
return transformBetweenContainerTypes({
|
|
70
|
+
tr,
|
|
71
|
+
sourceNode,
|
|
72
|
+
sourcePos,
|
|
73
|
+
targetNodeType,
|
|
74
|
+
targetAttrs
|
|
75
|
+
});
|
|
76
|
+
}
|
|
79
77
|
return unwrapAndConvertToBlockType({
|
|
80
78
|
tr,
|
|
81
79
|
sourceNode,
|
|
@@ -147,10 +145,7 @@ export const unwrapAndConvertToBlockType = context => {
|
|
|
147
145
|
|
|
148
146
|
// if the container is a code block, convert text content to multiple paragraphs
|
|
149
147
|
if (sourceNode.type === codeBlock) {
|
|
150
|
-
|
|
151
|
-
const lines = codeText.split('\n');
|
|
152
|
-
const paragraphNodes = lines.map(line => paragraph.create(null, line ? schema.text(line) : null));
|
|
153
|
-
sourceChildren = paragraphNodes;
|
|
148
|
+
sourceChildren = convertCodeBlockContentToParagraphs(sourceNode, schema);
|
|
154
149
|
}
|
|
155
150
|
|
|
156
151
|
// if target node is a paragraph, just do unwrap
|
|
@@ -273,18 +268,29 @@ export const transformBetweenContainerTypes = context => {
|
|
|
273
268
|
targetAttrs
|
|
274
269
|
} = context;
|
|
275
270
|
|
|
271
|
+
// Special handling for codeBlock target
|
|
272
|
+
if (targetNodeType.name === 'codeBlock') {
|
|
273
|
+
const contentSplits = splitContentForCodeBlock(sourceNode, targetNodeType, targetAttrs, tr.doc.type.schema);
|
|
274
|
+
return applySplitsToTransaction(tr, sourcePos, sourceNode.nodeSize, contentSplits);
|
|
275
|
+
}
|
|
276
|
+
|
|
276
277
|
// Get content validation for target container type
|
|
277
278
|
const isContentSupported = getContentSupportChecker(targetNodeType);
|
|
278
279
|
|
|
279
280
|
// Process content and collect splits
|
|
280
281
|
const contentSplits = splitContentAroundUnsupportedBlocks(sourceNode, isContentSupported, targetNodeType, targetAttrs, tr.doc.type.schema);
|
|
282
|
+
return applySplitsToTransaction(tr, sourcePos, sourceNode.nodeSize, contentSplits);
|
|
283
|
+
};
|
|
281
284
|
|
|
282
|
-
|
|
285
|
+
/**
|
|
286
|
+
* Apply content splits to transaction - shared utility for replacing and inserting splits
|
|
287
|
+
*/
|
|
288
|
+
const applySplitsToTransaction = (tr, sourcePos, sourceNodeSize, contentSplits) => {
|
|
283
289
|
let insertPos = sourcePos;
|
|
284
290
|
contentSplits.forEach((splitNode, index) => {
|
|
285
291
|
if (index === 0) {
|
|
286
292
|
// Replace the original node with the first split
|
|
287
|
-
tr.replaceWith(sourcePos, sourcePos +
|
|
293
|
+
tr.replaceWith(sourcePos, sourcePos + sourceNodeSize, splitNode);
|
|
288
294
|
insertPos = sourcePos + splitNode.nodeSize;
|
|
289
295
|
} else {
|
|
290
296
|
// Insert additional splits after
|
|
@@ -295,18 +301,75 @@ export const transformBetweenContainerTypes = context => {
|
|
|
295
301
|
return tr;
|
|
296
302
|
};
|
|
297
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Split content for codeBlock transformation, creating codeBlocks for text content
|
|
306
|
+
* and preserving unsupported blocks (like tables) separately
|
|
307
|
+
*/
|
|
308
|
+
const splitContentForCodeBlock = (sourceNode, targetNodeType, targetAttrs, schema) => {
|
|
309
|
+
var _sourceNode$attrs3;
|
|
310
|
+
const splits = [];
|
|
311
|
+
const children = sourceNode.content.content;
|
|
312
|
+
let currentTextContent = [];
|
|
313
|
+
|
|
314
|
+
// Handle expand title - add as first text if source is expand with title
|
|
315
|
+
if (sourceNode.type.name === 'expand' && (_sourceNode$attrs3 = sourceNode.attrs) !== null && _sourceNode$attrs3 !== void 0 && _sourceNode$attrs3.title) {
|
|
316
|
+
currentTextContent.push(sourceNode.attrs.title);
|
|
317
|
+
}
|
|
318
|
+
const flushCurrentCodeBlock = () => {
|
|
319
|
+
if (currentTextContent.length > 0) {
|
|
320
|
+
const codeText = currentTextContent.join('\n');
|
|
321
|
+
const codeBlockNode = targetNodeType.create(targetAttrs, schema.text(codeText));
|
|
322
|
+
splits.push(codeBlockNode);
|
|
323
|
+
currentTextContent = [];
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
const isCodeBlockCompatible = node => {
|
|
327
|
+
// Only text blocks (paragraph, heading) can be converted to codeBlock text
|
|
328
|
+
return node.isTextblock || node.type.name === 'codeBlock';
|
|
329
|
+
};
|
|
330
|
+
children.forEach(childNode => {
|
|
331
|
+
if (isCodeBlockCompatible(childNode)) {
|
|
332
|
+
// Extract text content from compatible nodes
|
|
333
|
+
if (childNode.type.name === 'codeBlock') {
|
|
334
|
+
// If it's already a codeBlock, extract its text
|
|
335
|
+
currentTextContent.push(childNode.textContent);
|
|
336
|
+
} else if (childNode.isTextblock) {
|
|
337
|
+
// Extract text from text blocks (paragraphs, headings, etc.)
|
|
338
|
+
const text = childNode.textContent;
|
|
339
|
+
if (text.trim()) {
|
|
340
|
+
currentTextContent.push(text);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
} else if (isBlockNodeForExtraction(childNode)) {
|
|
344
|
+
// Unsupported block node (table, etc.) - flush current codeBlock, add block, continue
|
|
345
|
+
flushCurrentCodeBlock();
|
|
346
|
+
splits.push(childNode);
|
|
347
|
+
} else {
|
|
348
|
+
// Other unsupported content - try to extract text if possible
|
|
349
|
+
const text = childNode.textContent;
|
|
350
|
+
if (text && text.trim()) {
|
|
351
|
+
currentTextContent.push(text);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// Flush any remaining text content as a codeBlock
|
|
357
|
+
flushCurrentCodeBlock();
|
|
358
|
+
return splits;
|
|
359
|
+
};
|
|
360
|
+
|
|
298
361
|
/**
|
|
299
362
|
* Split content around unsupported block nodes, creating separate containers
|
|
300
363
|
* for content before and after each unsupported block
|
|
301
364
|
*/
|
|
302
365
|
const splitContentAroundUnsupportedBlocks = (sourceNode, isContentSupported, targetNodeType, targetAttrs, schema) => {
|
|
303
|
-
var _sourceNode$
|
|
366
|
+
var _sourceNode$attrs4;
|
|
304
367
|
const splits = [];
|
|
305
368
|
const children = sourceNode.content.content;
|
|
306
369
|
let currentContainerContent = [];
|
|
307
370
|
|
|
308
371
|
// Handle expand title - add as first paragraph if source is expand with title
|
|
309
|
-
if (sourceNode.type.name === 'expand' && (_sourceNode$
|
|
372
|
+
if (sourceNode.type.name === 'expand' && (_sourceNode$attrs4 = sourceNode.attrs) !== null && _sourceNode$attrs4 !== void 0 && _sourceNode$attrs4.title) {
|
|
310
373
|
const titleParagraph = schema.nodes.paragraph.create({}, schema.text(sourceNode.attrs.title));
|
|
311
374
|
currentContainerContent.push(titleParagraph);
|
|
312
375
|
}
|
|
@@ -321,15 +384,15 @@ const splitContentAroundUnsupportedBlocks = (sourceNode, isContentSupported, tar
|
|
|
321
384
|
if (isContentSupported(childNode)) {
|
|
322
385
|
// Supported content - add to current container
|
|
323
386
|
currentContainerContent.push(childNode);
|
|
324
|
-
} else if (isBlockNodeForExtraction(childNode)) {
|
|
325
|
-
// Unsupported block node - flush current container, add block, continue
|
|
326
|
-
flushCurrentContainer();
|
|
327
|
-
splits.push(childNode);
|
|
328
387
|
} else if (childNode.type.name === targetNodeType.name) {
|
|
329
388
|
// Same type of container merge contents
|
|
330
389
|
childNode.content.forEach(child => {
|
|
331
390
|
currentContainerContent.push(child);
|
|
332
391
|
});
|
|
392
|
+
} else if (childNode.isBlock) {
|
|
393
|
+
// Unsupported block node - flush current container, add block, continue
|
|
394
|
+
flushCurrentContainer();
|
|
395
|
+
splits.push(childNode);
|
|
333
396
|
} else {
|
|
334
397
|
// Unsupported inline content - convert to paragraph and add to container
|
|
335
398
|
const inlineContent = convertNodeToInlineContent(childNode, schema);
|
|
@@ -20,6 +20,7 @@ export const transformBlockToList = context => {
|
|
|
20
20
|
$from,
|
|
21
21
|
$to
|
|
22
22
|
} = tr.selection;
|
|
23
|
+
const schema = tr.doc.type.schema;
|
|
23
24
|
const range = $from.blockRange($to);
|
|
24
25
|
if (!range) {
|
|
25
26
|
return null;
|
|
@@ -34,6 +35,12 @@ export const transformBlockToList = context => {
|
|
|
34
35
|
return transformToTaskList(tr, range, targetNodeType, targetAttrs, nodes);
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
// filter marks that are not allowed in the target node type
|
|
39
|
+
if (sourceNode.type === schema.nodes.paragraph || sourceNode.type === schema.nodes.heading) {
|
|
40
|
+
const allowedMarks = targetNodeType.allowedMarks(sourceNode.marks);
|
|
41
|
+
tr.setNodeMarkup(range.start, null, null, allowedMarks);
|
|
42
|
+
}
|
|
43
|
+
|
|
37
44
|
// For headings, convert to paragraph first since headings cannot be direct children of list items
|
|
38
45
|
if (sourceNode && sourceNode.type.name.startsWith('heading')) {
|
|
39
46
|
tr.setBlockType(range.start, range.end, nodes.paragraph);
|
|
@@ -168,4 +168,37 @@ export const convertNodeToInlineContent = (node, schema) => {
|
|
|
168
168
|
return [schema.text(node.textContent)];
|
|
169
169
|
}
|
|
170
170
|
return inlineNodes;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Filter marks from content based on the target node type
|
|
175
|
+
* @param content The content fragment to filter
|
|
176
|
+
* @param targetNodeType The target node type to check against
|
|
177
|
+
* @returns A new fragment with marks filtered for the target node type
|
|
178
|
+
*/
|
|
179
|
+
export const filterMarksForTargetNodeType = (content, targetNodeType) => {
|
|
180
|
+
const withValidMarks = [];
|
|
181
|
+
content.forEach(node => {
|
|
182
|
+
if (node.marks.length > 0) {
|
|
183
|
+
const allowedMarks = targetNodeType.allowedMarks(node.marks);
|
|
184
|
+
const updatedNode = node.mark(allowedMarks);
|
|
185
|
+
withValidMarks.push(updatedNode);
|
|
186
|
+
} else {
|
|
187
|
+
withValidMarks.push(node);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return Fragment.from(withValidMarks);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/** * Convert content from a code block node into multiple paragraph nodes
|
|
194
|
+
*/
|
|
195
|
+
export const convertCodeBlockContentToParagraphs = (codeBlockNode, schema) => {
|
|
196
|
+
const paragraphNodes = [];
|
|
197
|
+
const codeText = codeBlockNode.textContent;
|
|
198
|
+
const lines = codeText.split('\n');
|
|
199
|
+
lines.forEach(line => {
|
|
200
|
+
const paragraphNode = schema.nodes.paragraph.create(null, line ? schema.text(line) : null);
|
|
201
|
+
paragraphNodes.push(paragraphNode);
|
|
202
|
+
});
|
|
203
|
+
return paragraphNodes;
|
|
171
204
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import { CellSelection } from '@atlaskit/editor-tables';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Determines if a node is nested (not at top-level) based on its depth and context.
|
|
@@ -34,6 +35,11 @@ export const isNestedNode = selection => {
|
|
|
34
35
|
return true;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
// Special case for table selection
|
|
39
|
+
if (selection instanceof CellSelection) {
|
|
40
|
+
return depth > 3;
|
|
41
|
+
}
|
|
42
|
+
|
|
37
43
|
// Check parent node type for depth 2-3
|
|
38
44
|
const parentNode = $from.node(depth - 1);
|
|
39
45
|
if (!parentNode) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
2
|
import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
-
import { isBlockNodeType, isListNodeType, isContainerNodeType, isBlockNodeForExtraction, convertNodeToInlineContent, getContentSupportChecker } from './utils';
|
|
3
|
+
import { isBlockNodeType, isListNodeType, isContainerNodeType, isBlockNodeForExtraction, convertNodeToInlineContent, getContentSupportChecker, convertCodeBlockContentToParagraphs, filterMarksForTargetNodeType } from './utils';
|
|
4
4
|
var convertInvalidNodeToValidNodeType = function convertInvalidNodeToValidNodeType(sourceContent, sourceNodeType, validNodeType, withMarks) {
|
|
5
5
|
var validTransformedContent = [];
|
|
6
6
|
// Headings are not valid inside headings so convert heading nodes to paragraphs
|
|
@@ -13,19 +13,6 @@ var convertInvalidNodeToValidNodeType = function convertInvalidNodeToValidNodeTy
|
|
|
13
13
|
});
|
|
14
14
|
return Fragment.from(validTransformedContent);
|
|
15
15
|
};
|
|
16
|
-
var filterMarksForTargetNodeType = function filterMarksForTargetNodeType(content, targetNodeType) {
|
|
17
|
-
var withValidMarks = [];
|
|
18
|
-
content.forEach(function (node) {
|
|
19
|
-
if (node.marks.length > 0) {
|
|
20
|
-
var allowedMarks = targetNodeType.allowedMarks(node.marks);
|
|
21
|
-
var updatedNode = node.mark(allowedMarks);
|
|
22
|
-
withValidMarks.push(updatedNode);
|
|
23
|
-
} else {
|
|
24
|
-
withValidMarks.push(node);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
return Fragment.from(withValidMarks);
|
|
28
|
-
};
|
|
29
16
|
|
|
30
17
|
/**
|
|
31
18
|
* Transform selection to container type
|
|
@@ -40,7 +27,8 @@ export var transformToContainer = function transformToContainer(_ref) {
|
|
|
40
27
|
var content = selection.content().content;
|
|
41
28
|
var transformedContent = content;
|
|
42
29
|
if (sourceNode.type === schema.nodes.codeBlock) {
|
|
43
|
-
|
|
30
|
+
var 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);
|
|
@@ -75,6 +63,16 @@ export var transformContainerNode = function transformContainerNode(_ref2) {
|
|
|
75
63
|
|
|
76
64
|
// Transform container to block type - unwrap and convert content
|
|
77
65
|
if (isBlockNodeType(targetNodeType)) {
|
|
66
|
+
// special case container to codeblock
|
|
67
|
+
if (targetNodeType.name === 'codeBlock') {
|
|
68
|
+
return transformBetweenContainerTypes({
|
|
69
|
+
tr: tr,
|
|
70
|
+
sourceNode: sourceNode,
|
|
71
|
+
sourcePos: sourcePos,
|
|
72
|
+
targetNodeType: targetNodeType,
|
|
73
|
+
targetAttrs: targetAttrs
|
|
74
|
+
});
|
|
75
|
+
}
|
|
78
76
|
return unwrapAndConvertToBlockType({
|
|
79
77
|
tr: tr,
|
|
80
78
|
sourceNode: sourceNode,
|
|
@@ -141,12 +139,7 @@ export var unwrapAndConvertToBlockType = function unwrapAndConvertToBlockType(co
|
|
|
141
139
|
|
|
142
140
|
// if the container is a code block, convert text content to multiple paragraphs
|
|
143
141
|
if (sourceNode.type === codeBlock) {
|
|
144
|
-
|
|
145
|
-
var lines = codeText.split('\n');
|
|
146
|
-
var paragraphNodes = lines.map(function (line) {
|
|
147
|
-
return paragraph.create(null, line ? schema.text(line) : null);
|
|
148
|
-
});
|
|
149
|
-
sourceChildren = paragraphNodes;
|
|
142
|
+
sourceChildren = convertCodeBlockContentToParagraphs(sourceNode, schema);
|
|
150
143
|
}
|
|
151
144
|
|
|
152
145
|
// if target node is a paragraph, just do unwrap
|
|
@@ -267,18 +260,29 @@ export var transformBetweenContainerTypes = function transformBetweenContainerTy
|
|
|
267
260
|
targetNodeType = context.targetNodeType,
|
|
268
261
|
targetAttrs = context.targetAttrs;
|
|
269
262
|
|
|
263
|
+
// Special handling for codeBlock target
|
|
264
|
+
if (targetNodeType.name === 'codeBlock') {
|
|
265
|
+
var _contentSplits = splitContentForCodeBlock(sourceNode, targetNodeType, targetAttrs, tr.doc.type.schema);
|
|
266
|
+
return applySplitsToTransaction(tr, sourcePos, sourceNode.nodeSize, _contentSplits);
|
|
267
|
+
}
|
|
268
|
+
|
|
270
269
|
// Get content validation for target container type
|
|
271
270
|
var isContentSupported = getContentSupportChecker(targetNodeType);
|
|
272
271
|
|
|
273
272
|
// Process content and collect splits
|
|
274
273
|
var contentSplits = splitContentAroundUnsupportedBlocks(sourceNode, isContentSupported, targetNodeType, targetAttrs, tr.doc.type.schema);
|
|
274
|
+
return applySplitsToTransaction(tr, sourcePos, sourceNode.nodeSize, contentSplits);
|
|
275
|
+
};
|
|
275
276
|
|
|
276
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Apply content splits to transaction - shared utility for replacing and inserting splits
|
|
279
|
+
*/
|
|
280
|
+
var applySplitsToTransaction = function applySplitsToTransaction(tr, sourcePos, sourceNodeSize, contentSplits) {
|
|
277
281
|
var insertPos = sourcePos;
|
|
278
282
|
contentSplits.forEach(function (splitNode, index) {
|
|
279
283
|
if (index === 0) {
|
|
280
284
|
// Replace the original node with the first split
|
|
281
|
-
tr.replaceWith(sourcePos, sourcePos +
|
|
285
|
+
tr.replaceWith(sourcePos, sourcePos + sourceNodeSize, splitNode);
|
|
282
286
|
insertPos = sourcePos + splitNode.nodeSize;
|
|
283
287
|
} else {
|
|
284
288
|
// Insert additional splits after
|
|
@@ -289,18 +293,75 @@ export var transformBetweenContainerTypes = function transformBetweenContainerTy
|
|
|
289
293
|
return tr;
|
|
290
294
|
};
|
|
291
295
|
|
|
296
|
+
/**
|
|
297
|
+
* Split content for codeBlock transformation, creating codeBlocks for text content
|
|
298
|
+
* and preserving unsupported blocks (like tables) separately
|
|
299
|
+
*/
|
|
300
|
+
var splitContentForCodeBlock = function splitContentForCodeBlock(sourceNode, targetNodeType, targetAttrs, schema) {
|
|
301
|
+
var _sourceNode$attrs3;
|
|
302
|
+
var splits = [];
|
|
303
|
+
var children = sourceNode.content.content;
|
|
304
|
+
var currentTextContent = [];
|
|
305
|
+
|
|
306
|
+
// Handle expand title - add as first text if source is expand with title
|
|
307
|
+
if (sourceNode.type.name === 'expand' && (_sourceNode$attrs3 = sourceNode.attrs) !== null && _sourceNode$attrs3 !== void 0 && _sourceNode$attrs3.title) {
|
|
308
|
+
currentTextContent.push(sourceNode.attrs.title);
|
|
309
|
+
}
|
|
310
|
+
var flushCurrentCodeBlock = function flushCurrentCodeBlock() {
|
|
311
|
+
if (currentTextContent.length > 0) {
|
|
312
|
+
var codeText = currentTextContent.join('\n');
|
|
313
|
+
var codeBlockNode = targetNodeType.create(targetAttrs, schema.text(codeText));
|
|
314
|
+
splits.push(codeBlockNode);
|
|
315
|
+
currentTextContent = [];
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
var isCodeBlockCompatible = function isCodeBlockCompatible(node) {
|
|
319
|
+
// Only text blocks (paragraph, heading) can be converted to codeBlock text
|
|
320
|
+
return node.isTextblock || node.type.name === 'codeBlock';
|
|
321
|
+
};
|
|
322
|
+
children.forEach(function (childNode) {
|
|
323
|
+
if (isCodeBlockCompatible(childNode)) {
|
|
324
|
+
// Extract text content from compatible nodes
|
|
325
|
+
if (childNode.type.name === 'codeBlock') {
|
|
326
|
+
// If it's already a codeBlock, extract its text
|
|
327
|
+
currentTextContent.push(childNode.textContent);
|
|
328
|
+
} else if (childNode.isTextblock) {
|
|
329
|
+
// Extract text from text blocks (paragraphs, headings, etc.)
|
|
330
|
+
var text = childNode.textContent;
|
|
331
|
+
if (text.trim()) {
|
|
332
|
+
currentTextContent.push(text);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
} else if (isBlockNodeForExtraction(childNode)) {
|
|
336
|
+
// Unsupported block node (table, etc.) - flush current codeBlock, add block, continue
|
|
337
|
+
flushCurrentCodeBlock();
|
|
338
|
+
splits.push(childNode);
|
|
339
|
+
} else {
|
|
340
|
+
// Other unsupported content - try to extract text if possible
|
|
341
|
+
var _text = childNode.textContent;
|
|
342
|
+
if (_text && _text.trim()) {
|
|
343
|
+
currentTextContent.push(_text);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Flush any remaining text content as a codeBlock
|
|
349
|
+
flushCurrentCodeBlock();
|
|
350
|
+
return splits;
|
|
351
|
+
};
|
|
352
|
+
|
|
292
353
|
/**
|
|
293
354
|
* Split content around unsupported block nodes, creating separate containers
|
|
294
355
|
* for content before and after each unsupported block
|
|
295
356
|
*/
|
|
296
357
|
var splitContentAroundUnsupportedBlocks = function splitContentAroundUnsupportedBlocks(sourceNode, isContentSupported, targetNodeType, targetAttrs, schema) {
|
|
297
|
-
var _sourceNode$
|
|
358
|
+
var _sourceNode$attrs4;
|
|
298
359
|
var splits = [];
|
|
299
360
|
var children = sourceNode.content.content;
|
|
300
361
|
var currentContainerContent = [];
|
|
301
362
|
|
|
302
363
|
// Handle expand title - add as first paragraph if source is expand with title
|
|
303
|
-
if (sourceNode.type.name === 'expand' && (_sourceNode$
|
|
364
|
+
if (sourceNode.type.name === 'expand' && (_sourceNode$attrs4 = sourceNode.attrs) !== null && _sourceNode$attrs4 !== void 0 && _sourceNode$attrs4.title) {
|
|
304
365
|
var titleParagraph = schema.nodes.paragraph.create({}, schema.text(sourceNode.attrs.title));
|
|
305
366
|
currentContainerContent.push(titleParagraph);
|
|
306
367
|
}
|
|
@@ -315,15 +376,15 @@ var splitContentAroundUnsupportedBlocks = function splitContentAroundUnsupported
|
|
|
315
376
|
if (isContentSupported(childNode)) {
|
|
316
377
|
// Supported content - add to current container
|
|
317
378
|
currentContainerContent.push(childNode);
|
|
318
|
-
} else if (isBlockNodeForExtraction(childNode)) {
|
|
319
|
-
// Unsupported block node - flush current container, add block, continue
|
|
320
|
-
flushCurrentContainer();
|
|
321
|
-
splits.push(childNode);
|
|
322
379
|
} else if (childNode.type.name === targetNodeType.name) {
|
|
323
380
|
// Same type of container merge contents
|
|
324
381
|
childNode.content.forEach(function (child) {
|
|
325
382
|
currentContainerContent.push(child);
|
|
326
383
|
});
|
|
384
|
+
} else if (childNode.isBlock) {
|
|
385
|
+
// Unsupported block node - flush current container, add block, continue
|
|
386
|
+
flushCurrentContainer();
|
|
387
|
+
splits.push(childNode);
|
|
327
388
|
} else {
|
|
328
389
|
// Unsupported inline content - convert to paragraph and add to container
|
|
329
390
|
var inlineContent = convertNodeToInlineContent(childNode, schema);
|
|
@@ -18,6 +18,7 @@ export var transformBlockToList = function transformBlockToList(context) {
|
|
|
18
18
|
var _tr$selection = tr.selection,
|
|
19
19
|
$from = _tr$selection.$from,
|
|
20
20
|
$to = _tr$selection.$to;
|
|
21
|
+
var schema = tr.doc.type.schema;
|
|
21
22
|
var range = $from.blockRange($to);
|
|
22
23
|
if (!range) {
|
|
23
24
|
return null;
|
|
@@ -30,6 +31,12 @@ export var transformBlockToList = function transformBlockToList(context) {
|
|
|
30
31
|
return transformToTaskList(tr, range, targetNodeType, targetAttrs, nodes);
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
// filter marks that are not allowed in the target node type
|
|
35
|
+
if (sourceNode.type === schema.nodes.paragraph || sourceNode.type === schema.nodes.heading) {
|
|
36
|
+
var allowedMarks = targetNodeType.allowedMarks(sourceNode.marks);
|
|
37
|
+
tr.setNodeMarkup(range.start, null, null, allowedMarks);
|
|
38
|
+
}
|
|
39
|
+
|
|
33
40
|
// For headings, convert to paragraph first since headings cannot be direct children of list items
|
|
34
41
|
if (sourceNode && sourceNode.type.name.startsWith('heading')) {
|
|
35
42
|
tr.setBlockType(range.start, range.end, nodes.paragraph);
|
|
@@ -168,4 +168,37 @@ export var convertNodeToInlineContent = function convertNodeToInlineContent(node
|
|
|
168
168
|
return [schema.text(node.textContent)];
|
|
169
169
|
}
|
|
170
170
|
return inlineNodes;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Filter marks from content based on the target node type
|
|
175
|
+
* @param content The content fragment to filter
|
|
176
|
+
* @param targetNodeType The target node type to check against
|
|
177
|
+
* @returns A new fragment with marks filtered for the target node type
|
|
178
|
+
*/
|
|
179
|
+
export var filterMarksForTargetNodeType = function filterMarksForTargetNodeType(content, targetNodeType) {
|
|
180
|
+
var withValidMarks = [];
|
|
181
|
+
content.forEach(function (node) {
|
|
182
|
+
if (node.marks.length > 0) {
|
|
183
|
+
var allowedMarks = targetNodeType.allowedMarks(node.marks);
|
|
184
|
+
var updatedNode = node.mark(allowedMarks);
|
|
185
|
+
withValidMarks.push(updatedNode);
|
|
186
|
+
} else {
|
|
187
|
+
withValidMarks.push(node);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return Fragment.from(withValidMarks);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/** * Convert content from a code block node into multiple paragraph nodes
|
|
194
|
+
*/
|
|
195
|
+
export var convertCodeBlockContentToParagraphs = function convertCodeBlockContentToParagraphs(codeBlockNode, schema) {
|
|
196
|
+
var paragraphNodes = [];
|
|
197
|
+
var codeText = codeBlockNode.textContent;
|
|
198
|
+
var lines = codeText.split('\n');
|
|
199
|
+
lines.forEach(function (line) {
|
|
200
|
+
var paragraphNode = schema.nodes.paragraph.create(null, line ? schema.text(line) : null);
|
|
201
|
+
paragraphNodes.push(paragraphNode);
|
|
202
|
+
});
|
|
203
|
+
return paragraphNodes;
|
|
171
204
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import { CellSelection } from '@atlaskit/editor-tables';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Determines if a node is nested (not at top-level) based on its depth and context.
|
|
@@ -32,6 +33,11 @@ export var isNestedNode = function isNestedNode(selection) {
|
|
|
32
33
|
return true;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
// Special case for table selection
|
|
37
|
+
if (selection instanceof CellSelection) {
|
|
38
|
+
return depth > 3;
|
|
39
|
+
}
|
|
40
|
+
|
|
35
41
|
// Check parent node type for depth 2-3
|
|
36
42
|
var parentNode = $from.node(depth - 1);
|
|
37
43
|
if (!parentNode) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Node as PMNode, NodeType, Schema } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
3
|
import type { FormatNodeTargetType } from './types';
|
|
3
4
|
export declare const getTargetNodeInfo: (targetType: FormatNodeTargetType, nodes: Record<string, NodeType>) => {
|
|
4
5
|
attrs?: Record<string, unknown>;
|
|
@@ -28,3 +29,13 @@ export declare const getContentSupportChecker: (targetNodeType: NodeType) => ((n
|
|
|
28
29
|
* Convert a node to inline content that can be placed in a paragraph
|
|
29
30
|
*/
|
|
30
31
|
export declare const convertNodeToInlineContent: (node: PMNode, schema: Schema) => PMNode[];
|
|
32
|
+
/**
|
|
33
|
+
* Filter marks from content based on the target node type
|
|
34
|
+
* @param content The content fragment to filter
|
|
35
|
+
* @param targetNodeType The target node type to check against
|
|
36
|
+
* @returns A new fragment with marks filtered for the target node type
|
|
37
|
+
*/
|
|
38
|
+
export declare const filterMarksForTargetNodeType: (content: Fragment, targetNodeType: NodeType) => Fragment;
|
|
39
|
+
/** * Convert content from a code block node into multiple paragraph nodes
|
|
40
|
+
*/
|
|
41
|
+
export declare const convertCodeBlockContentToParagraphs: (codeBlockNode: PMNode, schema: Schema) => PMNode[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Node as PMNode, NodeType, Schema } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
3
|
import type { FormatNodeTargetType } from './types';
|
|
3
4
|
export declare const getTargetNodeInfo: (targetType: FormatNodeTargetType, nodes: Record<string, NodeType>) => {
|
|
4
5
|
attrs?: Record<string, unknown>;
|
|
@@ -28,3 +29,13 @@ export declare const getContentSupportChecker: (targetNodeType: NodeType) => ((n
|
|
|
28
29
|
* Convert a node to inline content that can be placed in a paragraph
|
|
29
30
|
*/
|
|
30
31
|
export declare const convertNodeToInlineContent: (node: PMNode, schema: Schema) => PMNode[];
|
|
32
|
+
/**
|
|
33
|
+
* Filter marks from content based on the target node type
|
|
34
|
+
* @param content The content fragment to filter
|
|
35
|
+
* @param targetNodeType The target node type to check against
|
|
36
|
+
* @returns A new fragment with marks filtered for the target node type
|
|
37
|
+
*/
|
|
38
|
+
export declare const filterMarksForTargetNodeType: (content: Fragment, targetNodeType: NodeType) => Fragment;
|
|
39
|
+
/** * Convert content from a code block node into multiple paragraph nodes
|
|
40
|
+
*/
|
|
41
|
+
export declare const convertCodeBlockContentToParagraphs: (codeBlockNode: PMNode, schema: Schema) => PMNode[];
|