UNPKG

@atlaskit/adf-schema

Version:

Shared package that contains the ADF-schema (json) and ProseMirror node/mark specs

301 lines (297 loc) 7.32 kB
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;