UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

226 lines (225 loc) 10.6 kB
import React from 'react'; import { isSafeUrl } from '@atlaskit/adf-schema'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics'; import { linkMessages, linkToolbarMessages } from '@atlaskit/editor-common/messages'; import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check'; import { RECENT_SEARCH_HEIGHT_IN_PX, RECENT_SEARCH_WIDTH_IN_PX } from '@atlaskit/editor-common/ui'; import LinkIcon from '@atlaskit/icon/core/link'; import LinkExternalIcon from '@atlaskit/icon/core/link-external'; import { hideLinkingToolbar, setUrlToMedia, showLinkingToolbar, unlink } from '../../pm-plugins/commands/linking'; import { getMediaLinkingState } from '../../pm-plugins/linking'; import { currentMediaInlineNode, currentMediaNode } from '../../pm-plugins/utils/current-media-node'; import MediaLinkingToolbar from '../../ui/MediaLinkingToolbar'; const FORCE_FOCUS_SELECTOR = '[data-testid="add-link-button"],[data-testid="edit-link-button"]'; const FORCE_FOCUS_SELECTOR_EDITOR_CONTROLS = '[data-testid="media-overflow-dropdown-trigger"]'; export function shouldShowMediaLinkToolbar(editorState) { const mediaLinkingState = getMediaLinkingState(editorState); if (!mediaLinkingState || mediaLinkingState.mediaPos === null) { return false; } const { nodes: { media, mediaInline }, marks: { link } } = editorState.schema; const node = editorState.doc.nodeAt(mediaLinkingState.mediaPos); if (!node || ![media, mediaInline].includes(node.type)) { return false; } const { parent } = editorState.doc.resolve(mediaLinkingState.mediaPos); return parent && parent.type.allowsMarkType(link); } export const getLinkingToolbar = (toolbarBaseConfig, mediaLinkingState, state, intl, pluginInjectionApi, providerFactory) => { const { link, visible, editable: editing, mediaPos } = mediaLinkingState; if (visible && mediaPos !== null) { const node = state.doc.nodeAt(mediaPos); if (node) { return { ...toolbarBaseConfig, height: RECENT_SEARCH_HEIGHT_IN_PX, width: RECENT_SEARCH_WIDTH_IN_PX, forcePlacement: true, items: [{ type: 'custom', fallback: [], disableArrowNavigation: true, render: (view, idx) => { if (!view || !providerFactory) { return null; } const setFocusOnFloatingToolbar = setFocus => { if (setFocus && areToolbarFlagsEnabled(Boolean(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.toolbar))) { var _pluginInjectionApi$f, _pluginInjectionApi$f2; const { state: { tr }, dispatch } = view; pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$f = pluginInjectionApi.floatingToolbar) === null || _pluginInjectionApi$f === void 0 ? void 0 : (_pluginInjectionApi$f2 = _pluginInjectionApi$f.actions) === null || _pluginInjectionApi$f2 === void 0 ? void 0 : _pluginInjectionApi$f2.forceFocusSelector(FORCE_FOCUS_SELECTOR_EDITOR_CONTROLS)(tr); dispatch(tr); } }; return /*#__PURE__*/React.createElement(MediaLinkingToolbar, { key: idx, displayUrl: link, providerFactory: providerFactory, intl: intl, editing: editing // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onUnlink: setFocus => { var _pluginInjectionApi$a; unlink(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions)(view.state, view.dispatch, view); setFocusOnFloatingToolbar(setFocus); } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onBack: (href, meta, setFocus) => { if (href.trim() && meta.inputMethod) { var _pluginInjectionApi$a2; setUrlToMedia(href, meta.inputMethod, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a2 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a2 === void 0 ? void 0 : _pluginInjectionApi$a2.actions)(view.state, view.dispatch, view); } hideLinkingToolbar(view.state, view.dispatch, view); setFocusOnFloatingToolbar(setFocus); } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onCancel: () => { var _pluginInjectionApi$f3, _pluginInjectionApi$f4; hideLinkingToolbar(view.state, view.dispatch, view, true); /** Focus should move to the 'Add link' button when the toolbar closes * and not close the floating toolbar. */ const { state: { tr }, dispatch } = view; const selector = areToolbarFlagsEnabled(Boolean(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.toolbar)) ? FORCE_FOCUS_SELECTOR_EDITOR_CONTROLS : FORCE_FOCUS_SELECTOR; pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$f3 = pluginInjectionApi.floatingToolbar) === null || _pluginInjectionApi$f3 === void 0 ? void 0 : (_pluginInjectionApi$f4 = _pluginInjectionApi$f3.actions) === null || _pluginInjectionApi$f4 === void 0 ? void 0 : _pluginInjectionApi$f4.forceFocusSelector(selector)(tr); dispatch(tr); } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onSubmit: (href, meta) => { var _pluginInjectionApi$a3; setUrlToMedia(href, meta.inputMethod, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a3 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a3 === void 0 ? void 0 : _pluginInjectionApi$a3.actions)(view.state, view.dispatch, view); hideLinkingToolbar(view.state, view.dispatch, view); setFocusOnFloatingToolbar(true); } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onBlur: () => { hideLinkingToolbar(view.state, view.dispatch, view); }, areAnyNewToolbarFlagsEnabled: areToolbarFlagsEnabled(Boolean(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.toolbar)) }); } }] }; } } }; const mediaTypes = ['image', 'video', 'audio', 'doc', 'archive', 'unknown']; const getMediaType = selectedNodeTypeSingle => { return mediaTypes.find(type => selectedNodeTypeSingle === null || selectedNodeTypeSingle === void 0 ? void 0 : selectedNodeTypeSingle.includes(type)); }; export const getLinkingDropdownOptions = (editorState, intl, mediaLinkingState, isInlineNode, allowLinking, isViewOnly) => { if (isViewOnly || !allowLinking || !shouldShowMediaLinkToolbar(editorState)) { return []; } let mediaType; const mediaNode = isInlineNode ? currentMediaInlineNode(editorState) : currentMediaNode(editorState); if (mediaNode) { const selectedNodeTypeSingle = mediaNode === null || mediaNode === void 0 ? void 0 : mediaNode.attrs.__fileMimeType; mediaType = getMediaType(selectedNodeTypeSingle); } // Only show link dropdown option for images and external media (shown as images) if (mediaType !== 'image' && (mediaNode === null || mediaNode === void 0 ? void 0 : mediaNode.attrs.type) !== 'external') { return []; } if (mediaLinkingState && mediaLinkingState.editable) { const title = intl.formatMessage(linkToolbarMessages.editLink); return [{ title, onClick: (editorState, dispatch, editorView) => { if (editorView) { const { state, dispatch } = editorView; showLinkingToolbar(state, dispatch); } return true; }, icon: /*#__PURE__*/React.createElement(LinkIcon, { label: "" }) }]; } else { const title = intl.formatMessage(linkToolbarMessages.addLink); return [{ title, onClick: (editorState, dispatch, editorView) => { if (editorView) { const { state, dispatch } = editorView; showLinkingToolbar(state, dispatch); } return true; }, icon: /*#__PURE__*/React.createElement(LinkIcon, { label: "" }) }]; } }; export const getOpenLinkToolbarButtonOption = (intl, mediaLinkingState, pluginInjectionApi) => { const isValidUrl = isSafeUrl(mediaLinkingState.link); const linkTitle = intl.formatMessage(isValidUrl ? linkMessages.openLink : linkToolbarMessages.unableToOpenLink); return { id: 'editor.media.open-link', testId: 'open-link-toolbar-button', type: 'button', icon: LinkExternalIcon, title: linkTitle, target: '_blank', href: isValidUrl ? mediaLinkingState.link : undefined, disabled: !isValidUrl, onClick: (state, dispatch, editorView) => { if (editorView) { var _pluginInjectionApi$a4; const { state: { tr }, dispatch } = editorView; pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a4 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a4 === void 0 ? void 0 : _pluginInjectionApi$a4.actions.attachAnalyticsEvent({ eventType: EVENT_TYPE.TRACK, action: ACTION.VISITED, actionSubject: ACTION_SUBJECT.MEDIA, actionSubjectId: ACTION_SUBJECT_ID.LINK })(tr); dispatch(tr); } return true; }, supportsViewMode: true }; };