@atlaskit/editor-plugin-media 1.36.5 → 1.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/cjs/nodeviews/mediaGroup.js +19 -0
- package/dist/cjs/nodeviews/mediaGroupNext.js +295 -0
- package/dist/cjs/nodeviews/mediaNodeUpdater.js +1 -3
- package/dist/cjs/plugin.js +22 -4
- package/dist/cjs/pm-plugins/main.js +2 -1
- package/dist/cjs/ui/MediaViewer/PortalWrapper.js +4 -2
- package/dist/cjs/utils/media-common.js +51 -1
- package/dist/es2019/nodeviews/mediaGroup.js +19 -0
- package/dist/es2019/nodeviews/mediaGroupNext.js +249 -0
- package/dist/es2019/nodeviews/mediaNodeUpdater.js +1 -2
- package/dist/es2019/plugin.js +19 -4
- package/dist/es2019/pm-plugins/main.js +2 -1
- package/dist/es2019/ui/MediaViewer/PortalWrapper.js +3 -2
- package/dist/es2019/utils/media-common.js +50 -1
- package/dist/esm/nodeviews/mediaGroup.js +19 -0
- package/dist/esm/nodeviews/mediaGroupNext.js +285 -0
- package/dist/esm/nodeviews/mediaNodeUpdater.js +1 -3
- package/dist/esm/plugin.js +19 -4
- package/dist/esm/pm-plugins/main.js +2 -1
- package/dist/esm/ui/MediaViewer/PortalWrapper.js +4 -2
- package/dist/esm/utils/media-common.js +50 -1
- package/dist/types/nodeviews/mediaGroupNext.d.ts +37 -0
- package/dist/types/ui/MediaViewer/PortalWrapper.d.ts +3 -2
- package/dist/types/utils/media-common.d.ts +5 -0
- package/dist/types-ts4.5/nodeviews/mediaGroupNext.d.ts +37 -0
- package/dist/types-ts4.5/ui/MediaViewer/PortalWrapper.d.ts +3 -2
- package/dist/types-ts4.5/utils/media-common.d.ts +5 -0
- package/package.json +7 -7
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { injectIntl } from 'react-intl-next';
|
|
3
|
+
import { usePreviousState } from '@atlaskit/editor-common/hooks';
|
|
4
|
+
import { nodeViewsMessages as messages } from '@atlaskit/editor-common/media';
|
|
5
|
+
import { isNodeSelectedOrInRange, SelectedState, setNodeSelection } from '@atlaskit/editor-common/utils';
|
|
6
|
+
import EditorCloseIcon from '@atlaskit/icon/glyph/editor/close';
|
|
7
|
+
import { getMediaFeatureFlag } from '@atlaskit/media-common';
|
|
8
|
+
import { Filmstrip } from '@atlaskit/media-filmstrip';
|
|
9
|
+
import { stateKey as mediaStateKey } from '../pm-plugins/plugin-key';
|
|
10
|
+
import { createMediaNodeUpdater } from './mediaNodeUpdater';
|
|
11
|
+
const getIdentifier = item => {
|
|
12
|
+
if (item.attrs.type === 'external') {
|
|
13
|
+
return {
|
|
14
|
+
mediaItemType: 'external-image',
|
|
15
|
+
dataURI: item.attrs.url
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
id: item.attrs.id,
|
|
20
|
+
mediaItemType: 'file',
|
|
21
|
+
collectionName: item.attrs.collection
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
const isNodeSelected = props => (mediaItemPos, mediaGroupPos) => {
|
|
25
|
+
const selected = isNodeSelectedOrInRange(props.anchorPos, props.headPos, mediaGroupPos, props.nodeSize);
|
|
26
|
+
if (selected === SelectedState.selectedInRange) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
if (selected === SelectedState.selectedInside && props.anchorPos === mediaItemPos) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
};
|
|
34
|
+
const prepareFilmstripItem = ({
|
|
35
|
+
allowLazyLoading,
|
|
36
|
+
enableDownloadButton,
|
|
37
|
+
handleMediaNodeRemoval,
|
|
38
|
+
getPos,
|
|
39
|
+
intl,
|
|
40
|
+
isMediaItemSelected,
|
|
41
|
+
setMediaGroupNodeSelection,
|
|
42
|
+
featureFlags
|
|
43
|
+
}) => (item, idx) => {
|
|
44
|
+
// We declared this to get a fresh position every time
|
|
45
|
+
const getNodePos = () => {
|
|
46
|
+
const pos = getPos();
|
|
47
|
+
if (typeof pos !== 'number') {
|
|
48
|
+
// 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
|
|
49
|
+
// Because the original code would return NaN on runtime
|
|
50
|
+
// We are just make it explict now.
|
|
51
|
+
// 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.
|
|
52
|
+
// TODO: ED-13910 prosemirror-bump leftovers
|
|
53
|
+
return NaN;
|
|
54
|
+
}
|
|
55
|
+
return pos + idx + 1;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Media Inline creates a floating toolbar with the same options, excludes these options if enabled
|
|
59
|
+
const mediaInlineOptions = (allowMediaInline = false) => {
|
|
60
|
+
if (!allowMediaInline) {
|
|
61
|
+
return {
|
|
62
|
+
shouldEnableDownloadButton: enableDownloadButton,
|
|
63
|
+
actions: [{
|
|
64
|
+
handler: handleMediaNodeRemoval.bind(null, undefined, getNodePos),
|
|
65
|
+
icon: /*#__PURE__*/React.createElement(EditorCloseIcon, {
|
|
66
|
+
label: intl.formatMessage(messages.mediaGroupDeleteLabel)
|
|
67
|
+
})
|
|
68
|
+
}]
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const mediaGroupPos = getPos();
|
|
73
|
+
return {
|
|
74
|
+
identifier: getIdentifier(item),
|
|
75
|
+
isLazy: allowLazyLoading,
|
|
76
|
+
selected: isMediaItemSelected(getNodePos(), typeof mediaGroupPos === 'number' ? mediaGroupPos : NaN),
|
|
77
|
+
onClick: () => {
|
|
78
|
+
setMediaGroupNodeSelection(getNodePos());
|
|
79
|
+
},
|
|
80
|
+
...mediaInlineOptions(getMediaFeatureFlag('mediaInline', featureFlags))
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Keep returning the same ProseMirror Node, unless the node content changed.
|
|
86
|
+
*
|
|
87
|
+
* React uses shallow comparation with `Object.is`,
|
|
88
|
+
* but that can cause multiple re-renders when the same node is given in a different instance.
|
|
89
|
+
*
|
|
90
|
+
* To avoid unnecessary re-renders, this hook uses the `Node.eq` from ProseMirror API to compare
|
|
91
|
+
* previous and new values.
|
|
92
|
+
*/
|
|
93
|
+
const useLatestMediaGroupNode = nextMediaNode => {
|
|
94
|
+
const previousMediaNode = usePreviousState(nextMediaNode);
|
|
95
|
+
const [mediaNode, setMediaNode] = React.useState(nextMediaNode);
|
|
96
|
+
React.useEffect(() => {
|
|
97
|
+
if (!previousMediaNode) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!previousMediaNode.eq(nextMediaNode)) {
|
|
101
|
+
setMediaNode(nextMediaNode);
|
|
102
|
+
}
|
|
103
|
+
}, [previousMediaNode, nextMediaNode]);
|
|
104
|
+
return mediaNode;
|
|
105
|
+
};
|
|
106
|
+
const runMediaNodeUpdate = async ({
|
|
107
|
+
mediaNodeUpdater,
|
|
108
|
+
getPos,
|
|
109
|
+
node,
|
|
110
|
+
updateAttrs
|
|
111
|
+
}) => {
|
|
112
|
+
if (updateAttrs) {
|
|
113
|
+
await mediaNodeUpdater.updateNodeAttrs(getPos);
|
|
114
|
+
}
|
|
115
|
+
const contextId = mediaNodeUpdater.getNodeContextId();
|
|
116
|
+
if (!contextId) {
|
|
117
|
+
await mediaNodeUpdater.updateNodeContextId(getPos);
|
|
118
|
+
}
|
|
119
|
+
const hasDifferentContextId = await mediaNodeUpdater.hasDifferentContextId();
|
|
120
|
+
if (hasDifferentContextId) {
|
|
121
|
+
await mediaNodeUpdater.copyNodeFromPos(getPos, {
|
|
122
|
+
traceId: node.attrs.__mediaTraceId
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const noop = () => {};
|
|
127
|
+
export const MediaGroupNext = injectIntl( /*#__PURE__*/React.memo(props => {
|
|
128
|
+
const {
|
|
129
|
+
mediaOptions: {
|
|
130
|
+
allowLazyLoading,
|
|
131
|
+
enableDownloadButton,
|
|
132
|
+
featureFlags
|
|
133
|
+
},
|
|
134
|
+
intl,
|
|
135
|
+
getPos,
|
|
136
|
+
anchorPos,
|
|
137
|
+
headPos,
|
|
138
|
+
view,
|
|
139
|
+
disabled,
|
|
140
|
+
editorViewMode,
|
|
141
|
+
mediaProvider,
|
|
142
|
+
contextIdentifierProvider,
|
|
143
|
+
isCopyPasteEnabled
|
|
144
|
+
} = props;
|
|
145
|
+
const mediaGroupNode = useLatestMediaGroupNode(props.node);
|
|
146
|
+
const mediaPluginState = useMemo(() => {
|
|
147
|
+
return mediaStateKey.getState(view.state);
|
|
148
|
+
}, [view.state]);
|
|
149
|
+
const mediaClientConfig = mediaPluginState === null || mediaPluginState === void 0 ? void 0 : mediaPluginState.mediaClientConfig;
|
|
150
|
+
const handleMediaGroupUpdate = mediaPluginState === null || mediaPluginState === void 0 ? void 0 : mediaPluginState.handleMediaGroupUpdate;
|
|
151
|
+
const [viewMediaClientConfig, setViewMediaClientConfig] = useState(undefined);
|
|
152
|
+
const nodeSize = mediaGroupNode.nodeSize;
|
|
153
|
+
const mediaNodesWithOffsets = useMemo(() => {
|
|
154
|
+
const result = [];
|
|
155
|
+
mediaGroupNode.forEach((item, childOffset) => {
|
|
156
|
+
result.push({
|
|
157
|
+
node: item,
|
|
158
|
+
offset: childOffset
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
return result;
|
|
162
|
+
}, [mediaGroupNode]);
|
|
163
|
+
const previousMediaNodesWithOffsets = usePreviousState(mediaNodesWithOffsets);
|
|
164
|
+
const handleMediaNodeRemoval = useMemo(() => {
|
|
165
|
+
return disabled || !mediaPluginState ? noop : mediaPluginState.handleMediaNodeRemoval;
|
|
166
|
+
}, [disabled, mediaPluginState]);
|
|
167
|
+
const setMediaGroupNodeSelection = useCallback(pos => {
|
|
168
|
+
setNodeSelection(view, pos);
|
|
169
|
+
}, [view]);
|
|
170
|
+
const isMediaItemSelected = useMemo(() => {
|
|
171
|
+
return isNodeSelected({
|
|
172
|
+
anchorPos,
|
|
173
|
+
headPos,
|
|
174
|
+
nodeSize
|
|
175
|
+
});
|
|
176
|
+
}, [anchorPos, headPos, nodeSize]);
|
|
177
|
+
const filmstripItem = useMemo(() => {
|
|
178
|
+
return prepareFilmstripItem({
|
|
179
|
+
allowLazyLoading,
|
|
180
|
+
enableDownloadButton,
|
|
181
|
+
handleMediaNodeRemoval,
|
|
182
|
+
getPos,
|
|
183
|
+
intl,
|
|
184
|
+
isMediaItemSelected,
|
|
185
|
+
setMediaGroupNodeSelection,
|
|
186
|
+
featureFlags
|
|
187
|
+
});
|
|
188
|
+
}, [allowLazyLoading, enableDownloadButton, handleMediaNodeRemoval, getPos, intl, isMediaItemSelected, setMediaGroupNodeSelection, featureFlags]);
|
|
189
|
+
const items = useMemo(() => {
|
|
190
|
+
return mediaNodesWithOffsets.map(({
|
|
191
|
+
node,
|
|
192
|
+
offset
|
|
193
|
+
}) => {
|
|
194
|
+
return filmstripItem(node, offset);
|
|
195
|
+
});
|
|
196
|
+
}, [mediaNodesWithOffsets, filmstripItem]);
|
|
197
|
+
useEffect(() => {
|
|
198
|
+
setViewMediaClientConfig(mediaClientConfig);
|
|
199
|
+
}, [mediaClientConfig]);
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
mediaNodesWithOffsets.forEach(({
|
|
202
|
+
node,
|
|
203
|
+
offset
|
|
204
|
+
}) => {
|
|
205
|
+
const mediaNodeUpdater = createMediaNodeUpdater({
|
|
206
|
+
view,
|
|
207
|
+
mediaProvider,
|
|
208
|
+
contextIdentifierProvider,
|
|
209
|
+
node,
|
|
210
|
+
isMediaSingle: false
|
|
211
|
+
});
|
|
212
|
+
const updateAttrs = isCopyPasteEnabled || isCopyPasteEnabled === undefined;
|
|
213
|
+
runMediaNodeUpdate({
|
|
214
|
+
mediaNodeUpdater,
|
|
215
|
+
node,
|
|
216
|
+
updateAttrs,
|
|
217
|
+
getPos: () => {
|
|
218
|
+
const pos = getPos();
|
|
219
|
+
if (typeof pos !== 'number') {
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
return pos + offset + 1;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
}, [view, contextIdentifierProvider, getPos, mediaProvider, mediaNodesWithOffsets, isCopyPasteEnabled]);
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
if (!handleMediaGroupUpdate || !previousMediaNodesWithOffsets) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const old = previousMediaNodesWithOffsets.map(({
|
|
232
|
+
node
|
|
233
|
+
}) => node);
|
|
234
|
+
const next = mediaNodesWithOffsets.map(({
|
|
235
|
+
node
|
|
236
|
+
}) => node);
|
|
237
|
+
handleMediaGroupUpdate(old, next);
|
|
238
|
+
return () => {
|
|
239
|
+
handleMediaGroupUpdate(next, []);
|
|
240
|
+
};
|
|
241
|
+
}, [handleMediaGroupUpdate, mediaNodesWithOffsets, previousMediaNodesWithOffsets]);
|
|
242
|
+
return /*#__PURE__*/React.createElement(Filmstrip, {
|
|
243
|
+
items: items,
|
|
244
|
+
mediaClientConfig: viewMediaClientConfig,
|
|
245
|
+
featureFlags: featureFlags,
|
|
246
|
+
shouldOpenMediaViewer: editorViewMode
|
|
247
|
+
});
|
|
248
|
+
}));
|
|
249
|
+
MediaGroupNext.displayName = 'MediaGroup';
|
|
@@ -424,8 +424,7 @@ const hasPrivateAttrsChanged = (currentAttrs, newAttrs) => {
|
|
|
424
424
|
};
|
|
425
425
|
export const createMediaNodeUpdater = props => {
|
|
426
426
|
const updaterProps = {
|
|
427
|
-
...props
|
|
428
|
-
isMediaSingle: true
|
|
427
|
+
...props
|
|
429
428
|
};
|
|
430
429
|
return new MediaNodeUpdater(updaterProps);
|
|
431
430
|
};
|
package/dist/es2019/plugin.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
3
3
|
import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
|
|
4
4
|
import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages';
|
|
@@ -28,6 +28,7 @@ import { floatingToolbar } from './toolbar';
|
|
|
28
28
|
import { MediaPickerComponents } from './ui/MediaPicker';
|
|
29
29
|
import { RenderMediaViewer } from './ui/MediaViewer/PortalWrapper';
|
|
30
30
|
import ToolbarMedia from './ui/ToolbarMedia';
|
|
31
|
+
import { createMediaIdentifierArray, extractMediaNodes } from './utils/media-common';
|
|
31
32
|
import { insertMediaAsMediaSingle } from './utils/media-single';
|
|
32
33
|
const MediaPickerFunctionalComponent = ({
|
|
33
34
|
api,
|
|
@@ -48,12 +49,24 @@ const MediaPickerFunctionalComponent = ({
|
|
|
48
49
|
});
|
|
49
50
|
};
|
|
50
51
|
const MediaViewerFunctionalComponent = ({
|
|
51
|
-
api
|
|
52
|
+
api,
|
|
53
|
+
editorView
|
|
52
54
|
}) => {
|
|
53
55
|
const {
|
|
54
56
|
mediaState
|
|
55
57
|
} = useSharedPluginState(api, ['media']);
|
|
56
58
|
|
|
59
|
+
// Only traverse document once when media viewer is visible, media viewer items will not update
|
|
60
|
+
// when document changes are made while media viewer is open
|
|
61
|
+
|
|
62
|
+
const mediaItems = useMemo(() => {
|
|
63
|
+
if (mediaState !== null && mediaState !== void 0 && mediaState.isMediaViewerVisible && fg('platform_editor_media_interaction_improvements')) {
|
|
64
|
+
const mediaNodes = extractMediaNodes(editorView.state.doc);
|
|
65
|
+
return createMediaIdentifierArray(mediaNodes);
|
|
66
|
+
}
|
|
67
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- only update mediaItems once when media viewer is visible
|
|
68
|
+
}, [mediaState === null || mediaState === void 0 ? void 0 : mediaState.isMediaViewerVisible]);
|
|
69
|
+
|
|
57
70
|
// Viewer does not have required attributes to render the media viewer
|
|
58
71
|
if (!(mediaState !== null && mediaState !== void 0 && mediaState.isMediaViewerVisible) || !(mediaState !== null && mediaState !== void 0 && mediaState.mediaViewerSelectedMedia) || !(mediaState !== null && mediaState !== void 0 && mediaState.mediaClientConfig)) {
|
|
59
72
|
return null;
|
|
@@ -65,7 +78,8 @@ const MediaViewerFunctionalComponent = ({
|
|
|
65
78
|
return /*#__PURE__*/React.createElement(RenderMediaViewer, {
|
|
66
79
|
mediaClientConfig: mediaState === null || mediaState === void 0 ? void 0 : mediaState.mediaClientConfig,
|
|
67
80
|
onClose: handleOnClose,
|
|
68
|
-
selectedNodeAttrs: mediaState.mediaViewerSelectedMedia
|
|
81
|
+
selectedNodeAttrs: mediaState.mediaViewerSelectedMedia,
|
|
82
|
+
items: fg('platform_editor_media_interaction_improvements') ? mediaItems : undefined
|
|
69
83
|
});
|
|
70
84
|
};
|
|
71
85
|
export const mediaPlugin = ({
|
|
@@ -260,7 +274,8 @@ export const mediaPlugin = ({
|
|
|
260
274
|
appearance
|
|
261
275
|
}) {
|
|
262
276
|
return /*#__PURE__*/React.createElement(React.Fragment, null, fg('platform_editor_media_previewer_bugfix') && /*#__PURE__*/React.createElement(MediaViewerFunctionalComponent, {
|
|
263
|
-
api: api
|
|
277
|
+
api: api,
|
|
278
|
+
editorView: editorView
|
|
264
279
|
}), /*#__PURE__*/React.createElement(MediaPickerFunctionalComponent, {
|
|
265
280
|
editorDomElement: editorView.dom,
|
|
266
281
|
appearance: appearance,
|
|
@@ -673,11 +673,12 @@ export const createPlugin = (_schema, options, getIntl, pluginInjectionApi, disp
|
|
|
673
673
|
switch (meta === null || meta === void 0 ? void 0 : meta.type) {
|
|
674
674
|
case ACTIONS.SHOW_MEDIA_VIEWER:
|
|
675
675
|
pluginState.mediaViewerSelectedMedia = meta.mediaViewerSelectedMedia;
|
|
676
|
-
pluginState.isMediaViewerVisible =
|
|
676
|
+
pluginState.isMediaViewerVisible = meta.isMediaViewerVisible;
|
|
677
677
|
nextPluginState = nextPluginState.clone();
|
|
678
678
|
break;
|
|
679
679
|
case ACTIONS.HIDE_MEDIA_VIEWER:
|
|
680
680
|
pluginState.mediaViewerSelectedMedia = undefined;
|
|
681
|
+
pluginState.isMediaViewerVisible = meta.isMediaViewerVisible;
|
|
681
682
|
nextPluginState = nextPluginState.clone();
|
|
682
683
|
break;
|
|
683
684
|
}
|
|
@@ -24,14 +24,15 @@ const getIdentifier = attrs => {
|
|
|
24
24
|
export const RenderMediaViewer = ({
|
|
25
25
|
mediaClientConfig,
|
|
26
26
|
onClose,
|
|
27
|
-
selectedNodeAttrs
|
|
27
|
+
selectedNodeAttrs,
|
|
28
|
+
items = []
|
|
28
29
|
}) => {
|
|
29
30
|
if (editorExperiment('add-media-from-url', true)) {
|
|
30
31
|
const identifier = getIdentifier(selectedNodeAttrs);
|
|
31
32
|
const collectionName = isExternalMedia(selectedNodeAttrs) ? '' : selectedNodeAttrs.collection;
|
|
32
33
|
return /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(MediaViewer, {
|
|
33
34
|
collectionName: collectionName,
|
|
34
|
-
items:
|
|
35
|
+
items: items,
|
|
35
36
|
mediaClientConfig: mediaClientConfig,
|
|
36
37
|
selectedItem: identifier,
|
|
37
38
|
onClose: onClose
|
|
@@ -3,8 +3,10 @@ import { createNewParagraphBelow, createParagraphNear } from '@atlaskit/editor-c
|
|
|
3
3
|
import { deleteSelection, splitBlock } from '@atlaskit/editor-prosemirror/commands';
|
|
4
4
|
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
5
5
|
import { findPositionOfNodeBefore } from '@atlaskit/editor-prosemirror/utils';
|
|
6
|
-
import { isMediaBlobUrl } from '@atlaskit/media-client';
|
|
6
|
+
import { isExternalImageIdentifier, isMediaBlobUrl } from '@atlaskit/media-client';
|
|
7
7
|
import { getMediaPluginState } from '../pm-plugins/main';
|
|
8
|
+
import { isExternalMedia } from '../toolbar/utils';
|
|
9
|
+
import { isVideo } from './media-single';
|
|
8
10
|
const isTemporary = id => {
|
|
9
11
|
return id.indexOf('temporary:') === 0;
|
|
10
12
|
};
|
|
@@ -230,4 +232,51 @@ export const getMediaFromSupportedMediaNodesFromSelection = state => {
|
|
|
230
232
|
default:
|
|
231
233
|
return null;
|
|
232
234
|
}
|
|
235
|
+
};
|
|
236
|
+
export const getIdentifier = attrs => {
|
|
237
|
+
if (isExternalMedia(attrs)) {
|
|
238
|
+
return {
|
|
239
|
+
mediaItemType: 'external-image',
|
|
240
|
+
dataURI: attrs.url
|
|
241
|
+
};
|
|
242
|
+
} else {
|
|
243
|
+
const {
|
|
244
|
+
id,
|
|
245
|
+
collection = ''
|
|
246
|
+
} = attrs;
|
|
247
|
+
return {
|
|
248
|
+
id,
|
|
249
|
+
mediaItemType: 'file',
|
|
250
|
+
collectionName: collection
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
export const extractMediaNodes = doc => {
|
|
255
|
+
const mediaNodes = [];
|
|
256
|
+
doc.descendants(node => {
|
|
257
|
+
if (node.type.name === 'media' || node.type.name === 'mediaInline') {
|
|
258
|
+
mediaNodes.push(node);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
return mediaNodes;
|
|
262
|
+
};
|
|
263
|
+
export const createMediaIdentifierArray = mediaNodes => {
|
|
264
|
+
const mediaIdentifierMap = new Map();
|
|
265
|
+
mediaNodes.forEach(item => {
|
|
266
|
+
const attrs = item.attrs;
|
|
267
|
+
if (!attrs) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (isVideo(attrs.__fileMimeType)) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const identifier = getIdentifier(attrs);
|
|
274
|
+
|
|
275
|
+
// Add only if not already processed
|
|
276
|
+
const idKey = isExternalImageIdentifier(identifier) ? identifier.dataURI : identifier.id;
|
|
277
|
+
if (!mediaIdentifierMap.has(idKey)) {
|
|
278
|
+
mediaIdentifierMap.set(idKey, identifier);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
return [...mediaIdentifierMap.values()];
|
|
233
282
|
};
|
|
@@ -21,8 +21,10 @@ import { isNodeSelectedOrInRange, SelectedState, setNodeSelection } from '@atlas
|
|
|
21
21
|
import EditorCloseIcon from '@atlaskit/icon/glyph/editor/close';
|
|
22
22
|
import { getMediaFeatureFlag } from '@atlaskit/media-common';
|
|
23
23
|
import { Filmstrip } from '@atlaskit/media-filmstrip';
|
|
24
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
24
25
|
import { useMediaProvider } from '../hooks/useMediaProvider';
|
|
25
26
|
import { stateKey as mediaStateKey } from '../pm-plugins/plugin-key';
|
|
27
|
+
import { MediaGroupNext } from './mediaGroupNext';
|
|
26
28
|
import { MediaNodeUpdater } from './mediaNodeUpdater';
|
|
27
29
|
var isMediaGroupSelectedFromProps = function isMediaGroupSelectedFromProps(props) {
|
|
28
30
|
/**
|
|
@@ -339,6 +341,23 @@ var MediaGroupNodeView = /*#__PURE__*/function (_ReactNodeView) {
|
|
|
339
341
|
if (!mediaProvider) {
|
|
340
342
|
return null;
|
|
341
343
|
}
|
|
344
|
+
if (fg('platform_editor_react18_phase2__media_single')) {
|
|
345
|
+
return /*#__PURE__*/React.createElement(MediaGroupNext, {
|
|
346
|
+
node: _this3.node,
|
|
347
|
+
getPos: getPos,
|
|
348
|
+
view: _this3.view,
|
|
349
|
+
forwardRef: forwardRef,
|
|
350
|
+
disabled: (editorDisabledPlugin || {}).editorDisabled,
|
|
351
|
+
allowLazyLoading: mediaOptions.allowLazyLoading,
|
|
352
|
+
mediaProvider: mediaProvider,
|
|
353
|
+
contextIdentifierProvider: contextIdentifierProvider,
|
|
354
|
+
isCopyPasteEnabled: mediaOptions.isCopyPasteEnabled,
|
|
355
|
+
anchorPos: _this3.view.state.selection.$anchor.pos,
|
|
356
|
+
headPos: _this3.view.state.selection.$head.pos,
|
|
357
|
+
mediaOptions: mediaOptions,
|
|
358
|
+
editorViewMode: (editorViewModePlugin === null || editorViewModePlugin === void 0 ? void 0 : editorViewModePlugin.mode) === 'view'
|
|
359
|
+
});
|
|
360
|
+
}
|
|
342
361
|
return /*#__PURE__*/React.createElement(IntlMediaGroup, {
|
|
343
362
|
node: _this3.node,
|
|
344
363
|
getPos: getPos,
|