UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

376 lines (373 loc) 18.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.ReactMediaGroupNode = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var _reactIntlNext = require("react-intl-next"); var _hooks = require("@atlaskit/editor-common/hooks"); var _providerFactory = require("@atlaskit/editor-common/provider-factory"); var _reactNodeView = _interopRequireDefault(require("@atlaskit/editor-common/react-node-view")); var _utils = require("@atlaskit/editor-common/utils"); var _close = _interopRequireDefault(require("@atlaskit/icon/glyph/editor/close")); var _mediaCommon = require("@atlaskit/media-common"); var _mediaFilmstrip = require("@atlaskit/media-filmstrip"); var _pluginKey = require("../pm-plugins/plugin-key"); var _mediaNodeUpdater = require("./mediaNodeUpdater"); var _messages = require("./messages"); 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; } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } var isMediaGroupSelectedFromProps = function isMediaGroupSelectedFromProps(props) { /** * ED-19831 * There is a getPos issue coming from this code. We need to apply this workaround for now and apply a patch * directly to confluence since this bug is now in production. */ var pos; try { pos = props.getPos ? props.getPos() : undefined; } catch (e) { pos = undefined; } if (typeof pos !== 'number') { return false; } return (0, _utils.isNodeSelectedOrInRange)(props.anchorPos, props.headPos, pos, props.node.nodeSize); }; var hasSelectionChanged = function hasSelectionChanged(oldProps, newProps) { if (isMediaGroupSelectedFromProps(oldProps) !== isMediaGroupSelectedFromProps(newProps)) { return true; } if (isMediaGroupSelectedFromProps(newProps) === _utils.SelectedState.selectedInside) { return oldProps.anchorPos !== newProps.anchorPos; } return false; }; // eslint-disable-next-line @repo/internal/react/no-class-components var MediaGroup = /*#__PURE__*/function (_React$Component) { (0, _inherits2.default)(MediaGroup, _React$Component); var _super = _createSuper(MediaGroup); function MediaGroup(_props) { var _this; (0, _classCallCheck2.default)(this, MediaGroup); _this = _super.call(this, _props); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "state", { viewMediaClientConfig: undefined }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "updateNodeAttrs", function (props, node, getPos) { var view = props.view, mediaProvider = props.mediaProvider, contextIdentifierProvider = props.contextIdentifierProvider; var mediaNodeUpdater = new _mediaNodeUpdater.MediaNodeUpdater({ view: view, mediaProvider: mediaProvider, contextIdentifierProvider: contextIdentifierProvider, node: node, isMediaSingle: false }); mediaNodeUpdater.updateNodeAttrs(getPos); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "setMediaItems", function (props) { var _this$mediaPluginStat; var updatedAttrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var node = props.node; var oldMediaNodes = _this.mediaNodes; _this.mediaNodes = []; node.forEach(function (item, childOffset) { var getPos = function getPos() { var pos = props.getPos(); if (typeof pos !== 'number') { // That may seems weird, but the previous type wasn't match with the real ProseMirror code. And a lot of Media API was built expecting a number // Because the original code would return NaN on runtime // We are just make it explict now. // We may run a deep investagation on Media code to figure out a better fix. But, for now, we want to keep the current behavior. // TODO: ED-13910 prosemirror-bump leftovers return NaN; } return pos + childOffset + 1; }; _this.mediaNodes.push(item); if (updatedAttrs) { _this.updateNodeAttrs(props, item, getPos); } }); (_this$mediaPluginStat = _this.mediaPluginState) === null || _this$mediaPluginStat === void 0 || _this$mediaPluginStat.handleMediaGroupUpdate(oldMediaNodes, _this.mediaNodes); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getIdentifier", function (item) { if (item.attrs.type === 'external') { return { mediaItemType: 'external-image', dataURI: item.attrs.url }; } return { id: item.attrs.id, mediaItemType: 'file', collectionName: item.attrs.collection }; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isNodeSelected", function (nodePos) { var selected = isMediaGroupSelectedFromProps(_this.props); if (selected === _utils.SelectedState.selectedInRange) { return true; } if (selected === _utils.SelectedState.selectedInside && _this.props.anchorPos === nodePos) { return true; } return false; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "renderChildNodes", function () { var viewMediaClientConfig = _this.state.viewMediaClientConfig; var _this$props = _this.props, getPos = _this$props.getPos, allowLazyLoading = _this$props.allowLazyLoading, disabled = _this$props.disabled, mediaOptions = _this$props.mediaOptions; var items = _this.mediaNodes.map(function (item, idx) { // We declared this to get a fresh position every time var getNodePos = function getNodePos() { var pos = getPos(); if (typeof pos !== 'number') { // That may seems weird, but the previous type wasn't match with the real ProseMirror code. And a lot of Media API was built expecting a number // Because the original code would return NaN on runtime // We are just make it explict now. // We may run a deep investagation on Media code to figure out a better fix. But, for now, we want to keep the current behavior. // TODO: ED-13910 prosemirror-bump leftovers return NaN; } return pos + idx + 1; }; // Media Inline creates a floating toolbar with the same options, excludes these options if enabled var mediaInlineOptions = function mediaInlineOptions() { var allowMediaInline = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; if (!allowMediaInline) { return { shouldEnableDownloadButton: mediaOptions.enableDownloadButton, actions: [{ handler: disabled || !_this.mediaPluginState ? function () {} : _this.mediaPluginState.handleMediaNodeRemoval.bind(null, undefined, getNodePos), icon: /*#__PURE__*/_react.default.createElement(_close.default, { label: _this.props.intl.formatMessage(_messages.messages.mediaGroupDeleteLabel) }) }] }; } }; return _objectSpread({ identifier: _this.getIdentifier(item), isLazy: allowLazyLoading, selected: _this.isNodeSelected(getNodePos()), onClick: function onClick() { (0, _utils.setNodeSelection)(_this.props.view, getNodePos()); } }, mediaInlineOptions((0, _mediaCommon.getMediaFeatureFlag)('mediaInline', mediaOptions.featureFlags))); }); return /*#__PURE__*/_react.default.createElement(_mediaFilmstrip.Filmstrip, { items: items, mediaClientConfig: viewMediaClientConfig, featureFlags: mediaOptions.featureFlags }); }); _this.mediaNodes = []; _this.mediaPluginState = _pluginKey.stateKey.getState(_props.view.state); _this.setMediaItems(_props); _this.state = { viewMediaClientConfig: undefined }; return _this; } (0, _createClass2.default)(MediaGroup, [{ key: "componentDidMount", value: function componentDidMount() { var _this2 = this; this.updateMediaClientConfig(); this.mediaNodes.forEach( /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(node) { var _this2$props, view, mediaProvider, contextIdentifierProvider, mediaNodeUpdater, getPos, contextId, hasDifferentContextId; return _regenerator.default.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: if (!(node.attrs.type === 'external')) { _context.next = 2; break; } return _context.abrupt("return"); case 2: _this2$props = _this2.props, view = _this2$props.view, mediaProvider = _this2$props.mediaProvider, contextIdentifierProvider = _this2$props.contextIdentifierProvider; mediaNodeUpdater = new _mediaNodeUpdater.MediaNodeUpdater({ view: view, mediaProvider: mediaProvider, contextIdentifierProvider: contextIdentifierProvider, node: node, isMediaSingle: false }); getPos = function getPos() { var pos = _this2.props.getPos(); if (typeof pos !== 'number') { // That may seems weird, but the previous type wasn't match with the real ProseMirror code. And a lot of Media API was built expecting a number // Because the original code would return NaN on runtime // We are just make it explict now. // We may run a deep investagation on Media code to figure out a better fix. But, for now, we want to keep the current behavior. // TODO: ED-13910 prosemirror-bump leftovers return NaN; } return pos + 1; }; contextId = mediaNodeUpdater.getNodeContextId(); if (contextId) { _context.next = 9; break; } _context.next = 9; return mediaNodeUpdater.updateNodeContextId(getPos); case 9: _context.next = 11; return mediaNodeUpdater.hasDifferentContextId(); case 11: hasDifferentContextId = _context.sent; if (!hasDifferentContextId) { _context.next = 15; break; } _context.next = 15; return mediaNodeUpdater.copyNodeFromPos(getPos, { traceId: node.attrs.__mediaTraceId }); case 15: case "end": return _context.stop(); } }, _callee); })); return function (_x) { return _ref.apply(this, arguments); }; }()); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { var _this$mediaPluginStat2; (_this$mediaPluginStat2 = this.mediaPluginState) === null || _this$mediaPluginStat2 === void 0 || _this$mediaPluginStat2.handleMediaGroupUpdate(this.mediaNodes, []); } }, { key: "UNSAFE_componentWillReceiveProps", value: function UNSAFE_componentWillReceiveProps(props) { this.updateMediaClientConfig(); this.setMediaItems(props, props.isCopyPasteEnabled || props.isCopyPasteEnabled === undefined); } }, { key: "shouldComponentUpdate", value: function shouldComponentUpdate(nextProps) { var _this$mediaPluginStat3; if (hasSelectionChanged(this.props, nextProps) || this.props.node !== nextProps.node || this.state.viewMediaClientConfig !== ((_this$mediaPluginStat3 = this.mediaPluginState) === null || _this$mediaPluginStat3 === void 0 ? void 0 : _this$mediaPluginStat3.mediaClientConfig)) { return true; } return false; } }, { key: "updateMediaClientConfig", value: function updateMediaClientConfig() { var viewMediaClientConfig = this.state.viewMediaClientConfig; var _ref2 = this.mediaPluginState || {}, mediaClientConfig = _ref2.mediaClientConfig; if (!viewMediaClientConfig && mediaClientConfig) { this.setState({ viewMediaClientConfig: mediaClientConfig }); } } }, { key: "render", value: function render() { return this.renderChildNodes(); } }]); return MediaGroup; }(_react.default.Component); (0, _defineProperty2.default)(MediaGroup, "displayName", 'MediaGroup'); var IntlMediaGroup = (0, _reactIntlNext.injectIntl)(MediaGroup); var _default = exports.default = IntlMediaGroup; function MediaGroupNodeViewInternal(_ref3) { var renderFn = _ref3.renderFn, pluginInjectionApi = _ref3.pluginInjectionApi; var _useSharedPluginState = (0, _hooks.useSharedPluginState)(pluginInjectionApi, ['editorDisabled']), editorDisabledPlugin = _useSharedPluginState.editorDisabledState; return renderFn({ editorDisabledPlugin: editorDisabledPlugin }); } var MediaGroupNodeView = /*#__PURE__*/function (_ReactNodeView) { (0, _inherits2.default)(MediaGroupNodeView, _ReactNodeView); var _super2 = _createSuper(MediaGroupNodeView); function MediaGroupNodeView() { (0, _classCallCheck2.default)(this, MediaGroupNodeView); return _super2.apply(this, arguments); } (0, _createClass2.default)(MediaGroupNodeView, [{ key: "render", value: function render(props, forwardRef) { var _this3 = this; var providerFactory = props.providerFactory, mediaOptions = props.mediaOptions, pluginInjectionApi = props.pluginInjectionApi; var getPos = this.getPos; return /*#__PURE__*/_react.default.createElement(_providerFactory.WithProviders, { providers: ['mediaProvider', 'contextIdentifierProvider'], providerFactory: providerFactory, renderNode: function renderNode(_ref4) { var mediaProvider = _ref4.mediaProvider, contextIdentifierProvider = _ref4.contextIdentifierProvider; var renderFn = function renderFn(_ref5) { var editorDisabledPlugin = _ref5.editorDisabledPlugin; if (!mediaProvider) { return null; } return /*#__PURE__*/_react.default.createElement(IntlMediaGroup, { node: _this3.node, getPos: getPos, view: _this3.view, forwardRef: forwardRef, disabled: (editorDisabledPlugin || {}).editorDisabled, allowLazyLoading: mediaOptions.allowLazyLoading, mediaProvider: mediaProvider, contextIdentifierProvider: contextIdentifierProvider, isCopyPasteEnabled: mediaOptions.isCopyPasteEnabled, anchorPos: _this3.view.state.selection.$anchor.pos, headPos: _this3.view.state.selection.$head.pos, mediaOptions: mediaOptions }); }; return /*#__PURE__*/_react.default.createElement(MediaGroupNodeViewInternal, { renderFn: renderFn, pluginInjectionApi: pluginInjectionApi }); } }); } }]); return MediaGroupNodeView; }(_reactNodeView.default); var ReactMediaGroupNode = exports.ReactMediaGroupNode = function ReactMediaGroupNode(portalProviderAPI, eventDispatcher, providerFactory) { var mediaOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; var pluginInjectionApi = arguments.length > 4 ? arguments[4] : undefined; return function (node, view, getPos) { var hasIntlContext = true; return new MediaGroupNodeView(node, view, getPos, portalProviderAPI, eventDispatcher, { providerFactory: providerFactory, mediaOptions: mediaOptions, pluginInjectionApi: pluginInjectionApi }, undefined, undefined, undefined, hasIntlContext).init(); }; };