UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

182 lines (181 loc) • 6.64 kB
import { buildAction } from './manifest-helpers'; export const groupBy = (arr, attr, keyRenamer) => arr.reduce((acc, item) => { acc[keyRenamer(item[attr])] = item; return acc; }, {}); export function buildMenuItem(manifest, extensionModule) { const title = extensionModule.title || manifest.title; const key = `${manifest.key}:${extensionModule.key}`; const node = buildAction(extensionModule.action, manifest); if (!node) { throw new Error(`Couldn't find any action for ${title} (${key})`); } return { key, title, extensionType: manifest.type, keywords: extensionModule.keywords || manifest.keywords || [], featured: extensionModule.featured || false, categories: extensionModule.categories || manifest.categories || [], description: extensionModule.description || manifest.description, summary: manifest.summary, documentationUrl: manifest.documentationUrl, icon: extensionModule.icon || manifest.icons['48'], node }; } export const getQuickInsertItemsFromModule = (extensions, transformFunction) => { const items = extensions.map(manifest => { const modules = manifest.modules.quickInsert || []; return modules.map(extensionModule => buildMenuItem(manifest, extensionModule)); }); const flatItems = [].concat(...items); return flatItems.map(transformFunction); }; export async function getAutoConvertPatternsFromModule(extensions) { const items = await Promise.all(extensions.map(async manifest => { if (manifest.modules.autoConvert && manifest.modules.autoConvert.url) { return manifest.modules.autoConvert.url; } return []; })); return [].concat(...items); } export const createAutoConverterRunner = autoConvertHandlers => text => { for (const handler of autoConvertHandlers) { const result = handler(text); if (result) { return result; } } }; export async function getExtensionAutoConvertersFromProvider(extensionProviderPromise) { const extensionProvider = await extensionProviderPromise; const extensionAutoConverters = await extensionProvider.getAutoConverter(); return createAutoConverterRunner(extensionAutoConverters); } const logError = (msg, ...args) => { // eslint-disable-next-line no-console console.error(msg, ...args); }; const toolbarItemToButtonConfig = (toolbarItem, parentKey) => { const { tooltip, key, label, icon, action, disabled } = toolbarItem; const itemKey = [parentKey, key].join(':'); if (typeof action !== 'function') { logError(`Provided action is not a function for extension toolbar button: ${label} (${itemKey})`); } let labelAndIcon = {}; switch (toolbarItem.display) { case 'icon': if (!icon) { logError(`icon should be provided for extension toolbar button (${itemKey}), when display is set to 'icon'`); } labelAndIcon = { icon }; break; case 'label': if (!label) { logError(`label should be provided for extension toolbar button (${itemKey}), when display is set to 'label'`); } labelAndIcon = { label }; break; default: if (!label || !icon) { logError(`label and icon should be provided for extension toolbar button (${itemKey}), when display is not set or set to 'icon-and-label'`); } labelAndIcon = { icon, label }; break; } return { key: itemKey, tooltip, action, disabled, ...labelAndIcon }; }; const compareContext = (contextA, contextB) => { if (contextA.type === contextB.type && contextA.nodeType === contextB.nodeType) { if (contextA.type === 'node') { return true; } if (contextA.type === 'extension' && contextB.type === 'extension') { return contextA.extensionKey === contextB.extensionKey && contextA.extensionType === contextB.extensionType; } } return false; }; const hasDuplicateContext = contextualToolbars => { if (contextualToolbars.length > 1) { const contexts = contextualToolbars.map(contextualToolbar => contextualToolbar.context); return contexts.find((currentContext, currentIndex) => currentIndex !== contexts.findIndex(context => compareContext(currentContext, context))); } }; export const getContextualToolbarItemsFromModule = (extensions, node, api) => { return extensions.map(extension => { if (extension.modules.contextualToolbars) { const duplicateContext = hasDuplicateContext(extension.modules.contextualToolbars); if (duplicateContext) { logError(`[contextualToolbars] Duplicate context detected - ${JSON.stringify(duplicateContext)}.`); return []; } return extension.modules.contextualToolbars.map(contextualToolbar => { if (shouldAddExtensionItemForNode(contextualToolbar, node)) { const { toolbarItems } = contextualToolbar; if (typeof toolbarItems === 'function') { return toolbarItems(node, api); } return toolbarItems; } return []; }).flatMap(toolbarButtons => toolbarButtons.map(toolbarButton => toolbarItemToButtonConfig(toolbarButton, extension.key))); } return []; }).flatMap(extensionToolbarButtons => extensionToolbarButtons); }; // defines whether to add toolbar item for the given node function shouldAddExtensionItemForNode(item, node) { var _node$attrs; // if item type is a standard node - should match the nodeType if (item.context.type === 'node' && item.context.nodeType === node.type) { return true; } // for other cases should be an extension and match the nodeType ("extension" | "inlineExtension" | "bodiedExtension" | "multiBodiedExtension") if (item.context.type !== 'extension' || node.type !== item.context.nodeType) { return false; } const { extensionType, extensionKey } = item.context; // if extension type is given - should match extension type if (extensionType && extensionType !== ((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.extensionType)) { return false; } // if extension key is a string if (typeof extensionKey === 'string') { var _node$attrs2; return extensionKey === ((_node$attrs2 = node.attrs) === null || _node$attrs2 === void 0 ? void 0 : _node$attrs2.extensionKey); } // if extension key is an array if (Array.isArray(extensionKey) && extensionKey.length) { var _node$attrs3; return extensionKey.includes((_node$attrs3 = node.attrs) === null || _node$attrs3 === void 0 ? void 0 : _node$attrs3.extensionKey); } return false; }