@atlaskit/adf-schema
Version:
Shared package that contains the ADF-schema (json) and ProseMirror node/mark specs
301 lines (297 loc) • 7.32 kB
JavaScript
import { Schema } from '@atlaskit/editor-prosemirror/model';
import { COLOR, FONT_STYLE, SEARCH_QUERY, LINK } from './groups';
import { sanitizeNodes } from './sanitizeNodes';
import { link, em, strong, textColor, strike, subsup, underline, code, typeAheadQuery, confluenceInlineComment, breakout, alignment, indentation, annotation, unsupportedMark, unsupportedNodeAttribute, dataConsumer, fragment, border, backgroundColor } from './marks';
import { confluenceJiraIssue, confluenceUnsupportedBlock, confluenceUnsupportedInline, doc, paragraph, text, bulletList, orderedListWithOrder, listItem, heading, codeBlock, extendedPanel, rule, image, mention, media, mediaInline, mediaSingleFull, mediaGroup, hardBreak, emoji, table, tableCell, tableHeader, tableRow, decisionList, decisionItem, taskList, taskItem, unknownBlock, extension, inlineExtension, bodiedExtension, multiBodiedExtension, extensionFrame, date, placeholder, layoutSection, layoutColumn, inlineCard, blockCard, unsupportedBlock, unsupportedInline, status, expandWithNestedExpand, nestedExpand, embedCard, caption, extendedBlockquote } from './nodes';
function addItems(builtInItems, config) {
var customSpecs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
if (!config) {
return {};
}
/**
* Add built-in Node / Mark specs
*/
var items = builtInItems.reduce(function (items, _ref) {
var name = _ref.name,
spec = _ref.spec;
if (config.indexOf(name) !== -1) {
items[name] = customSpecs[name] || spec;
}
return items;
}, {});
/**
* Add Custom Node / Mark specs
*/
return Object.keys(customSpecs).reduce(function (items, name) {
if (items[name]) {
return items;
}
items[name] = customSpecs[name];
return items;
}, items);
}
// We use groups to allow schemas to be constructed in different shapes without changing node/mark
// specs, but this means nodes/marks are defined with groups that might never be used in the schema.
// In this scenario ProseMirror will complain and prevent the schema from being constructed.
//
// To avoid the problem, we include items that serve to "declare" the groups in the schema. This
// approach unfortunately leaves unused items in the schema, but has the benefit of avoiding the
// need to manipulate `exclude` or content expression values for potentially every schema item.
function groupDeclaration(name) {
return {
name: "__".concat(name, "GroupDeclaration"),
spec: {
group: name
}
};
}
var markGroupDeclarations = [groupDeclaration(COLOR), groupDeclaration(FONT_STYLE), groupDeclaration(SEARCH_QUERY), groupDeclaration(LINK)];
var markGroupDeclarationsNames = markGroupDeclarations.map(function (groupMark) {
return groupMark.name;
});
var nodesInOrder = [{
name: 'doc',
spec: doc
}, {
name: 'paragraph',
spec: paragraph
}, {
name: 'text',
spec: text
}, {
name: 'bulletList',
spec: bulletList
}, {
name: 'orderedList',
spec: orderedListWithOrder
}, {
name: 'listItem',
spec: listItem
}, {
name: 'heading',
spec: heading
}, {
name: 'blockquote',
spec: extendedBlockquote
}, {
name: 'codeBlock',
spec: codeBlock
}, {
name: 'panel',
spec: extendedPanel(true)
}, {
name: 'rule',
spec: rule
}, {
name: 'image',
spec: image
}, {
name: 'mention',
spec: mention
}, {
name: 'caption',
spec: caption
}, {
name: 'media',
spec: media
}, {
name: 'mediaGroup',
spec: mediaGroup
}, {
name: 'mediaSingle',
spec: mediaSingleFull
}, {
name: 'mediaInline',
spec: mediaInline
}, {
name: 'placeholder',
spec: placeholder
}, {
name: 'layoutSection',
spec: layoutSection
}, {
name: 'layoutColumn',
spec: layoutColumn
}, {
name: 'hardBreak',
spec: hardBreak
}, {
name: 'emoji',
spec: emoji
}, {
name: 'table',
spec: table
}, {
name: 'tableCell',
spec: tableCell
}, {
name: 'tableRow',
spec: tableRow
}, {
name: 'tableHeader',
spec: tableHeader
}, {
name: 'confluenceJiraIssue',
spec: confluenceJiraIssue
}, {
name: 'confluenceUnsupportedInline',
spec: confluenceUnsupportedInline
}, {
name: 'confluenceUnsupportedBlock',
spec: confluenceUnsupportedBlock
}, {
name: 'decisionList',
spec: decisionList
}, {
name: 'decisionItem',
spec: decisionItem
}, {
name: 'taskList',
spec: taskList
}, {
name: 'taskItem',
spec: taskItem
}, {
name: 'date',
spec: date
}, {
name: 'status',
spec: status
}, {
name: 'expand',
spec: expandWithNestedExpand
}, {
name: 'nestedExpand',
spec: nestedExpand
}, {
name: 'extension',
spec: extension
}, {
name: 'inlineExtension',
spec: inlineExtension
}, {
name: 'bodiedExtension',
spec: bodiedExtension
}, {
name: 'multiBodiedExtension',
spec: multiBodiedExtension
}, {
name: 'extensionFrame',
spec: extensionFrame
}, {
name: 'inlineCard',
spec: inlineCard
}, {
name: 'blockCard',
spec: blockCard
}, {
name: 'embedCard',
spec: embedCard
}, {
name: 'unknownBlock',
spec: unknownBlock
}, {
name: 'unsupportedBlock',
spec: unsupportedBlock
}, {
name: 'unsupportedInline',
spec: unsupportedInline
}];
var marksInOrder = [{
name: 'link',
spec: link
}, {
name: 'em',
spec: em
}, {
name: 'strong',
spec: strong
}, {
name: 'textColor',
spec: textColor
}, {
name: 'backgroundColor',
spec: backgroundColor
}, {
name: 'strike',
spec: strike
}, {
name: 'subsup',
spec: subsup
}, {
name: 'underline',
spec: underline
}, {
name: 'code',
spec: code
}, {
name: 'typeAheadQuery',
spec: typeAheadQuery
}, {
name: 'alignment',
spec: alignment
}, {
name: 'annotation',
spec: annotation
}, {
name: 'confluenceInlineComment',
spec: confluenceInlineComment
}].concat(markGroupDeclarations, [{
name: 'breakout',
spec: breakout
}, {
name: 'dataConsumer',
spec: dataConsumer
}, {
name: 'fragment',
spec: fragment
}, {
name: 'indentation',
spec: indentation
}, {
name: 'border',
spec: border
}, {
name: 'unsupportedMark',
spec: unsupportedMark
}, {
name: 'unsupportedNodeAttribute',
spec: unsupportedNodeAttribute
}]);
export function getNodesAndMarksMap() {
var nodes = nodesInOrder.reduce(function (acc, _ref2) {
var name = _ref2.name,
spec = _ref2.spec;
// @ts-expect-error - Type for SchemaBuiltInItem is not correct
acc[name] = spec;
return acc;
}, {});
var marks = marksInOrder.reduce(function (acc, _ref3) {
var name = _ref3.name,
spec = _ref3.spec;
// @ts-expect-error - Type for SchemaBuiltInItem is not correct
acc[name] = spec;
return acc;
}, {});
return {
nodes: nodes,
marks: marks
};
}
/**
* Creates a schema preserving order of marks and nodes.
*/
export function createSchema(config) {
var customNodeSpecs = config.customNodeSpecs,
customMarkSpecs = config.customMarkSpecs;
var nodesConfig = Object.keys(customNodeSpecs || {}).concat(config.nodes);
var marksConfig = Object.keys(customMarkSpecs || {}).concat(config.marks || []).concat(markGroupDeclarationsNames);
var nodes = addItems(nodesInOrder, nodesConfig, customNodeSpecs);
var marks = addItems(marksInOrder, marksConfig, customMarkSpecs);
nodes = sanitizeNodes(nodes, marks);
return new Schema({
nodes: nodes,
marks: marks
});
}
export var allowCustomPanel = true;