UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

169 lines (165 loc) 5.36 kB
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics'; import { createToggleBlockMarkOnRange } from '@atlaskit/editor-common/commands'; import { normalizeUrl } from '@atlaskit/editor-common/utils'; import { createMediaLinkingCommand, getMediaLinkingState, mediaLinkingPluginKey } from '../pm-plugins/linking'; import { MediaLinkingActionsTypes } from '../pm-plugins/linking/actions'; import { getMediaPluginState } from '../pm-plugins/main'; import { checkMediaType } from '../utils/check-media-type'; import { currentMediaNode } from '../utils/current-media-node'; export const showLinkingToolbar = createMediaLinkingCommand(state => { const mediaLinkingState = getMediaLinkingState(state); if (mediaLinkingState && mediaLinkingState.mediaPos !== null) { const mediaSingle = state.doc.nodeAt(mediaLinkingState.mediaPos); if (mediaSingle) { return { type: MediaLinkingActionsTypes.showToolbar }; } } return false; }); export const showLinkingToolbarWithMediaTypeCheck = (editorState, dispatch, editorView) => { if (dispatch && editorView) { const mediaNode = currentMediaNode(editorState); if (!mediaNode) { return false; } const { mediaClientConfig } = getMediaPluginState(editorState); if (!mediaClientConfig) { return false; } checkMediaType(mediaNode, mediaClientConfig).then(mediaType => { if ((mediaType === 'external' || mediaType === 'image') && // We make sure the selection and the node hasn't changed. currentMediaNode(editorView.state) === mediaNode) { dispatch(editorView.state.tr.setMeta(mediaLinkingPluginKey, { type: MediaLinkingActionsTypes.showToolbar })); } }); } return true; }; const hideLinkingToolbarCommand = createMediaLinkingCommand({ type: MediaLinkingActionsTypes.hideToolbar }); export const hideLinkingToolbar = (state, dispatch, view, focusFloatingToolbar) => { hideLinkingToolbarCommand(state, dispatch, view); // restore focus on the editor so keyboard shortcuts aren't lost to the browser if (view && !focusFloatingToolbar) { view.focus(); } }; function getCurrentUrl(state) { const { link: linkType } = state.schema.marks; const mediaLinkingState = getMediaLinkingState(state); if (!mediaLinkingState || mediaLinkingState.mediaPos === null) { return; } const $pos = state.doc.resolve(mediaLinkingState.mediaPos); const node = state.doc.nodeAt($pos.pos); if (!node) { return; } const hasLink = linkType.isInSet(node.marks); if (!hasLink) { return; } const link = node.marks.find(mark => mark.type === linkType); // Already check exist const url = link.attrs.href; return url; } function toggleLinkMark(tr, state, { forceRemove = false, url }) { const mediaLinkingState = getMediaLinkingState(state); if (!mediaLinkingState || mediaLinkingState.mediaPos === null) { return tr; } const $pos = state.doc.resolve(mediaLinkingState.mediaPos); const node = state.doc.nodeAt($pos.pos); if (!node) { return tr; } const linkMark = state.schema.marks.link; const { media } = state.schema.nodes; const toggleBlockLinkMark = createToggleBlockMarkOnRange(linkMark, (prevAttrs, node) => { // Only add mark to media if (!node || node.type !== media) { return; //No op } if (forceRemove) { return false; } const href = normalizeUrl(url); if (prevAttrs && prevAttrs.href === href) { return; //No op } if (href.trim() === '') { return false; // remove } return { ...prevAttrs, href: href }; }, [media]); toggleBlockLinkMark($pos.pos, $pos.pos + node.nodeSize, tr, state); return tr; } const fireAnalyticForMediaLink = (tr, action, attributes = undefined, editorAnalyticsAPI) => { editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({ action, eventType: EVENT_TYPE.TRACK, actionSubject: ACTION_SUBJECT.MEDIA, actionSubjectId: ACTION_SUBJECT_ID.LINK, attributes })(tr); return tr; }; export const unlink = editorAnalyticsAPI => createMediaLinkingCommand({ type: MediaLinkingActionsTypes.unlink }, (tr, state) => { const transaction = toggleLinkMark(tr, state, { forceRemove: true }); return fireAnalyticForMediaLink(transaction, ACTION.DELETED, undefined, editorAnalyticsAPI); }); const getAction = (newUrl, state) => { const currentUrl = getCurrentUrl(state); if (!currentUrl) { return ACTION.ADDED; } else if (newUrl !== currentUrl) { return ACTION.EDITED; } return undefined; }; export const setUrlToMedia = (url, inputMethod, editorAnalyticsAPI) => createMediaLinkingCommand({ type: MediaLinkingActionsTypes.setUrl, payload: normalizeUrl(url) }, (tr, state) => { const action = getAction(url, state); if (!action) { return tr; } try { const toggleLinkMarkResult = toggleLinkMark(tr, state, { url: url }); fireAnalyticForMediaLink(tr, action, action === ACTION.ADDED ? { inputMethod } : undefined, editorAnalyticsAPI); return toggleLinkMarkResult; } catch (e) { fireAnalyticForMediaLink(tr, ACTION.ERRORED, { action: action }, editorAnalyticsAPI); throw e; } });