UNPKG

@atlaskit/editor-plugin-card

Version:

Card plugin for @atlaskit/editor-core

130 lines (125 loc) 6.32 kB
import { Fragment } from '@atlaskit/editor-prosemirror/model'; import { NodeSelection } from '@atlaskit/editor-prosemirror/state'; import { getResolvedAttributes } from '@atlaskit/link-analytics/resolved-attributes'; import { ASSETS_LIST_OF_LINKS_DATASOURCE_ID, CONFLUENCE_SEARCH_DATASOURCE_ID, JIRA_LIST_OF_LINKS_DATASOURCE_ID } from '@atlaskit/link-datasource'; import { pluginKey } from './plugin-key'; export const appearanceForNodeType = spec => { if (spec.name === 'inlineCard') { return 'inline'; } else if (spec.name === 'blockCard') { return 'block'; } else if (spec.name === 'embedCard') { return 'embed'; } return; }; export const selectedCardAppearance = state => { if (state.selection instanceof NodeSelection) { return appearanceForNodeType(state.selection.node.type); } }; export const titleUrlPairFromNode = node => { const { attrs } = node; return { url: attrs.url || attrs.data && attrs.data.url, title: attrs.data && attrs.data.title }; }; /** * Merges the title and url from attributes and CardInfo from the resolved view, preferring the CardInfo. * @param titleUrlPair title and url information from the node attributes * @param info information stored in state from the resolved UI component view */ export const mergeCardInfo = (titleUrlPair, info) => { return { title: info && info.title || titleUrlPair.title, url: info && info.url || titleUrlPair.url }; }; export const displayInfoForCard = (node, info) => mergeCardInfo(titleUrlPairFromNode(node), info); export const findCardInfo = state => { const pluginState = pluginKey.getState(state); if (!pluginState) { return undefined; } return pluginState.cards.find(cardInfo => cardInfo.pos === state.selection.from); }; const isAppearanceSupportedInParent = (currentNodePosition, editorState, fragment, currentAppearance) => { const resolvedPosition = editorState.doc.resolve(currentNodePosition); const parent = currentAppearance === 'embed' || currentAppearance === 'block' ? resolvedPosition.node() : resolvedPosition.node(-1); return parent && parent.type.validContent(fragment); }; export const isEmbedSupportedAtPosition = (currentNodePosition, editorState, currentAppearance) => isAppearanceSupportedInParent(currentNodePosition, editorState, Fragment.from(editorState.schema.nodes.embedCard.createChecked({})), currentAppearance); export const isBlockSupportedAtPosition = (currentNodePosition, editorState, currentAppearance) => isAppearanceSupportedInParent(currentNodePosition, editorState, Fragment.from(editorState.schema.nodes.blockCard.createChecked({})), currentAppearance); export const getResolvedAttributesFromStore = (url, display, store) => { if (!store) { return {}; } const urlState = store === null || store === void 0 ? void 0 : store.getState()[url]; const displayCategory = display === 'url' ? 'link' : undefined; return getResolvedAttributes({ url, displayCategory }, urlState === null || urlState === void 0 ? void 0 : urlState.details); }; export const isDatasourceConfigEditable = datasourceId => { const datasourcesWithConfigModal = [JIRA_LIST_OF_LINKS_DATASOURCE_ID, ASSETS_LIST_OF_LINKS_DATASOURCE_ID, CONFLUENCE_SEARCH_DATASOURCE_ID]; return datasourcesWithConfigModal.includes(datasourceId); }; /** * Typeguard that checks node attributes are datasource node attributes * ** WARNING ** Typeguards are not a guarantee, if the asserted type changes * this function will not be updated automatically */ export const isDatasourceAdfAttributes = attrs => { // Check is attributes object if (!(typeof attrs === 'object' && attrs !== null)) { return false; } // Check datasource attribute is an object if (!('datasource' in attrs)) { return false; } if (typeof attrs.datasource !== 'object' || attrs.datasource === null) { return false; } const hasId = 'id' in attrs.datasource && typeof attrs.datasource.id === 'string'; const hasParameters = 'parameters' in attrs.datasource && typeof attrs.datasource.parameters === 'object' && attrs.datasource.parameters !== null && !Array.isArray(attrs.datasource.parameters); const hasViews = 'views' in attrs.datasource && Array.isArray(attrs.datasource.views); return hasId && hasParameters && hasViews; }; /** * Typeguard that checks a node is a datasource node (blockCard and has datasource attributes) * ** WARNING ** Typeguards are not a guarantee, if the asserted type changes * this function will not be updated automatically */ export const isDatasourceNode = node => { if (!node) { return false; } return node.type.name === 'blockCard' && isDatasourceAdfAttributes(node.attrs); }; /** * Focuses the editorView if it's not already focused. * @param editorView The editor view to focus. */ export const focusEditorView = editorView => { if (!editorView.hasFocus()) { editorView.focus(); } }; export const getAwarenessProps = (editorState, getPos, allowEmbeds, allowBlockCards, disableOverlay = false) => { var _editorState$selectio, _editorState$selectio2, _editorState$selectio3; const getPosFunction = typeof getPos !== 'boolean' ? getPos : undefined; const linkPosition = getPosFunction === null || getPosFunction === void 0 ? void 0 : getPosFunction(); const canBeUpgradedToEmbed = !!linkPosition && allowEmbeds ? isEmbedSupportedAtPosition(linkPosition, editorState, 'inline') : false; const canBeUpgradedToBlock = !!linkPosition && allowBlockCards ? isBlockSupportedAtPosition(linkPosition, editorState, 'inline') : false; const isSelected = editorState.selection instanceof NodeSelection && ((_editorState$selectio = editorState.selection) === null || _editorState$selectio === void 0 ? void 0 : (_editorState$selectio2 = _editorState$selectio.node) === null || _editorState$selectio2 === void 0 ? void 0 : _editorState$selectio2.type) === editorState.schema.nodes.inlineCard && ((_editorState$selectio3 = editorState.selection) === null || _editorState$selectio3 === void 0 ? void 0 : _editorState$selectio3.from) === (getPosFunction === null || getPosFunction === void 0 ? void 0 : getPosFunction()); return { isPulseEnabled: canBeUpgradedToEmbed, isOverlayEnabled: !disableOverlay && (canBeUpgradedToEmbed || canBeUpgradedToBlock), isSelected }; };