@atlaskit/editor-plugin-media
Version:
Media plugin for @atlaskit/editor-core
171 lines (170 loc) • 5.83 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import React from 'react';
import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
import { DEFAULT_IMAGE_HEIGHT, DEFAULT_IMAGE_WIDTH } from '@atlaskit/editor-common/media-single';
import { WithProviders } from '@atlaskit/editor-common/provider-factory';
import { SelectionBasedNodeView } from '@atlaskit/editor-common/selection-based-node-view';
import { getAttrsFromUrl } from '@atlaskit/media-client';
import { updateCurrentMediaNodeAttrs } from '../../commands/helpers';
import { isMediaBlobUrlFromAttrs } from '../../utils/media-common';
import MediaNode from './media';
const MediaNodeWithProviders = ({
pluginInjectionApi,
innerComponent
}) => {
const {
widthState
} = useSharedPluginState(pluginInjectionApi, ['width']);
return innerComponent({
width: widthState
});
};
function isMediaDecorationSpec(decoration) {
return decoration.spec.type !== undefined && decoration.spec.selected !== undefined;
}
class MediaNodeView extends SelectionBasedNodeView {
constructor(...args) {
super(...args);
_defineProperty(this, "isSelected", false);
_defineProperty(this, "onExternalImageLoaded", dimensions => {
const getPos = this.getPos;
const {
width,
height,
...rest
} = this.getAttrs();
if (!width || !height) {
updateCurrentMediaNodeAttrs({
...rest,
width: width || dimensions.width,
height: height || dimensions.height
}, {
node: this.node,
getPos
})(this.view.state, this.view.dispatch);
}
});
_defineProperty(this, "renderMediaNodeWithState", (mediaProvider, contextIdentifierProvider) => {
return ({
width: editorWidth
}) => {
const getPos = this.getPos;
const {
mediaOptions
} = this.reactComponentProps;
const attrs = this.getAttrs();
const url = attrs.type === 'external' ? attrs.url : '';
let {
width,
height
} = attrs;
if (this.isMediaBlobUrl()) {
const urlAttrs = getAttrsFromUrl(url);
if (urlAttrs) {
const {
width: urlWidth,
height: urlHeight
} = urlAttrs;
width = width || urlWidth;
height = height || urlHeight;
}
}
width = width || DEFAULT_IMAGE_WIDTH;
height = height || DEFAULT_IMAGE_HEIGHT;
// mediaSingle defines the max dimensions, so we don't need to constrain twice.
const maxDimensions = {
width: `100%`,
height: `100%`
};
const originalDimensions = {
width,
height
};
return /*#__PURE__*/React.createElement(MediaNode, {
view: this.view,
node: this.node,
getPos: getPos,
selected: this.nodeInsideSelection(),
originalDimensions: originalDimensions,
maxDimensions: maxDimensions,
url: url,
mediaProvider: mediaProvider,
contextIdentifierProvider: contextIdentifierProvider,
mediaOptions: mediaOptions,
onExternalImageLoaded: this.onExternalImageLoaded
});
};
});
_defineProperty(this, "renderMediaNodeWithProviders", ({
mediaProvider,
contextIdentifierProvider
}) => {
const {
pluginInjectionApi
} = this.reactComponentProps;
return /*#__PURE__*/React.createElement(MediaNodeWithProviders, {
pluginInjectionApi: pluginInjectionApi,
innerComponent: this.renderMediaNodeWithState(mediaProvider, contextIdentifierProvider)
});
});
}
createDomRef() {
const domRef = document.createElement('div');
if (this.reactComponentProps.mediaOptions && this.reactComponentProps.mediaOptions.allowMediaSingleEditable) {
// workaround Chrome bug in https://product-fabric.atlassian.net/browse/ED-5379
// see also: https://github.com/ProseMirror/prosemirror/issues/884
domRef.contentEditable = 'true';
}
return domRef;
}
viewShouldUpdate(nextNode, decorations) {
const hasMediaNodeSelectedDecoration = decorations.some(decoration => isMediaDecorationSpec(decoration) && decoration.spec.type === 'media' && decoration.spec.selected);
if (this.isSelected !== hasMediaNodeSelectedDecoration) {
this.isSelected = hasMediaNodeSelectedDecoration;
return true;
}
if (this.node.attrs !== nextNode.attrs) {
return true;
}
return super.viewShouldUpdate(nextNode, decorations);
}
stopEvent(event) {
// Don't trap right click events on media node
if (['mousedown', 'contextmenu'].indexOf(event.type) !== -1) {
const mouseEvent = event;
if (mouseEvent.button === 2) {
return true;
}
}
return false;
}
getAttrs() {
const {
attrs
} = this.node;
return attrs;
}
isMediaBlobUrl() {
const attrs = this.getAttrs();
return isMediaBlobUrlFromAttrs(attrs);
}
render() {
const {
providerFactory
} = this.reactComponentProps;
return /*#__PURE__*/React.createElement(WithProviders, {
providers: ['mediaProvider', 'contextIdentifierProvider'],
providerFactory: providerFactory,
renderNode: this.renderMediaNodeWithProviders
});
}
}
export const ReactMediaNode = (portalProviderAPI, eventDispatcher, providerFactory, mediaOptions = {}, pluginInjectionApi) => (node, view, getPos) => {
const hasIntlContext = true;
return new MediaNodeView(node, view, getPos, portalProviderAPI, eventDispatcher, {
eventDispatcher,
providerFactory,
mediaOptions,
pluginInjectionApi
}, undefined, undefined, undefined, hasIntlContext).init();
};