@atlaskit/renderer
Version:
Renderer component
415 lines (412 loc) • 18.8 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/inherits";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
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) { _defineProperty(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; }
import _regeneratorRuntime from "@babel/runtime/regenerator";
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
import React, { Component, useContext } from 'react';
import { filter } from '@atlaskit/adf-utils/traverse';
import { Card as CardAsync, CardSync, CardLoading, CardError } from '@atlaskit/media-card';
import { MediaClientContext } from '@atlaskit/media-client-react';
import { withImageLoader } from '@atlaskit/editor-common/utils';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
import AnalyticsContext from '../analytics/analyticsContext';
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
export var mediaIdentifierMap = new Map();
export var getListOfIdentifiersFromDoc = function getListOfIdentifiersFromDoc(doc) {
if (!doc) {
return [];
}
return filter(doc, function (node) {
return node.type === 'media';
}).reduce(function (identifierList, mediaNode) {
if (mediaNode.attrs) {
var _mediaNode$attrs = mediaNode.attrs,
type = _mediaNode$attrs.type,
dataURI = _mediaNode$attrs.url,
id = _mediaNode$attrs.id;
if (type === 'file' && id) {
identifierList.push({
mediaItemType: 'file',
id: id
});
} else if (type === 'external' && dataURI) {
identifierList.push({
mediaItemType: 'external-image',
dataURI: dataURI,
name: dataURI
});
}
}
return identifierList;
}, []);
};
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/react/no-class-components
export var MediaCardView = /*#__PURE__*/function (_Component) {
function MediaCardView() {
var _this;
_classCallCheck(this, MediaCardView);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _callSuper(this, MediaCardView, [].concat(args));
_defineProperty(_this, "state", {});
_defineProperty(_this, "saveFileState", /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(id) {
var _this$props, collectionName, mediaClient, options, fileState, _t;
return _regeneratorRuntime.wrap(function (_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_this$props = _this.props, collectionName = _this$props.collection, mediaClient = _this$props.mediaClient;
options = {
collectionName: collectionName
};
_context.prev = 1;
if (!mediaClient) {
_context.next = 3;
break;
}
_context.next = 2;
return mediaClient.file.getCurrentState(id, options);
case 2:
fileState = _context.sent;
_this.setState({
fileState: fileState
});
case 3:
_context.next = 5;
break;
case 4:
_context.prev = 4;
_t = _context["catch"](1);
case 5:
case "end":
return _context.stop();
}
}, _callee, null, [[1, 4]]);
}));
return function (_x) {
return _ref.apply(this, arguments);
};
}());
_defineProperty(_this, "onError", function (reason) {
var _this$props$fireAnaly, _this$props3;
var _this$props2 = _this.props,
nestedUnder = _this$props2.nestedUnder,
rendererContext = _this$props2.rendererContext;
(_this$props$fireAnaly = (_this$props3 = _this.props).fireAnalyticsEvent) === null || _this$props$fireAnaly === void 0 || _this$props$fireAnaly.call(_this$props3, {
action: ACTION.ERRORED,
actionSubject: ACTION_SUBJECT.RENDERER,
actionSubjectId: ACTION_SUBJECT_ID.MEDIA,
eventType: EVENT_TYPE.UI,
attributes: _objectSpread(_objectSpread({
reason: reason,
external: false
}, nestedUnder && editorExperiment('platform_synced_block', true) ? {
nestedUnder: nestedUnder
} : {}), rendererContext !== null && rendererContext !== void 0 && rendererContext.nestedRendererType && editorExperiment('platform_synced_block', true) ? {
nestedRendererType: rendererContext.nestedRendererType
} : {})
});
});
_defineProperty(_this, "renderLoadingCard", function () {
var cardDimensions = _this.props.cardDimensions;
return /*#__PURE__*/React.createElement(CardLoading, {
dimensions: cardDimensions,
interactionName: "renderer-media-card-loading"
});
});
/**
* We want to call provided `eventHandlers.media.onClick` when it's provided,
* but we also don't want to call it when it's a video and inline video player is enabled.
* This is due to consumers normally process this onClick call by opening media viewer and
* we don't want that to happened described above text.
*/
_defineProperty(_this, "getOnCardClickCallback", function (isInlinePlayer) {
var eventHandlers = _this.props.eventHandlers;
if (eventHandlers && eventHandlers.media && eventHandlers.media.onClick) {
return function (result, analyticsEvent) {
var isVideo = result.mediaItemDetails && result.mediaItemDetails.mediaType === 'video';
var isVideoWithInlinePlayer = isInlinePlayer && isVideo;
if (!isVideoWithInlinePlayer && eventHandlers && eventHandlers.media && eventHandlers.media.onClick) {
eventHandlers.media.onClick(result, analyticsEvent);
}
};
}
return undefined;
});
return _this;
}
_inherits(MediaCardView, _Component);
return _createClass(MediaCardView, [{
key: "componentDidMount",
value: function () {
var _componentDidMount = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
var _this$props4, rendererContext, contextIdentifierProvider, id, url, collectionName, nodeIsInCache, _t2, _t3;
return _regeneratorRuntime.wrap(function (_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
_this$props4 = this.props, rendererContext = _this$props4.rendererContext, contextIdentifierProvider = _this$props4.contextIdentifierProvider, id = _this$props4.id, url = _this$props4.url, collectionName = _this$props4.collection;
if (!contextIdentifierProvider) {
_context2.next = 2;
break;
}
_t2 = this;
_context2.next = 1;
return contextIdentifierProvider;
case 1:
_t3 = _context2.sent;
_t2.setState.call(_t2, {
contextIdentifierProvider: _t3
});
case 2:
nodeIsInCache = id && mediaIdentifierMap.has(id) || url && mediaIdentifierMap.has(url);
if (rendererContext && rendererContext.adDoc && !nodeIsInCache) {
getListOfIdentifiersFromDoc(rendererContext.adDoc).forEach(function (identifier) {
if (identifier.mediaItemType === 'file' && identifier.id === id) {
mediaIdentifierMap.set(identifier.id, _objectSpread(_objectSpread({}, identifier), {}, {
collectionName: collectionName
}));
} else if (identifier.mediaItemType === 'external-image') {
mediaIdentifierMap.set(identifier.dataURI, identifier);
}
});
}
if (id) {
this.saveFileState(id);
}
case 3:
case "end":
return _context2.stop();
}
}, _callee2, this);
}));
function componentDidMount() {
return _componentDidMount.apply(this, arguments);
}
return componentDidMount;
}()
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps) {
var oldId = prevProps.id;
if (this.props.id && oldId !== this.props.id) {
this.saveFileState(this.props.id);
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
var _this$props5 = this.props,
id = _this$props5.id,
dataURI = _this$props5.url;
if (id) {
mediaIdentifierMap.delete(id);
} else if (dataURI) {
mediaIdentifierMap.delete(dataURI);
}
}
}, {
key: "renderExternal",
value: function renderExternal(shouldOpenMediaViewer) {
var _this$props6 = this.props,
cardDimensions = _this$props6.cardDimensions,
resizeMode = _this$props6.resizeMode,
appearance = _this$props6.appearance,
url = _this$props6.url,
imageStatus = _this$props6.imageStatus,
disableOverlay = _this$props6.disableOverlay,
alt = _this$props6.alt,
featureFlags = _this$props6.featureFlags,
ssr = _this$props6.ssr,
mediaClient = _this$props6.mediaClient,
dataAttributes = _this$props6.dataAttributes,
enableSyncMediaCard = _this$props6.enableSyncMediaCard,
localId = _this$props6.localId;
if (imageStatus === 'loading' || !url) {
return this.renderLoadingCard();
}
var identifier = {
dataURI: url,
name: url,
mediaItemType: 'external-image'
};
// we need this statement for the mandatory mediaClientConfig below
var mediaClientConfig = mediaClient === null || mediaClient === void 0 ? void 0 : mediaClient.mediaClientConfig;
var Card = enableSyncMediaCard ? CardSync : CardAsync;
return (
/*#__PURE__*/
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
React.createElement("div", _extends({}, dataAttributes, {
"data-node-type": "media",
"data-local-id": localId
}), /*#__PURE__*/React.createElement(Card
// TODO: MPT-315 - clean up after we move mediaClientConfig into FileIdentifier
// context is not really used when the type is external and we want to render the component asap
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
, {
mediaClientConfig: mediaClientConfig,
alt: alt,
identifier: identifier,
dimensions: cardDimensions,
appearance: appearance,
resizeMode: resizeMode,
disableOverlay: disableOverlay,
shouldOpenMediaViewer: shouldOpenMediaViewer,
mediaViewerItems: Array.from(mediaIdentifierMap.values()),
featureFlags: featureFlags,
ssr: ssr === null || ssr === void 0 ? void 0 : ssr.mode,
shouldHideTooltip: false,
onError: expValEquals('platform_editor_media_error_analytics', 'isEnabled', true) ? this.onError : undefined
}))
);
}
}, {
key: "render",
value: function render() {
var _this$state = this.state,
contextIdentifierProvider = _this$state.contextIdentifierProvider,
fileState = _this$state.fileState;
var _this$props7 = this.props,
id = _this$props7.id,
alt = _this$props7.alt,
type = _this$props7.type,
collection = _this$props7.collection,
occurrenceKey = _this$props7.occurrenceKey,
cardDimensions = _this$props7.cardDimensions,
resizeMode = _this$props7.resizeMode,
disableOverlay = _this$props7.disableOverlay,
useInlinePlayer = _this$props7.useInlinePlayer,
originalDimensions = _this$props7.originalDimensions,
forceOpenMediaViewer = _this$props7.shouldOpenMediaViewer,
featureFlags = _this$props7.featureFlags,
shouldEnableDownloadButton = _this$props7.shouldEnableDownloadButton,
ssr = _this$props7.ssr,
mediaClient = _this$props7.mediaClient,
dataAttributes = _this$props7.dataAttributes,
enableSyncMediaCard = _this$props7.enableSyncMediaCard,
localId = _this$props7.localId,
mediaViewerExtensions = _this$props7.mediaViewerExtensions;
var isMobile = false;
var shouldPlayInline = useInlinePlayer !== undefined ? useInlinePlayer : true;
var isInlinePlayer = isMobile ? false : shouldPlayInline;
var onCardClick = this.getOnCardClickCallback(isInlinePlayer);
var shouldOpenMediaViewer = typeof forceOpenMediaViewer === 'boolean' ? forceOpenMediaViewer : !isMobile && !onCardClick;
if (type === 'external') {
return this.renderExternal(shouldOpenMediaViewer);
}
if (type === 'link') {
return null;
}
var mediaClientConfig = !!ssr ? ssr.config : mediaClient === null || mediaClient === void 0 ? void 0 : mediaClient.mediaClientConfig;
if (!mediaClientConfig || !id) {
return this.renderLoadingCard();
}
if (!id || type !== 'file') {
return /*#__PURE__*/React.createElement(CardError, {
dimensions: cardDimensions
});
}
var contextId = contextIdentifierProvider && contextIdentifierProvider.objectId;
var identifier = {
id: id,
mediaItemType: 'file',
collectionName: collection,
occurrenceKey: occurrenceKey
};
var Card = enableSyncMediaCard ? CardSync : CardAsync;
// Quick solution to disable lazy loading of images on PDF export pages in Confluence to remedy an issue with images never loading
// More robust solution will be implemented as part of CCPDF-233 - Link: https://hello.jira.atlassian.cloud/browse/CCPDF-233
var currentUrl = window.location.href;
var shouldDisableLazyLoading = expValEquals('platform_editor_disable_lazy_load_media', 'isEnabled', true) && currentUrl.includes('/wiki/pdf/spaces/');
return /*#__PURE__*/React.createElement("div", _extends({}, getClipboardAttrs({
id: id,
alt: alt,
collection: collection,
contextIdentifierProvider: contextIdentifierProvider,
originalDimensions: originalDimensions,
fileState: fileState
}), dataAttributes, {
"data-local-id": localId
}), /*#__PURE__*/React.createElement(Card, {
identifier: identifier,
alt: alt,
contextId: contextId,
mediaClientConfig: mediaClientConfig,
dimensions: cardDimensions,
originalDimensions: originalDimensions,
onClick: onCardClick,
resizeMode: resizeMode,
isLazy: !isMobile && !shouldDisableLazyLoading,
disableOverlay: disableOverlay,
useInlinePlayer: isInlinePlayer,
shouldOpenMediaViewer: shouldOpenMediaViewer,
mediaViewerItems: Array.from(mediaIdentifierMap.values()),
featureFlags: featureFlags,
shouldEnableDownloadButton: shouldEnableDownloadButton,
ssr: ssr === null || ssr === void 0 ? void 0 : ssr.mode,
shouldHideTooltip: isMobile,
mediaViewerExtensions: mediaViewerExtensions,
onError: expValEquals('platform_editor_media_error_analytics', 'isEnabled', true) ? this.onError : undefined
}));
}
}]);
}(Component);
// Needed for copy & paste
export var getClipboardAttrs = function getClipboardAttrs(_ref2) {
var id = _ref2.id,
alt = _ref2.alt,
collection = _ref2.collection,
contextIdentifierProvider = _ref2.contextIdentifierProvider,
originalDimensions = _ref2.originalDimensions,
fileState = _ref2.fileState;
var contextId = contextIdentifierProvider && contextIdentifierProvider.objectId;
var width = originalDimensions && originalDimensions.width;
var height = originalDimensions && originalDimensions.height;
var fileName = 'file'; // default name is needed for Confluence
var fileSize = 1;
var fileMimeType = '';
if (fileState && fileState.status !== 'error') {
fileSize = fileState.size;
fileName = fileState.name;
fileMimeType = fileState.mimeType;
}
return {
'data-context-id': contextId,
'data-type': 'file',
'data-node-type': 'media',
'data-width': width,
'data-height': height,
'data-id': id,
'data-collection': collection,
'data-file-name': fileName,
'data-file-size': fileSize,
'data-file-mime-type': fileMimeType,
'data-alt': alt
};
};
export var MediaCardInternal = function MediaCardInternal(props) {
var mediaClient = useContext(MediaClientContext);
return /*#__PURE__*/React.createElement(AnalyticsContext.Consumer, null, function (_ref3) {
var fireAnalyticsEvent = _ref3.fireAnalyticsEvent;
return /*#__PURE__*/React.createElement(MediaCardView
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
, _extends({}, props, {
mediaClient: mediaClient,
fireAnalyticsEvent: fireAnalyticsEvent
}));
});
};
export var MediaCard = withImageLoader(MediaCardInternal);