UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

427 lines (424 loc) 23 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.mediaPlugin = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _analytics = require("@atlaskit/editor-common/analytics"); var _hooks = require("@atlaskit/editor-common/hooks"); var _messages = require("@atlaskit/editor-common/messages"); var _quickInsert = require("@atlaskit/editor-common/quick-insert"); var _safePlugin = require("@atlaskit/editor-common/safe-plugin"); var _toolbarFlagCheck = require("@atlaskit/editor-common/toolbar-flag-check"); var _state = require("@atlaskit/editor-prosemirror/state"); var _mediaCommon = require("@atlaskit/media-common"); var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _experiments = require("@atlaskit/tmp-editor-statsig/experiments"); var _lazyMediaGroup = require("./nodeviews/lazy-media-group"); var _lazyMediaInline = require("./nodeviews/lazy-media-inline"); var _mediaNodeView = require("./nodeviews/mediaNodeView"); var _mediaSingle = require("./nodeviews/mediaSingle"); var _media = require("./nodeviews/toDOM-fixes/media"); var _mediaGroup = require("./nodeviews/toDOM-fixes/mediaGroup"); var _mediaInline = require("./nodeviews/toDOM-fixes/mediaInline"); var _mediaSingle2 = require("./nodeviews/toDOM-fixes/mediaSingle"); var _aiGeneratingDecoration = require("./pm-plugins/ai-generating-decoration"); var _altText = require("./pm-plugins/alt-text"); var _keymap = _interopRequireDefault(require("./pm-plugins/alt-text/keymap")); var _commands = require("./pm-plugins/commands"); var _keymap2 = _interopRequireDefault(require("./pm-plugins/keymap")); var _keymapMedia = _interopRequireDefault(require("./pm-plugins/keymap-media")); var _linking = _interopRequireDefault(require("./pm-plugins/linking")); var _keymap3 = _interopRequireDefault(require("./pm-plugins/linking/keymap")); var _main = require("./pm-plugins/main"); var _pixelResizing = require("./pm-plugins/pixel-resizing"); var _pluginKey = require("./pm-plugins/plugin-key"); var _mediaCommon2 = require("./pm-plugins/utils/media-common"); var _mediaSingle3 = require("./pm-plugins/utils/media-single"); var _MediaPicker = require("./ui/MediaPicker"); var _PortalWrapper = require("./ui/MediaViewer/PortalWrapper"); var _toolbar = require("./ui/toolbar"); var _ToolbarMedia = _interopRequireDefault(require("./ui/ToolbarMedia")); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var selector = function selector(states) { var _states$mediaState, _states$mediaState2; return { onPopupToggle: (_states$mediaState = states.mediaState) === null || _states$mediaState === void 0 ? void 0 : _states$mediaState.onPopupToggle, setBrowseFn: (_states$mediaState2 = states.mediaState) === null || _states$mediaState2 === void 0 ? void 0 : _states$mediaState2.setBrowseFn }; }; var MediaPickerFunctionalComponent = function MediaPickerFunctionalComponent(_ref) { var api = _ref.api, editorDomElement = _ref.editorDomElement, appearance = _ref.appearance; var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['media'], selector), onPopupToggle = _useSharedPluginState.onPopupToggle, setBrowseFn = _useSharedPluginState.setBrowseFn; if (!onPopupToggle || !setBrowseFn) { return null; } return /*#__PURE__*/_react.default.createElement(_MediaPicker.MediaPickerComponents, { onPopupToggle: onPopupToggle, setBrowseFn: setBrowseFn, editorDomElement: editorDomElement, appearance: appearance, api: api }); }; var mediaViewerStateSelector = function mediaViewerStateSelector(states) { var _states$mediaState3, _states$mediaState4, _states$mediaState5; return { isMediaViewerVisible: (_states$mediaState3 = states.mediaState) === null || _states$mediaState3 === void 0 ? void 0 : _states$mediaState3.isMediaViewerVisible, mediaViewerSelectedMedia: (_states$mediaState4 = states.mediaState) === null || _states$mediaState4 === void 0 ? void 0 : _states$mediaState4.mediaViewerSelectedMedia, mediaClientConfig: (_states$mediaState5 = states.mediaState) === null || _states$mediaState5 === void 0 ? void 0 : _states$mediaState5.mediaClientConfig }; }; var MediaViewerFunctionalComponent = function MediaViewerFunctionalComponent(_ref2) { var api = _ref2.api, editorView = _ref2.editorView, mediaViewerExtensions = _ref2.mediaViewerExtensions; // Only traverse document once when media viewer is visible, media viewer items will not update // when document changes are made while media viewer is open var _useSharedPluginState2 = (0, _hooks.useSharedPluginStateWithSelector)(api, ['media'], mediaViewerStateSelector), isMediaViewerVisible = _useSharedPluginState2.isMediaViewerVisible, mediaViewerSelectedMedia = _useSharedPluginState2.mediaViewerSelectedMedia, mediaClientConfig = _useSharedPluginState2.mediaClientConfig; var mediaItems = (0, _react.useMemo)(function () { if (isMediaViewerVisible) { var mediaNodes = (0, _mediaCommon2.extractMediaNodes)(editorView.state.doc); return (0, _mediaCommon2.createMediaIdentifierArray)(mediaNodes); } // eslint-disable-next-line react-hooks/exhaustive-deps -- only update mediaItems once when media viewer is visible }, [isMediaViewerVisible]); // Viewer does not have required attributes to render the media viewer if (!isMediaViewerVisible || !mediaViewerSelectedMedia || !mediaClientConfig) { return null; } var handleOnClose = function handleOnClose() { // Run Command to hide the media viewer api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 ? void 0 : api.media.commands.hideMediaViewer); }; return /*#__PURE__*/_react.default.createElement(_PortalWrapper.RenderMediaViewer, { mediaClientConfig: mediaClientConfig, onClose: handleOnClose, selectedNodeAttrs: mediaViewerSelectedMedia, items: mediaItems, extensions: mediaViewerExtensions }); }; var mediaPlugin = exports.mediaPlugin = function mediaPlugin(_ref3) { var _api$analytics3; var _ref3$config = _ref3.config, options = _ref3$config === void 0 ? {} : _ref3$config, api = _ref3.api; var previousMediaProvider; var mediaErrorLocalIds = new Set(); return { name: 'media', getSharedState: function getSharedState(editorState) { if (!editorState) { return null; } return _pluginKey.stateKey.getState(editorState) || null; }, actions: { handleMediaNodeRenderError: function handleMediaNodeRenderError(node, reason, nestedUnder) { var _api$analytics; var isDuplicateError = false; if ((0, _expValEquals.expValEquals)('platform_editor_media_reliability_observability', 'isEnabled', true)) { if (mediaErrorLocalIds.has(node.attrs.localId)) { // we mark duplicate errors in the case of nested media nodes // renderering to avoid firing multiple errored events for the same underlying issue, // which can happen more often with nested media nodes isDuplicateError = true; } else { mediaErrorLocalIds.add(node.attrs.localId); } } api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({ action: _analytics.ACTION.ERRORED, actionSubject: _analytics.ACTION_SUBJECT.EDITOR, actionSubjectId: _analytics.ACTION_SUBJECT_ID.MEDIA, eventType: _analytics.EVENT_TYPE.UI, attributes: _objectSpread(_objectSpread({ reason: reason, external: node.attrs.__external }, nestedUnder && (0, _experiments.editorExperiment)('platform_synced_block', true) ? { nestedUnder: nestedUnder } : {}), (0, _experiments.editorExperiment)('platform_synced_block', true) ? { isDuplicateError: isDuplicateError } : {}) }); }, insertMediaAsMediaSingle: function insertMediaAsMediaSingle(view, node, inputMethod, insertMediaVia) { var _api$analytics2; return (0, _mediaSingle3.insertMediaAsMediaSingle)(view, node, inputMethod, api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions, insertMediaVia, options === null || options === void 0 ? void 0 : options.allowPixelResizing); }, setProvider: function setProvider(provider) { var _api$core$actions$exe; // Prevent someone trying to set the exact same provider twice for performance reasons if (previousMediaProvider === provider) { return false; } previousMediaProvider = provider; return (_api$core$actions$exe = api === null || api === void 0 ? void 0 : api.core.actions.execute(function (_ref4) { var tr = _ref4.tr; return tr.setMeta(_pluginKey.stateKey, { mediaProvider: provider }); })) !== null && _api$core$actions$exe !== void 0 ? _api$core$actions$exe : false; } }, commands: { showMediaViewer: _commands.showMediaViewer, hideMediaViewer: _commands.hideMediaViewer, trackMediaPaste: _commands.trackMediaPaste, setAIGenerating: _commands.setAIGenerating, clearAIGenerating: _commands.clearAIGenerating, insertMediaSingle: (0, _commands.insertMediaAsMediaSingleCommand)(api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions, options.allowPixelResizing) }, nodes: function nodes() { var _ref5 = options || {}, _ref5$allowMediaGroup = _ref5.allowMediaGroup, allowMediaGroup = _ref5$allowMediaGroup === void 0 ? true : _ref5$allowMediaGroup, _ref5$allowMediaSingl = _ref5.allowMediaSingle, allowMediaSingle = _ref5$allowMediaSingl === void 0 ? false : _ref5$allowMediaSingl, _ref5$allowPixelResiz = _ref5.allowPixelResizing, allowPixelResizing = _ref5$allowPixelResiz === void 0 ? false : _ref5$allowPixelResiz, allowCaptions = _ref5.allowCaptions, allowMediaInlineImages = _ref5.allowMediaInlineImages, mediaFeatureFlags = _ref5.featureFlags; var allowMediaInline = (0, _platformFeatureFlags.fg)('platform_editor_remove_media_inline_feature_flag') ? allowMediaInlineImages : (0, _mediaCommon.getMediaFeatureFlag)('mediaInline', mediaFeatureFlags); var mediaSingleOption = { withCaption: allowCaptions, withExtendedWidthTypes: allowPixelResizing }; return [{ name: 'mediaGroup', node: (0, _mediaGroup.mediaGroupSpecWithFixedToDOM)() }, { name: 'mediaSingle', node: (0, _mediaSingle2.mediaSingleSpecWithFixedToDOM)(mediaSingleOption) }, { name: 'media', node: (0, _media.mediaSpecWithFixedToDOM)() }, { name: 'mediaInline', node: (0, _mediaInline.mediaInlineSpecWithFixedToDOM)() }].filter(function (node) { if (node.name === 'mediaGroup') { return allowMediaGroup; } if (node.name === 'mediaSingle') { return allowMediaSingle; } if (node.name === 'mediaInline') { return allowMediaInline; } return true; }); }, pmPlugins: function pmPlugins() { var pmPlugins = [{ name: 'media', plugin: function plugin(_ref6) { var schema = _ref6.schema, dispatch = _ref6.dispatch, getIntl = _ref6.getIntl, eventDispatcher = _ref6.eventDispatcher, providerFactory = _ref6.providerFactory, errorReporter = _ref6.errorReporter, portalProviderAPI = _ref6.portalProviderAPI, dispatchAnalyticsEvent = _ref6.dispatchAnalyticsEvent, nodeViewPortalProviderAPI = _ref6.nodeViewPortalProviderAPI; return (0, _main.createPlugin)(schema, { providerFactory: providerFactory, nodeViews: { mediaGroup: (0, _lazyMediaGroup.lazyMediaGroupView)(portalProviderAPI, eventDispatcher, providerFactory, options, api), mediaSingle: (0, _mediaSingle.ReactMediaSingleNode)(portalProviderAPI, eventDispatcher, providerFactory, api, dispatchAnalyticsEvent, options), media: (0, _mediaNodeView.ReactMediaNode)(portalProviderAPI, eventDispatcher, providerFactory, options, api), mediaInline: (0, _lazyMediaInline.lazyMediaInlineView)(portalProviderAPI, eventDispatcher, providerFactory, api, undefined, options === null || options === void 0 ? void 0 : options.fallbackMediaNameFetcher) }, errorReporter: errorReporter, uploadErrorHandler: options && options.uploadErrorHandler, waitForMediaUpload: options && options.waitForMediaUpload, customDropzoneContainer: options && options.customDropzoneContainer, customMediaPicker: options && options.customMediaPicker, allowResizing: !!(options && options.allowResizing) }, getIntl, api, nodeViewPortalProviderAPI, dispatch, options); } }, { name: 'mediaKeymap', plugin: function plugin(_ref7) { var _api$analytics4, _api$selection; var getIntl = _ref7.getIntl; return (0, _keymap2.default)(options, api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : _api$analytics4.actions, api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 ? void 0 : _api$selection.actions, api === null || api === void 0 ? void 0 : api.width, getIntl); } }]; if (options && options.allowMediaSingle) { pmPlugins.push({ name: 'mediaSingleKeymap', plugin: function plugin(_ref8) { var schema = _ref8.schema; return (0, _keymapMedia.default)(schema); } }); } if (options && options.allowAltTextOnImages) { pmPlugins.push({ name: 'mediaAltText', plugin: _altText.createPlugin }); pmPlugins.push({ name: 'mediaAltTextKeymap', plugin: function plugin(_ref9) { var _api$analytics5; var schema = _ref9.schema; return (0, _keymap.default)(schema, api === null || api === void 0 || (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : _api$analytics5.actions); } }); } if (options && options.allowLinking) { pmPlugins.push({ name: 'mediaLinking', plugin: function plugin(_ref0) { var dispatch = _ref0.dispatch; return (0, _linking.default)(dispatch); } }); pmPlugins.push({ name: 'mediaLinkingKeymap', plugin: function plugin(_ref1) { var schema = _ref1.schema; return (0, _keymap3.default)(schema); } }); } if (options && options.allowAdvancedToolBarOptions && options.allowResizing && (0, _toolbarFlagCheck.areToolbarFlagsEnabled)(Boolean(api === null || api === void 0 ? void 0 : api.toolbar)) && options.allowPixelResizing) { pmPlugins.push({ name: 'mediaPixelResizing', plugin: _pixelResizing.createPlugin }); } pmPlugins.push({ name: 'mediaAIGeneratingDecoration', plugin: function plugin() { return (0, _aiGeneratingDecoration.createAIGeneratingDecorationPlugin)(); } }); pmPlugins.push({ name: 'mediaSelectionHandler', plugin: function plugin() { var mediaSelectionHandlerPlugin = new _safePlugin.SafePlugin({ key: new _state.PluginKey('mediaSelectionHandlerPlugin'), props: { handleScrollToSelection: function handleScrollToSelection(view) { var selection = view.state.selection; if (!(selection instanceof _state.NodeSelection) || selection.node.type.name !== 'media') { return false; } var _view$domAtPos = view.domAtPos(selection.from), node = _view$domAtPos.node, offset = _view$domAtPos.offset; if ( // Is the media element mounted already? offset === node.childNodes.length) { // Media is not ready, so stop the scroll request return true; } // Media is ready, keep the scrolling request return false; } } }); return mediaSelectionHandlerPlugin; } }); return pmPlugins; }, contentComponent: function contentComponent(_ref10) { var editorView = _ref10.editorView, appearance = _ref10.appearance; if (!editorView) { return null; } return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(MediaViewerFunctionalComponent, { api: api, editorView: editorView, mediaViewerExtensions: options === null || options === void 0 ? void 0 : options.mediaViewerExtensions }), /*#__PURE__*/_react.default.createElement(MediaPickerFunctionalComponent, { editorDomElement: editorView.dom, appearance: appearance, api: api })); }, secondaryToolbarComponent: function secondaryToolbarComponent(_ref11) { var disabled = _ref11.disabled; return /*#__PURE__*/_react.default.createElement(_ToolbarMedia.default, { isDisabled: disabled, isReducedSpacing: true, api: api }); }, pluginsOptions: { quickInsert: function quickInsert(_ref12) { var formatMessage = _ref12.formatMessage; return !(api !== null && api !== void 0 && api.mediaInsert) ? [{ id: 'media', title: formatMessage(_messages.toolbarInsertBlockMessages.mediaFiles), description: formatMessage(_messages.toolbarInsertBlockMessages.mediaFilesDescription), priority: 400, keywords: ['attachment', 'gif', 'media', 'picture', 'image', 'video', 'file'], icon: function icon() { return /*#__PURE__*/_react.default.createElement(_quickInsert.IconImages, null); }, isDisabledOffline: true, action: function action(insert, state) { var _api$analytics6; var pluginState = _pluginKey.stateKey.getState(state); pluginState === null || pluginState === void 0 || pluginState.showMediaPicker(); var tr = insert(''); api === null || api === void 0 || (_api$analytics6 = api.analytics) === null || _api$analytics6 === void 0 || _api$analytics6.actions.attachAnalyticsEvent({ action: _analytics.ACTION.OPENED, actionSubject: _analytics.ACTION_SUBJECT.PICKER, actionSubjectId: _analytics.ACTION_SUBJECT_ID.PICKER_CLOUD, attributes: { inputMethod: _analytics.INPUT_METHOD.QUICK_INSERT }, eventType: _analytics.EVENT_TYPE.UI })(tr); return tr; } }] : []; }, floatingToolbar: function floatingToolbar(state, intl, providerFactory) { var _api$editorViewMode; return (0, _toolbar.floatingToolbar)(state, intl, { providerFactory: providerFactory, allowMediaInline: options && (0, _mediaCommon.getMediaFeatureFlag)('mediaInline', options.featureFlags), allowResizing: options && options.allowResizing, allowResizingInTables: options && options.allowResizingInTables, allowCommentsOnMedia: options && options.allowCommentsOnMedia, allowLinking: options && options.allowLinking, allowAdvancedToolBarOptions: options && options.allowAdvancedToolBarOptions, allowAltTextOnImages: options && options.allowAltTextOnImages, allowImageEditing: !!(api !== null && api !== void 0 && api.mediaEditing) && options && options.allowImageEditing, allowImagePreview: options && options.allowImagePreview, altTextValidator: options && options.altTextValidator, fullWidthEnabled: options && options.fullWidthEnabled, allowMediaInlineImages: options && options.allowMediaInlineImages, isViewOnly: (api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode) === 'view', allowPixelResizing: options === null || options === void 0 ? void 0 : options.allowPixelResizing, onCommentButtonMount: options === null || options === void 0 ? void 0 : options.onCommentButtonMount, createCommentExperience: options === null || options === void 0 ? void 0 : options.createCommentExperience }, api); } } }; };