@atlaskit/editor-plugin-media
Version:
Media plugin for @atlaskit/editor-core
376 lines (373 loc) • 18.7 kB
JavaScript
;
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();
};
};