@atlaskit/editor-plugin-card
Version:
Card plugin for @atlaskit/editor-core
221 lines • 9.78 kB
JavaScript
import React from 'react';
import { cardMessages as messages } from '@atlaskit/editor-common/messages';
import { IconDatasourceAssetsObjects, IconDatasourceConfluenceSearch, IconDatasourceJiraIssue } from '@atlaskit/editor-common/quick-insert';
import { canRenderDatasource } from '@atlaskit/editor-common/utils';
import { ASSETS_LIST_OF_LINKS_DATASOURCE_ID, CONFLUENCE_SEARCH_DATASOURCE_ID } from '@atlaskit/link-datasource';
import { fg } from '@atlaskit/platform-feature-flags';
import { blockCardSpecWithFixedToDOM } from './nodeviews/toDOM-fixes/blockCard';
import { embedCardSpecWithFixedToDOM } from './nodeviews/toDOM-fixes/embedCard';
import { inlineCardSpecWithFixedToDOM } from './nodeviews/toDOM-fixes/inlineCard';
import { hideLinkToolbar, setProvider, showDatasourceModal } from './pm-plugins/actions';
import { queueCardsFromChangedTr } from './pm-plugins/doc';
import { cardKeymap } from './pm-plugins/keymap';
import { createPlugin } from './pm-plugins/main';
import { pluginKey } from './pm-plugins/plugin-key';
import { isDatasourceConfigEditable } from './pm-plugins/utils';
import { createEventsQueue } from './ui/analytics/create-events-queue';
import DatasourceModalWithState from './ui/DatasourceModal/ModalWithState';
import { EditorLinkingPlatformAnalytics } from './ui/EditorLinkingPlatformAnalytics';
import { EditorSmartCardEvents } from './ui/EditorSmartCardEvents';
// Ignored via go/ees005
// eslint-disable-next-line import/no-named-as-default
import LayoutButton from './ui/LayoutButton';
import { floatingToolbar, getEndingToolbarItems, getStartingToolbarItems } from './ui/toolbar';
export const cardPlugin = ({
config: options = {},
api
}) => {
var _api$base, _options$lpLinkPicker;
let previousCardProvider;
const cardPluginEvents = createEventsQueue();
let instanceEmbedCardTransformers = options.embedCardTransformers;
api === null || api === void 0 ? void 0 : (_api$base = api.base) === null || _api$base === void 0 ? void 0 : _api$base.actions.registerMarks(({
tr,
node,
pos
}) => {
const {
doc
} = tr;
const {
schema
} = doc.type;
const {
inlineCard: inlineCardNodeType
} = schema.nodes;
if (node.type === inlineCardNodeType) {
const newText = node.attrs.url;
const currentPos = tr.mapping.map(pos);
tr.replaceWith(currentPos, currentPos + node.nodeSize, schema.text(newText, node.marks));
}
});
return {
name: 'card',
getSharedState(editorState) {
if (!editorState) {
return null;
}
return pluginKey.getState(editorState) || null;
},
nodes() {
const nodes = [{
name: 'inlineCard',
node: inlineCardSpecWithFixedToDOM()
}, {
name: 'blockCard',
node: blockCardSpecWithFixedToDOM()
}];
if (options.allowEmbeds) {
nodes.push({
name: 'embedCard',
node: embedCardSpecWithFixedToDOM()
});
}
return nodes;
},
pmPlugins() {
var _options$allowBlockCa, _options$allowResizin, _options$useAlternati, _options$allowWrappin, _options$allowAlignme, _options$allowDatasou, _options$showUpgradeD;
const allowBlockCards = (_options$allowBlockCa = options.allowBlockCards) !== null && _options$allowBlockCa !== void 0 ? _options$allowBlockCa : true;
const allowResizing = (_options$allowResizin = options.allowResizing) !== null && _options$allowResizin !== void 0 ? _options$allowResizin : true;
const useAlternativePreloader = (_options$useAlternati = options.useAlternativePreloader) !== null && _options$useAlternati !== void 0 ? _options$useAlternati : true;
const allowWrapping = (_options$allowWrappin = options.allowWrapping) !== null && _options$allowWrappin !== void 0 ? _options$allowWrappin : true;
const allowAlignment = (_options$allowAlignme = options.allowAlignment) !== null && _options$allowAlignme !== void 0 ? _options$allowAlignme : true;
const allowDatasource = (_options$allowDatasou = options.allowDatasource) !== null && _options$allowDatasou !== void 0 ? _options$allowDatasou : false;
const showUpgradeDiscoverability = (_options$showUpgradeD = options.showUpgradeDiscoverability) !== null && _options$showUpgradeD !== void 0 ? _options$showUpgradeD : true;
const plugins = [{
name: 'card',
plugin: createPlugin({
...options,
allowBlockCards,
allowResizing,
useAlternativePreloader,
allowWrapping,
allowAlignment,
allowDatasource,
cardPluginEvents,
embedCardTransformers: instanceEmbedCardTransformers,
showUpgradeDiscoverability
}, api)
}];
plugins.push({
name: 'cardKeymap',
plugin: ({
featureFlags
}) => {
return cardKeymap(featureFlags);
}
});
return plugins;
},
contentComponent({
editorView,
popupsMountPoint,
popupsScrollableElement,
popupsBoundariesElement
}) {
if (!editorView) {
return null;
}
const breakoutEnabled = options.editorAppearance === 'full-page';
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(EditorSmartCardEvents, {
editorView: editorView
}), /*#__PURE__*/React.createElement(EditorLinkingPlatformAnalytics, {
cardPluginEvents: cardPluginEvents,
editorView: editorView
}), breakoutEnabled && /*#__PURE__*/React.createElement(LayoutButton, {
api: api,
editorView: editorView,
mountPoint: popupsMountPoint,
scrollableElement: popupsScrollableElement,
boundariesElement: popupsBoundariesElement
}), /*#__PURE__*/React.createElement(DatasourceModalWithState, {
api: api,
editorView: editorView
}));
},
actions: {
setProvider: async providerPromise => {
var _api$core$actions$exe;
const provider = await providerPromise;
// Prevent someone trying to set the exact same provider twice for performance reasons
if (previousCardProvider === provider || (options === null || options === void 0 ? void 0 : options.provider) === providerPromise) {
return false;
}
previousCardProvider = provider;
return (_api$core$actions$exe = api === null || api === void 0 ? void 0 : api.core.actions.execute(({
tr
}) => setProvider(provider)(tr))) !== null && _api$core$actions$exe !== void 0 ? _api$core$actions$exe : false;
},
hideLinkToolbar,
queueCardsFromChangedTr,
registerEmbedCardTransformer: transformers => {
instanceEmbedCardTransformers = transformers;
},
getStartingToolbarItems: getStartingToolbarItems(options, api),
getEndingToolbarItems: getEndingToolbarItems(options, api)
},
pluginsOptions: {
floatingToolbar: floatingToolbar(options, (_options$lpLinkPicker = options.lpLinkPicker) !== null && _options$lpLinkPicker !== void 0 ? _options$lpLinkPicker : false, options.linkPicker, api, options.disableFloatingToolbar),
quickInsert: ({
formatMessage
}) => {
const quickInsertArray = [];
if (!options.allowDatasource) {
return quickInsertArray;
}
quickInsertArray.push({
id: 'datasource',
title: formatMessage(fg('confluence-issue-terminology-refresh') ? messages.datasourceJiraIssueIssueTermRefresh : messages.datasourceJiraIssue),
description: formatMessage(fg('confluence-issue-terminology-refresh') ? messages.datasourceJiraIssueDescriptionIssueTermRefresh : messages.datasourceJiraIssueDescription),
isDisabledOffline: true,
categories: ['external-content', 'development'],
keywords: ['jira'],
featured: true,
...(fg('jim-lower-ranking-in-jira-macro-search') && {
priority: 500
}),
icon: () => /*#__PURE__*/React.createElement(IconDatasourceJiraIssue, null),
action(insert) {
const tr = insert(undefined);
showDatasourceModal('jira')(tr);
return tr;
}
});
if (canRenderDatasource(ASSETS_LIST_OF_LINKS_DATASOURCE_ID)) {
quickInsertArray.push({
id: 'datasource',
title: formatMessage(messages.datasourceAssetsObjectsGeneralAvailability),
description: formatMessage(messages.datasourceAssetsObjectsDescription),
isDisabledOffline: true,
categories: ['external-content', 'development'],
keywords: ['assets'],
icon: () => /*#__PURE__*/React.createElement(IconDatasourceAssetsObjects, null),
action(insert) {
const tr = insert(undefined);
showDatasourceModal('assets')(tr);
return tr;
}
});
}
if (isDatasourceConfigEditable(CONFLUENCE_SEARCH_DATASOURCE_ID)) {
quickInsertArray.push({
id: 'datasource',
title: formatMessage(messages.datasourceConfluenceSearch),
description: formatMessage(messages.datasourceConfluenceSearchDescription),
isDisabledOffline: true,
categories: ['external-content', 'development'],
keywords: ['confluence'],
featured: true,
icon: () => /*#__PURE__*/React.createElement(IconDatasourceConfluenceSearch, null),
action(insert) {
const tr = insert(undefined);
showDatasourceModal('confluence-search')(tr);
return tr;
}
});
}
return quickInsertArray;
}
}
};
};