UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

293 lines (284 loc) 11.3 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; import { atTheBeginningOfBlock, atTheBeginningOfDoc, atTheEndOfBlock, endPositionOfParent, GapCursorSelection, startPositionOfParent } from '@atlaskit/editor-common/selection'; import { createNewParagraphBelow, createParagraphNear } from '@atlaskit/editor-common/utils'; import { deleteSelection, splitBlock } from '@atlaskit/editor-prosemirror/commands'; import { NodeSelection } from '@atlaskit/editor-prosemirror/state'; import { findPositionOfNodeBefore } from '@atlaskit/editor-prosemirror/utils'; import { isExternalImageIdentifier, isMediaBlobUrl } from '@atlaskit/media-client'; import { isExternalMedia } from '../../ui/toolbar/utils'; import { getMediaPluginState } from '../main'; import { isVideo } from './media-single'; var isTemporary = function isTemporary(id) { return id.indexOf('temporary:') === 0; }; export var isMediaBlobUrlFromAttrs = function isMediaBlobUrlFromAttrs(attrs) { return !!(attrs && attrs.type === 'external' && isMediaBlobUrl(attrs.url)); }; export var posOfMediaGroupNearby = function posOfMediaGroupNearby(state) { return posOfParentMediaGroup(state) || posOfFollowingMediaGroup(state) || posOfPrecedingMediaGroup(state) || posOfMediaGroupNextToGapCursor(state); }; export var isSelectionNonMediaBlockNode = function isSelectionNonMediaBlockNode(state) { var _ref = state.selection, node = _ref.node; return node && node.type !== state.schema.nodes.media && node.isBlock; }; export var isSelectionMediaSingleNode = function isSelectionMediaSingleNode(state) { var _ref2 = state.selection, node = _ref2.node; return node && node.type === state.schema.nodes.mediaSingle; }; var isSelectionMediaInlineNode = function isSelectionMediaInlineNode(state) { var _ref3 = state.selection, node = _ref3.node; return node && node.type === state.schema.nodes.mediaInline; }; export var posOfPrecedingMediaGroup = function posOfPrecedingMediaGroup(state) { if (!atTheBeginningOfBlock(state)) { return; } return posOfMediaGroupAbove(state, state.selection.$from); }; var posOfMediaGroupNextToGapCursor = function posOfMediaGroupNextToGapCursor(state) { var selection = state.selection; if (selection instanceof GapCursorSelection) { var $pos = state.selection.$from; var mediaGroupType = state.schema.nodes.mediaGroup; return posOfImmediatePrecedingMediaGroup($pos, mediaGroupType) || posOfImmediateFollowingMediaGroup($pos, mediaGroupType); } }; var posOfImmediatePrecedingMediaGroup = function posOfImmediatePrecedingMediaGroup($pos, mediaGroupType) { if ($pos.nodeBefore && $pos.nodeBefore.type === mediaGroupType) { return $pos.pos - $pos.nodeBefore.nodeSize + 1; } }; var posOfImmediateFollowingMediaGroup = function posOfImmediateFollowingMediaGroup($pos, mediaGroupType) { if ($pos.nodeAfter && $pos.nodeAfter.type === mediaGroupType) { return $pos.pos + 1; } }; var posOfFollowingMediaGroup = function posOfFollowingMediaGroup(state) { if (!atTheEndOfBlock(state)) { return; } return posOfMediaGroupBelow(state, state.selection.$to); }; var posOfMediaGroupAbove = function posOfMediaGroupAbove(state, $pos) { var adjacentPos; var adjacentNode; if (isSelectionNonMediaBlockNode(state)) { adjacentPos = $pos.pos; adjacentNode = $pos.nodeBefore; } else { adjacentPos = startPositionOfParent($pos) - 1; adjacentNode = state.doc.resolve(adjacentPos).nodeBefore; } if (adjacentNode && adjacentNode.type === state.schema.nodes.mediaGroup) { return adjacentPos - adjacentNode.nodeSize + 1; } return; }; /** * Determine whether the cursor is inside empty paragraph * or the selection is the entire paragraph */ export var isInsidePotentialEmptyParagraph = function isInsidePotentialEmptyParagraph(state) { var $from = state.selection.$from; return $from.parent.type === state.schema.nodes.paragraph && atTheBeginningOfBlock(state) && atTheEndOfBlock(state); }; var posOfMediaGroupBelow = function posOfMediaGroupBelow(state, $pos) { var prepend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; var adjacentPos; var adjacentNode; if (isSelectionNonMediaBlockNode(state)) { adjacentPos = $pos.pos; adjacentNode = $pos.nodeAfter; } else { adjacentPos = endPositionOfParent($pos); adjacentNode = state.doc.nodeAt(adjacentPos); } if (adjacentNode && adjacentNode.type === state.schema.nodes.mediaGroup) { return prepend ? adjacentPos + 1 : adjacentPos + adjacentNode.nodeSize - 1; } return; }; export var posOfParentMediaGroup = function posOfParentMediaGroup(state, $pos) { var prepend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var $from = state.selection.$from; $pos = $pos || $from; if ($pos.parent.type === state.schema.nodes.mediaGroup) { return prepend ? startPositionOfParent($pos) : endPositionOfParent($pos) - 1; } return; }; export var removeMediaNode = function removeMediaNode(view, node, getPos) { var id = node.attrs.id; var state = view.state; var tr = state.tr, selection = state.selection, doc = state.doc; var currentMediaNodePos = getPos(); if (typeof currentMediaNodePos !== 'number') { return; } tr.deleteRange(currentMediaNodePos, currentMediaNodePos + node.nodeSize); if (isTemporary(id)) { tr.setMeta('addToHistory', false); } var $currentMediaNodePos = doc.resolve(currentMediaNodePos); var nodeBefore = $currentMediaNodePos.nodeBefore, parent = $currentMediaNodePos.parent; var isLastMediaNode = $currentMediaNodePos.index() === parent.childCount - 1; // If deleting a selected media node, we need to tell where the cursor to go next. // Prosemirror didn't gave us the behaviour of moving left if the media node is not the last one. // So we handle it ourselves. if (selection.from === currentMediaNodePos && !isLastMediaNode && !atTheBeginningOfDoc(state) && nodeBefore && nodeBefore.type.name === 'media') { var _nodeBefore = findPositionOfNodeBefore(tr.selection); if (_nodeBefore) { tr.setSelection(NodeSelection.create(tr.doc, _nodeBefore)); } } view.dispatch(tr); }; export var splitMediaGroup = function splitMediaGroup(view) { var selection = view.state.selection; // if selection is not a media node, do nothing. if (!(selection instanceof NodeSelection) || selection.node.type !== view.state.schema.nodes.media) { return false; } deleteSelection(view.state, view.dispatch); if (selection.$to.nodeAfter) { splitBlock(view.state, view.dispatch); createParagraphNear(false)(view.state, view.dispatch); } else { createNewParagraphBelow(view.state, view.dispatch); } return true; }; var isOptionalAttr = function isOptionalAttr(attr) { return attr.length > 1 && attr[0] === '_' && attr[1] === '_'; }; export var copyOptionalAttrsFromMediaState = function copyOptionalAttrsFromMediaState(mediaState, node) { Object.keys(node.attrs).filter(isOptionalAttr).forEach(function (key) { var mediaStateKey = key.substring(2); var attrValue = mediaState[mediaStateKey]; if (attrValue !== undefined) { // @ts-ignore - [unblock prosemirror bump] assigning to readonly prop node.attrs[key] = attrValue; } }); }; export var getMediaNodeFromSelection = function getMediaNodeFromSelection(state) { if (!isSelectionMediaSingleNode(state)) { return null; } var tr = state.tr; var pos = tr.selection.from + 1; var mediaNode = tr.doc.nodeAt(pos); if (mediaNode && mediaNode.type === state.schema.nodes.media) { return mediaNode; } return null; }; var getMediaInlineNodeFromSelection = function getMediaInlineNodeFromSelection(state) { if (!isSelectionMediaInlineNode(state)) { return null; } var tr = state.tr; var pos = tr.selection.from; var mediaNode = tr.doc.nodeAt(pos); return mediaNode; }; export var isMediaSingleOrInlineNodeSelected = function isMediaSingleOrInlineNodeSelected(state) { var _getMediaPluginState = getMediaPluginState(state), allowInlineImages = _getMediaPluginState.allowInlineImages; return isSelectionMediaSingleNode(state) || allowInlineImages && isSelectionMediaInlineNode(state); }; export var getMediaSingleOrInlineNodeFromSelection = function getMediaSingleOrInlineNodeFromSelection(state) { var _getMediaPluginState2 = getMediaPluginState(state), allowInlineImages = _getMediaPluginState2.allowInlineImages; var mediaNode = getMediaNodeFromSelection(state) || allowInlineImages && getMediaInlineNodeFromSelection(state); return mediaNode || null; }; export var getMediaFromSupportedMediaNodesFromSelection = function getMediaFromSupportedMediaNodesFromSelection(state) { var _ref4 = state.selection, node = _ref4.node; // Specifically for media supported nodes, double click could have been initiated on the media caption if (!node) { return null; } switch (node.type) { case node.type.schema.nodes.media: case node.type.schema.nodes.mediaInline: return node; case node.type.schema.nodes.mediaSingle: case node.type.schema.nodes.mediaGroup: return node.firstChild; default: return null; } }; export var isNodeDoubleClickSupportedInLivePagesViewMode = function isNodeDoubleClickSupportedInLivePagesViewMode(isViewMode, node) { if (!node) { return false; } // Double Click is not supported for video nodes on both views if (isVideo(node.attrs.__fileMimeType)) { return false; } // Double click is supported for all editor media nodes if (!isViewMode) { return true; } // Double Click is not supported for mediaGroup and mediaInline nodes that are file if (node.type === node.type.schema.nodes.mediaGroup || node.type === node.type.schema.nodes.mediaInline && node.attrs.type === 'file') { return false; } // Double Click supported for all other media nodes return true; }; export var getIdentifier = function getIdentifier(attrs) { if (isExternalMedia(attrs)) { return { mediaItemType: 'external-image', dataURI: attrs.url }; } else { var id = attrs.id, _attrs$collection = attrs.collection, collection = _attrs$collection === void 0 ? '' : _attrs$collection; return { id: id, mediaItemType: 'file', collectionName: collection }; } }; export var extractMediaNodes = function extractMediaNodes(doc) { var mediaNodes = []; doc.descendants(function (node) { if (node.type.name === 'media' || node.type.name === 'mediaInline') { mediaNodes.push(node); } }); return mediaNodes; }; // eslint-disable-next-line @typescript-eslint/no-explicit-any export var createMediaIdentifierArray = function createMediaIdentifierArray(mediaNodes) { var mediaIdentifierMap = new Map(); mediaNodes.forEach(function (item) { var attrs = item.attrs; if (!attrs) { return; } if (isVideo(attrs.__fileMimeType)) { return; } var identifier = getIdentifier(attrs); // Add only if not already processed var idKey = isExternalImageIdentifier(identifier) ? identifier.dataURI : identifier.id; if (!mediaIdentifierMap.has(idKey)) { mediaIdentifierMap.set(idKey, identifier); } }); return _toConsumableArray(mediaIdentifierMap.values()); };