@atlaskit/editor-plugin-block-menu
Version:
BlockMenu plugin for @atlaskit/editor-core
217 lines (215 loc) • 9.4 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.listToListStep = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _transforms = require("@atlaskit/editor-common/transforms");
var _model = require("@atlaskit/editor-prosemirror/model");
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
var _nodeChecks = require("../nodeChecks");
/**
* Recursively converts nested lists to the target list type.
* This function handles the conversion of both the list container and its items,
* including any nested lists within those items.
*
* Important: taskList has a different nesting structure than bulletList/orderedList:
* - taskList: nested taskLists are SIBLINGS of taskItems in the parent taskList
* - bulletList/orderedList: nested lists are CHILDREN of listItems
*/
var _transformList = function transformList(node, targetListType, targetItemType, unsupportedContent) {
var schema = node.type.schema;
var taskListType = schema.nodes.taskList;
var isSourceTaskList = node.type === taskListType;
var isTargetTaskList = targetListType === taskListType.name;
var convertFromTaskListStructure = function convertFromTaskListStructure(node, targetListType, targetItemType) {
var schema = node.type.schema;
var targetListNodeType = schema.nodes[targetListType];
var transformedContent = [];
node.forEach(function (child) {
if ((0, _nodeChecks.isListWithIndentation)(child.type.name, schema)) {
// This is a nested list - it should become a child of the previous item
if (transformedContent.length > 0) {
var previousItem = transformedContent[transformedContent.length - 1];
// Convert the nested list and add it to the previous item's content
var transformedNestedList = _transformList(child, targetListType, targetItemType, unsupportedContent);
var newContent = previousItem.content.append(_model.Fragment.from([transformedNestedList]));
var updatedItem = previousItem.type.create(previousItem.attrs, newContent);
transformedContent[transformedContent.length - 1] = updatedItem;
}
// If there's no previous item, skip this nested list (orphaned)
} else {
var transformedItem = transformListItem(child, targetListType, targetItemType);
if (transformedItem) {
transformedContent.push(transformedItem);
}
}
});
return targetListNodeType.create(node.attrs, transformedContent);
};
var convertToTaskListStructure = function convertToTaskListStructure(node, targetListType, targetItemType) {
var schema = node.type.schema;
var targetListNodeType = schema.nodes[targetListType];
var transformedContent = [];
node.forEach(function (itemNode) {
var transformedItem = transformListItem(itemNode, targetListType, targetItemType, true);
if (transformedItem) {
transformedContent.push(transformedItem);
}
itemNode.forEach(function (child) {
if ((0, _nodeChecks.isListWithIndentation)(child.type.name, schema)) {
transformedContent.push(_transformList(child, targetListType, targetItemType, unsupportedContent));
}
});
});
return targetListNodeType.create(node.attrs, transformedContent);
};
var transformListItem = function transformListItem(itemNode, targetListType, targetItemType) {
var excludeNestedLists = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var schema = itemNode.type.schema;
var targetItemNodeType = schema.nodes[targetItemType];
var isTargetTaskItem = targetItemType === 'taskItem';
var isSourceTaskItem = itemNode.type.name === 'taskItem';
var paragraphType = schema.nodes.paragraph;
if (isTargetTaskItem) {
var inlineContent = [];
var blockMarks = itemNode.marks;
itemNode.forEach(function (child) {
if (child.type === paragraphType) {
inlineContent.push.apply(inlineContent, (0, _toConsumableArray2.default)(child.children));
if (child.marks.length > 0) {
blockMarks = child.marks;
}
} else if (child.isInline) {
inlineContent.push(child);
// Nested lists will be extracted and placed as siblings in the taskList
} else if (!(0, _nodeChecks.isListWithIndentation)(child.type.name, schema)) {
unsupportedContent.push(child);
}
});
var blockTaskItem = schema.nodes.blockTaskItem;
if (blockTaskItem && blockMarks.length > 0 && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true)) {
return (0, _transforms.createBlockTaskItem)({
content: inlineContent,
marks: blockMarks,
schema: schema
});
}
return targetItemNodeType.create({}, inlineContent);
}
var transformedContent = [];
if (isSourceTaskItem) {
transformedContent.push(paragraphType.create(null, itemNode.content));
} else {
itemNode.forEach(function (child) {
if ((0, _nodeChecks.isListWithIndentation)(child.type.name, schema)) {
if (excludeNestedLists) {
// Skip nested lists - they will be handled separately as siblings
return;
}
transformedContent.push(_transformList(child, targetListType, targetItemType, unsupportedContent));
} else {
transformedContent.push(child);
}
});
}
if (transformedContent.length === 0) {
transformedContent.push(paragraphType.create());
}
return targetItemNodeType.create({}, transformedContent);
};
var convertList = function convertList(node, schema, targetListType, targetItemType) {
var targetListNodeType = schema.nodes[targetListType];
var transformedContent = [];
node.forEach(function (childNode) {
var transformedItem = (0, _nodeChecks.isListWithIndentation)(childNode.type.name, schema) ? _transformList(childNode, targetListType, targetItemType, unsupportedContent) : transformListItem(childNode, targetListType, targetItemType);
if (transformedItem) {
transformedContent.push(transformedItem);
}
});
return targetListNodeType.create(node.attrs, transformedContent);
};
if (isSourceTaskList && !isTargetTaskList) {
return convertFromTaskListStructure(node, targetListType, targetItemType);
} else if (!isSourceTaskList && isTargetTaskList) {
return convertToTaskListStructure(node, targetListType, targetItemType);
}
return convertList(node, schema, targetListType, targetItemType);
};
/**
* Transform step that converts between bulletList, orderedList, and taskList types.
* This step maintains the order and indentation of the list by recursively
* converting all nested lists while preserving the structure. It also handles
* conversion between listItem and taskItem types.
*
* When converting to taskList/taskItem, unsupported content (images, codeBlocks) is filtered out.
*
* @example
* Input (bulletList with nested bulletList):
* - bulletList
* - listItem "1"
* - bulletList
* - listItem "1.1"
* - bulletList
* - listItem "1.1.1"
* - listItem "1.2"
* - listItem "2"
*
* Output (orderedList with nested orderedList):
* 1. orderedList
* 1. listItem "1"
* 1. orderedList
* 1. listItem "1.1"
* 1. orderedList
* 1. listItem "1.1.1"
* 2. listItem "1.2"
* 2. listItem "2"
*
* @example
* Input (bulletList with nested taskList):
* - bulletList
* - listItem "Regular item"
* - taskList
* - taskItem "Task 1" (checked)
* - taskItem "Task 2" (unchecked)
*
* Output (orderedList with nested orderedList, taskItems converted to listItems):
* 1. orderedList
* 1. listItem "Regular item"
* 1. orderedList
* 1. listItem "Task 1"
* 2. listItem "Task 2"
*
* @example
* Input (bulletList to taskList, with paragraph extraction):
* - bulletList
* - listItem
* - paragraph "Text content"
* - listItem
* - paragraph "Text"
* - codeBlock "code"
* - mediaSingle (image)
*
* Output (taskList with text extracted from paragraphs, unsupported content filtered):
* - taskList
* - taskItem "Text content" (text extracted from paragraph)
* - taskItem "Text" (text extracted, codeBlock and image filtered out)
*
* @param nodes - The nodes to transform
* @param context - The transformation context containing schema and target node type
* @returns The transformed nodes
*/
var listToListStep = exports.listToListStep = function listToListStep(nodes, context) {
var schema = context.schema,
targetNodeTypeName = context.targetNodeTypeName;
var unsupportedContent = [];
var transformedNodes = nodes.map(function (node) {
if ((0, _nodeChecks.isListWithIndentation)(node.type.name, schema)) {
var targetItemType = targetNodeTypeName === 'taskList' ? 'taskItem' : 'listItem';
return _transformList(node, targetNodeTypeName, targetItemType, unsupportedContent);
}
return node;
});
return [].concat((0, _toConsumableArray2.default)(transformedNodes), unsupportedContent);
};