@atlaskit/editor-plugin-card
Version:
Card plugin for @atlaskit/editor-core
142 lines (137 loc) • 7.33 kB
JavaScript
import { Fragment } from '@atlaskit/editor-prosemirror/model';
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
import { getResolvedAttributes } from '@atlaskit/link-analytics/get-resolved-attributes';
import { ASSETS_LIST_OF_LINKS_DATASOURCE_ID } from '@atlaskit/link-datasource/assets-modal';
import { CONFLUENCE_SEARCH_DATASOURCE_ID } from '@atlaskit/link-datasource/confluence-search-modal';
import { JIRA_LIST_OF_LINKS_DATASOURCE_ID } from '@atlaskit/link-datasource/jira-issues-modal';
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
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, cardActions) => {
if (isExperimentEnabled('platform_editor_reduce_forced_layout_2')) {
var _cardActions$getCardR, _cardActions$getCardR2;
const registrations = (_cardActions$getCardR = cardActions === null || cardActions === void 0 ? void 0 : (_cardActions$getCardR2 = cardActions.getCardRegistrations) === null || _cardActions$getCardR2 === void 0 ? void 0 : _cardActions$getCardR2.call(cardActions)) !== null && _cardActions$getCardR !== void 0 ? _cardActions$getCardR : {};
const card = Object.values(registrations).find(registration => registration.getPos() === state.selection.from);
return card ? {
id: card.id,
title: card.title,
url: card.url,
pos: state.selection.from
} : undefined;
} else {
const pluginState = pluginKey.getState(state);
return pluginState === null || pluginState === void 0 ? void 0 : 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
};
};