@atlaskit/editor-plugin-media 0.2.0 → 0.3.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 +17 -0
- package/dist/cjs/commands/captions.js +59 -0
- package/dist/cjs/commands/helpers.js +127 -0
- package/dist/cjs/commands/index.js +24 -0
- package/dist/cjs/commands/linking.js +181 -0
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/media-plugin-options.js +5 -0
- package/dist/cjs/next-plugin-type.js +5 -0
- package/dist/cjs/nodeviews/mediaGroup.js +376 -0
- package/dist/cjs/nodeviews/mediaInline.js +288 -0
- package/dist/cjs/nodeviews/mediaNodeUpdater.js +739 -0
- package/dist/cjs/nodeviews/mediaNodeView/index.js +177 -0
- package/dist/cjs/nodeviews/mediaNodeView/media.js +242 -0
- package/dist/cjs/nodeviews/mediaSingle.js +629 -0
- package/dist/cjs/nodeviews/messages.js +14 -0
- package/dist/cjs/nodeviews/styles.js +46 -0
- package/dist/cjs/nodeviews/types.js +5 -0
- package/dist/cjs/picker-facade.js +192 -0
- package/dist/cjs/plugin.js +293 -0
- package/dist/cjs/pm-plugins/alt-text/actions.js +5 -0
- package/dist/cjs/pm-plugins/alt-text/commands.js +59 -0
- package/dist/cjs/pm-plugins/alt-text/index.js +36 -0
- package/dist/cjs/pm-plugins/alt-text/keymap.js +15 -0
- package/dist/cjs/pm-plugins/alt-text/messages.js +44 -0
- package/dist/cjs/pm-plugins/alt-text/reducer.js +32 -0
- package/dist/cjs/pm-plugins/alt-text/types.js +5 -0
- package/dist/cjs/pm-plugins/alt-text/ui/AltTextEdit.js +209 -0
- package/dist/cjs/pm-plugins/keymap-media-single.js +163 -0
- package/dist/cjs/pm-plugins/keymap.js +88 -0
- package/dist/cjs/pm-plugins/linking/actions.js +13 -0
- package/dist/cjs/pm-plugins/linking/index.js +65 -0
- package/dist/cjs/pm-plugins/linking/keymap.js +14 -0
- package/dist/cjs/pm-plugins/linking/reducer.js +43 -0
- package/dist/cjs/pm-plugins/linking/types.js +5 -0
- package/dist/cjs/pm-plugins/main.js +813 -0
- package/dist/cjs/pm-plugins/media-editor-plugin-factory.js +8 -0
- package/dist/cjs/pm-plugins/mediaTaskManager.js +101 -0
- package/dist/cjs/pm-plugins/plugin-key.js +8 -0
- package/dist/cjs/pm-plugins/types.js +5 -0
- package/dist/cjs/toolbar/alt-text.js +80 -0
- package/dist/cjs/toolbar/commands.js +236 -0
- package/dist/cjs/toolbar/filePreviewItem.js +66 -0
- package/dist/cjs/toolbar/imageBorder.js +20 -0
- package/dist/cjs/toolbar/index.js +523 -0
- package/dist/cjs/toolbar/linking-toolbar-appearance.js +100 -0
- package/dist/cjs/toolbar/linking.js +96 -0
- package/dist/cjs/toolbar/utils.js +110 -0
- package/dist/cjs/ui/CaptionPlaceholder/index.js +27 -0
- package/dist/cjs/ui/CaptionPlaceholder/messages.js +14 -0
- package/dist/cjs/ui/ImageBorder/index.js +226 -0
- package/dist/cjs/ui/ImageBorder/messages.js +49 -0
- package/dist/cjs/ui/ImageBorder/styles.js +52 -0
- package/dist/cjs/ui/Media/DropPlaceholder.js +38 -0
- package/dist/cjs/ui/Media/drop-placeholder-messages.js +14 -0
- package/dist/cjs/ui/MediaLinkingToolbar.js +196 -0
- package/dist/cjs/ui/MediaPicker/BrowserWrapper.js +40 -0
- package/dist/cjs/ui/MediaPicker/ClipboardWrapper.js +39 -0
- package/dist/cjs/ui/MediaPicker/DropzoneWrapper.js +51 -0
- package/dist/cjs/ui/MediaPicker/PickerFacadeProvider.js +151 -0
- package/dist/cjs/ui/MediaPicker/index.js +103 -0
- package/dist/cjs/ui/PixelEntry/constants.js +7 -0
- package/dist/cjs/ui/PixelEntry/index.js +185 -0
- package/dist/cjs/ui/PixelEntry/messages.js +54 -0
- package/dist/cjs/ui/PixelEntry/styles.js +19 -0
- package/dist/cjs/ui/PixelEntry/types.js +5 -0
- package/dist/cjs/ui/ResizableMediaSingle/ResizableMediaMigrationNotification.js +16 -0
- package/dist/cjs/ui/ResizableMediaSingle/ResizableMediaSingleNext.js +541 -0
- package/dist/cjs/ui/ResizableMediaSingle/index.js +422 -0
- package/dist/cjs/ui/ResizableMediaSingle/styled.js +14 -0
- package/dist/cjs/ui/ResizableMediaSingle/styles.js +17 -0
- package/dist/cjs/ui/ResizableMediaSingle/types.js +5 -0
- package/dist/cjs/ui/ToolbarMedia/index.js +42 -0
- package/dist/cjs/ui/ToolbarMedia/toolbar-media-messages.js +14 -0
- package/dist/cjs/ui/media-linking-toolbar-messages.js +14 -0
- package/dist/cjs/utils/analytics.js +53 -0
- package/dist/cjs/utils/check-media-type.js +56 -0
- package/dist/cjs/utils/current-media-node.js +41 -0
- package/dist/cjs/utils/is-image.js +9 -0
- package/dist/cjs/utils/media-common.js +181 -0
- package/dist/cjs/utils/media-files.js +297 -0
- package/dist/cjs/utils/media-single.js +181 -0
- package/dist/es2019/commands/captions.js +47 -0
- package/dist/es2019/commands/helpers.js +113 -0
- package/dist/es2019/commands/index.js +1 -0
- package/dist/es2019/commands/linking.js +169 -0
- package/dist/es2019/index.js +1 -1
- package/dist/es2019/media-plugin-options.js +1 -0
- package/dist/es2019/next-plugin-type.js +1 -0
- package/dist/es2019/nodeviews/mediaGroup.js +314 -0
- package/dist/es2019/nodeviews/mediaInline.js +201 -0
- package/dist/es2019/nodeviews/mediaNodeUpdater.js +384 -0
- package/dist/es2019/nodeviews/mediaNodeView/index.js +149 -0
- package/dist/es2019/nodeviews/mediaNodeView/media.js +182 -0
- package/dist/es2019/nodeviews/mediaSingle.js +511 -0
- package/dist/es2019/nodeviews/messages.js +8 -0
- package/dist/es2019/nodeviews/styles.js +46 -0
- package/dist/es2019/nodeviews/types.js +1 -0
- package/dist/es2019/picker-facade.js +146 -0
- package/dist/es2019/plugin.js +284 -0
- package/dist/es2019/pm-plugins/alt-text/actions.js +1 -0
- package/dist/es2019/pm-plugins/alt-text/commands.js +42 -0
- package/dist/es2019/pm-plugins/alt-text/index.js +33 -0
- package/dist/es2019/pm-plugins/alt-text/keymap.js +9 -0
- package/dist/es2019/pm-plugins/alt-text/messages.js +38 -0
- package/dist/es2019/pm-plugins/alt-text/reducer.js +26 -0
- package/dist/es2019/pm-plugins/alt-text/types.js +1 -0
- package/dist/es2019/pm-plugins/alt-text/ui/AltTextEdit.js +228 -0
- package/dist/es2019/pm-plugins/keymap-media-single.js +172 -0
- package/dist/es2019/pm-plugins/keymap.js +84 -0
- package/dist/es2019/pm-plugins/linking/actions.js +7 -0
- package/dist/es2019/pm-plugins/linking/index.js +56 -0
- package/dist/es2019/pm-plugins/linking/keymap.js +8 -0
- package/dist/es2019/pm-plugins/linking/reducer.js +37 -0
- package/dist/es2019/pm-plugins/linking/types.js +1 -0
- package/dist/es2019/pm-plugins/main.js +695 -0
- package/dist/es2019/pm-plugins/media-editor-plugin-factory.js +2 -0
- package/dist/es2019/pm-plugins/mediaTaskManager.js +64 -0
- package/dist/es2019/pm-plugins/plugin-key.js +2 -0
- package/dist/es2019/pm-plugins/types.js +1 -0
- package/dist/es2019/toolbar/alt-text.js +72 -0
- package/dist/es2019/toolbar/commands.js +212 -0
- package/dist/es2019/toolbar/filePreviewItem.js +54 -0
- package/dist/es2019/toolbar/imageBorder.js +15 -0
- package/dist/es2019/toolbar/index.js +538 -0
- package/dist/es2019/toolbar/linking-toolbar-appearance.js +90 -0
- package/dist/es2019/toolbar/linking.js +98 -0
- package/dist/es2019/toolbar/utils.js +86 -0
- package/dist/es2019/ui/CaptionPlaceholder/index.js +25 -0
- package/dist/es2019/ui/CaptionPlaceholder/messages.js +8 -0
- package/dist/es2019/ui/ImageBorder/index.js +213 -0
- package/dist/es2019/ui/ImageBorder/messages.js +43 -0
- package/dist/es2019/ui/ImageBorder/styles.js +126 -0
- package/dist/es2019/ui/Media/DropPlaceholder.js +47 -0
- package/dist/es2019/ui/Media/drop-placeholder-messages.js +8 -0
- package/dist/es2019/ui/MediaLinkingToolbar.js +190 -0
- package/dist/es2019/ui/MediaPicker/BrowserWrapper.js +31 -0
- package/dist/es2019/ui/MediaPicker/ClipboardWrapper.js +32 -0
- package/dist/es2019/ui/MediaPicker/DropzoneWrapper.js +42 -0
- package/dist/es2019/ui/MediaPicker/PickerFacadeProvider.js +85 -0
- package/dist/es2019/ui/MediaPicker/index.js +82 -0
- package/dist/es2019/ui/PixelEntry/constants.js +1 -0
- package/dist/es2019/ui/PixelEntry/index.js +170 -0
- package/dist/es2019/ui/PixelEntry/messages.js +48 -0
- package/dist/es2019/ui/PixelEntry/styles.js +51 -0
- package/dist/es2019/ui/PixelEntry/types.js +1 -0
- package/dist/es2019/ui/ResizableMediaSingle/ResizableMediaMigrationNotification.js +9 -0
- package/dist/es2019/ui/ResizableMediaSingle/ResizableMediaSingleNext.js +454 -0
- package/dist/es2019/ui/ResizableMediaSingle/index.js +344 -0
- package/dist/es2019/ui/ResizableMediaSingle/styled.js +9 -0
- package/dist/es2019/ui/ResizableMediaSingle/styles.js +14 -0
- package/dist/es2019/ui/ResizableMediaSingle/types.js +1 -0
- package/dist/es2019/ui/ToolbarMedia/index.js +37 -0
- package/dist/es2019/ui/ToolbarMedia/toolbar-media-messages.js +8 -0
- package/dist/es2019/ui/media-linking-toolbar-messages.js +8 -0
- package/dist/es2019/utils/analytics.js +51 -0
- package/dist/es2019/utils/check-media-type.js +19 -0
- package/dist/es2019/utils/current-media-node.js +35 -0
- package/dist/es2019/utils/is-image.js +3 -0
- package/dist/es2019/utils/media-common.js +189 -0
- package/dist/es2019/utils/media-files.js +321 -0
- package/dist/es2019/utils/media-single.js +176 -0
- package/dist/esm/commands/captions.js +53 -0
- package/dist/esm/commands/helpers.js +120 -0
- package/dist/esm/commands/index.js +1 -0
- package/dist/esm/commands/linking.js +174 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/media-plugin-options.js +1 -0
- package/dist/esm/next-plugin-type.js +1 -0
- package/dist/esm/nodeviews/mediaGroup.js +369 -0
- package/dist/esm/nodeviews/mediaInline.js +278 -0
- package/dist/esm/nodeviews/mediaNodeUpdater.js +732 -0
- package/dist/esm/nodeviews/mediaNodeView/index.js +170 -0
- package/dist/esm/nodeviews/mediaNodeView/media.js +233 -0
- package/dist/esm/nodeviews/mediaSingle.js +622 -0
- package/dist/esm/nodeviews/messages.js +8 -0
- package/dist/esm/nodeviews/styles.js +39 -0
- package/dist/esm/nodeviews/types.js +1 -0
- package/dist/esm/picker-facade.js +186 -0
- package/dist/esm/plugin.js +282 -0
- package/dist/esm/pm-plugins/alt-text/actions.js +1 -0
- package/dist/esm/pm-plugins/alt-text/commands.js +52 -0
- package/dist/esm/pm-plugins/alt-text/index.js +31 -0
- package/dist/esm/pm-plugins/alt-text/keymap.js +9 -0
- package/dist/esm/pm-plugins/alt-text/messages.js +38 -0
- package/dist/esm/pm-plugins/alt-text/reducer.js +25 -0
- package/dist/esm/pm-plugins/alt-text/types.js +1 -0
- package/dist/esm/pm-plugins/alt-text/ui/AltTextEdit.js +206 -0
- package/dist/esm/pm-plugins/keymap-media-single.js +158 -0
- package/dist/esm/pm-plugins/keymap.js +81 -0
- package/dist/esm/pm-plugins/linking/actions.js +7 -0
- package/dist/esm/pm-plugins/linking/index.js +59 -0
- package/dist/esm/pm-plugins/linking/keymap.js +8 -0
- package/dist/esm/pm-plugins/linking/reducer.js +36 -0
- package/dist/esm/pm-plugins/linking/types.js +1 -0
- package/dist/esm/pm-plugins/main.js +798 -0
- package/dist/esm/pm-plugins/media-editor-plugin-factory.js +2 -0
- package/dist/esm/pm-plugins/mediaTaskManager.js +94 -0
- package/dist/esm/pm-plugins/plugin-key.js +2 -0
- package/dist/esm/pm-plugins/types.js +1 -0
- package/dist/esm/toolbar/alt-text.js +70 -0
- package/dist/esm/toolbar/commands.js +229 -0
- package/dist/esm/toolbar/filePreviewItem.js +56 -0
- package/dist/esm/toolbar/imageBorder.js +14 -0
- package/dist/esm/toolbar/index.js +513 -0
- package/dist/esm/toolbar/linking-toolbar-appearance.js +91 -0
- package/dist/esm/toolbar/linking.js +88 -0
- package/dist/esm/toolbar/utils.js +103 -0
- package/dist/esm/ui/CaptionPlaceholder/index.js +20 -0
- package/dist/esm/ui/CaptionPlaceholder/messages.js +8 -0
- package/dist/esm/ui/ImageBorder/index.js +218 -0
- package/dist/esm/ui/ImageBorder/messages.js +43 -0
- package/dist/esm/ui/ImageBorder/styles.js +42 -0
- package/dist/esm/ui/Media/DropPlaceholder.js +31 -0
- package/dist/esm/ui/Media/drop-placeholder-messages.js +8 -0
- package/dist/esm/ui/MediaLinkingToolbar.js +188 -0
- package/dist/esm/ui/MediaPicker/BrowserWrapper.js +33 -0
- package/dist/esm/ui/MediaPicker/ClipboardWrapper.js +32 -0
- package/dist/esm/ui/MediaPicker/DropzoneWrapper.js +44 -0
- package/dist/esm/ui/MediaPicker/PickerFacadeProvider.js +145 -0
- package/dist/esm/ui/MediaPicker/index.js +96 -0
- package/dist/esm/ui/PixelEntry/constants.js +1 -0
- package/dist/esm/ui/PixelEntry/index.js +174 -0
- package/dist/esm/ui/PixelEntry/messages.js +48 -0
- package/dist/esm/ui/PixelEntry/styles.js +12 -0
- package/dist/esm/ui/PixelEntry/types.js +1 -0
- package/dist/esm/ui/ResizableMediaSingle/ResizableMediaMigrationNotification.js +9 -0
- package/dist/esm/ui/ResizableMediaSingle/ResizableMediaSingleNext.js +535 -0
- package/dist/esm/ui/ResizableMediaSingle/index.js +417 -0
- package/dist/esm/ui/ResizableMediaSingle/styled.js +7 -0
- package/dist/esm/ui/ResizableMediaSingle/styles.js +7 -0
- package/dist/esm/ui/ResizableMediaSingle/types.js +1 -0
- package/dist/esm/ui/ToolbarMedia/index.js +35 -0
- package/dist/esm/ui/ToolbarMedia/toolbar-media-messages.js +8 -0
- package/dist/esm/ui/media-linking-toolbar-messages.js +8 -0
- package/dist/esm/utils/analytics.js +47 -0
- package/dist/esm/utils/check-media-type.js +49 -0
- package/dist/esm/utils/current-media-node.js +35 -0
- package/dist/esm/utils/is-image.js +3 -0
- package/dist/esm/utils/media-common.js +175 -0
- package/dist/esm/utils/media-files.js +291 -0
- package/dist/esm/utils/media-single.js +172 -0
- package/dist/types/commands/captions.d.ts +5 -0
- package/dist/types/commands/helpers.d.ts +15 -0
- package/dist/types/commands/index.d.ts +1 -0
- package/dist/types/commands/linking.d.ts +9 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/media-plugin-options.d.ts +17 -0
- package/dist/types/next-plugin-type.d.ts +33 -0
- package/dist/types/nodeviews/__mocks__/mediaNodeUpdater.d.ts +24 -0
- package/dist/types/nodeviews/mediaGroup.d.ts +33 -0
- package/dist/types/nodeviews/mediaInline.d.ts +50 -0
- package/dist/types/nodeviews/mediaNodeUpdater.d.ts +45 -0
- package/dist/types/nodeviews/mediaNodeView/index.d.ts +28 -0
- package/dist/types/nodeviews/mediaNodeView/media.d.ts +44 -0
- package/dist/types/nodeviews/mediaSingle.d.ts +62 -0
- package/dist/types/nodeviews/messages.d.ts +7 -0
- package/dist/types/nodeviews/styles.d.ts +16 -0
- package/dist/types/nodeviews/types.d.ts +42 -0
- package/dist/types/picker-facade.d.ts +44 -0
- package/dist/types/plugin.d.ts +7 -0
- package/dist/types/pm-plugins/alt-text/actions.d.ts +10 -0
- package/dist/types/pm-plugins/alt-text/commands.d.ts +4 -0
- package/dist/types/pm-plugins/alt-text/index.d.ts +7 -0
- package/dist/types/pm-plugins/alt-text/keymap.d.ts +4 -0
- package/dist/types/pm-plugins/alt-text/messages.d.ts +37 -0
- package/dist/types/pm-plugins/alt-text/reducer.d.ts +4 -0
- package/dist/types/pm-plugins/alt-text/types.d.ts +3 -0
- package/dist/types/pm-plugins/alt-text/ui/AltTextEdit.d.ts +41 -0
- package/dist/types/pm-plugins/keymap-media-single.d.ts +3 -0
- package/dist/types/pm-plugins/keymap.d.ts +6 -0
- package/dist/types/pm-plugins/linking/actions.d.ts +20 -0
- package/dist/types/pm-plugins/linking/index.d.ts +10 -0
- package/dist/types/pm-plugins/linking/keymap.d.ts +3 -0
- package/dist/types/pm-plugins/linking/reducer.d.ts +4 -0
- package/dist/types/pm-plugins/linking/types.d.ts +12 -0
- package/dist/types/pm-plugins/main.d.ts +120 -0
- package/dist/types/pm-plugins/media-editor-plugin-factory.d.ts +3 -0
- package/dist/types/pm-plugins/mediaTaskManager.d.ts +9 -0
- package/dist/types/pm-plugins/plugin-key.d.ts +3 -0
- package/dist/types/pm-plugins/types.d.ts +65 -0
- package/dist/types/toolbar/alt-text.d.ts +13 -0
- package/dist/types/toolbar/commands.d.ts +12 -0
- package/dist/types/toolbar/filePreviewItem.d.ts +9 -0
- package/dist/types/toolbar/imageBorder.d.ts +2 -0
- package/dist/types/toolbar/index.d.ts +6 -0
- package/dist/types/toolbar/linking-toolbar-appearance.d.ts +14 -0
- package/dist/types/toolbar/linking.d.ts +10 -0
- package/dist/types/toolbar/utils.d.ts +11 -0
- package/dist/types/types.d.ts +2 -1
- package/dist/types/ui/CaptionPlaceholder/index.d.ts +6 -0
- package/dist/types/ui/CaptionPlaceholder/messages.d.ts +7 -0
- package/dist/types/ui/ImageBorder/index.d.ts +11 -0
- package/dist/types/ui/ImageBorder/messages.d.ts +42 -0
- package/dist/types/ui/ImageBorder/styles.d.ts +15 -0
- package/dist/types/ui/Media/DropPlaceholder.d.ts +8 -0
- package/dist/types/ui/Media/drop-placeholder-messages.d.ts +7 -0
- package/dist/types/ui/MediaLinkingToolbar.d.ts +35 -0
- package/dist/types/ui/MediaPicker/BrowserWrapper.d.ts +11 -0
- package/dist/types/ui/MediaPicker/ClipboardWrapper.d.ts +10 -0
- package/dist/types/ui/MediaPicker/DropzoneWrapper.d.ts +13 -0
- package/dist/types/ui/MediaPicker/PickerFacadeProvider.d.ts +28 -0
- package/dist/types/ui/MediaPicker/index.d.ts +23 -0
- package/dist/types/ui/PixelEntry/constants.d.ts +1 -0
- package/dist/types/ui/PixelEntry/index.d.ts +8 -0
- package/dist/types/ui/PixelEntry/messages.d.ts +47 -0
- package/dist/types/ui/PixelEntry/styles.d.ts +8 -0
- package/dist/types/ui/PixelEntry/types.d.ts +58 -0
- package/dist/types/ui/ResizableMediaSingle/ResizableMediaMigrationNotification.d.ts +3 -0
- package/dist/types/ui/ResizableMediaSingle/ResizableMediaSingleNext.d.ts +59 -0
- package/dist/types/ui/ResizableMediaSingle/index.d.ts +45 -0
- package/dist/types/ui/ResizableMediaSingle/styled.d.ts +2 -0
- package/dist/types/ui/ResizableMediaSingle/styles.d.ts +1 -0
- package/dist/types/ui/ResizableMediaSingle/types.d.ts +27 -0
- package/dist/types/ui/ToolbarMedia/index.d.ts +13 -0
- package/dist/types/ui/ToolbarMedia/toolbar-media-messages.d.ts +7 -0
- package/dist/types/ui/media-linking-toolbar-messages.d.ts +7 -0
- package/dist/types/utils/analytics.d.ts +3 -0
- package/dist/types/utils/check-media-type.d.ts +4 -0
- package/dist/types/utils/current-media-node.d.ts +9 -0
- package/dist/types/utils/is-image.d.ts +1 -0
- package/dist/types/utils/media-common.d.ts +20 -0
- package/dist/types/utils/media-files.d.ts +30 -0
- package/dist/types/utils/media-single.d.ts +20 -0
- package/package.json +32 -20
- package/report.api.md +430 -0
- package/dist/types-ts4.5/index.d.ts +0 -1
- package/dist/types-ts4.5/types.d.ts +0 -118
- package/tmp/api-report-tmp.d.ts +0 -9
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { atTheBeginningOfBlock, atTheBeginningOfDoc, atTheEndOfBlock, endPositionOfParent, GapCursorSelection, startPositionOfParent } from '@atlaskit/editor-common/selection';
|
|
2
|
+
import { createNewParagraphBelow, createParagraphNear } from '@atlaskit/editor-common/utils';
|
|
3
|
+
import { deleteSelection, splitBlock } from '@atlaskit/editor-prosemirror/commands';
|
|
4
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
5
|
+
import { findPositionOfNodeBefore } from '@atlaskit/editor-prosemirror/utils';
|
|
6
|
+
import { isMediaBlobUrl } from '@atlaskit/media-client';
|
|
7
|
+
const isTemporary = id => {
|
|
8
|
+
return id.indexOf('temporary:') === 0;
|
|
9
|
+
};
|
|
10
|
+
export const isMediaBlobUrlFromAttrs = attrs => {
|
|
11
|
+
return !!(attrs && attrs.type === 'external' && isMediaBlobUrl(attrs.url));
|
|
12
|
+
};
|
|
13
|
+
export const posOfMediaGroupNearby = state => {
|
|
14
|
+
return posOfParentMediaGroup(state) || posOfFollowingMediaGroup(state) || posOfPrecedingMediaGroup(state) || posOfMediaGroupNextToGapCursor(state);
|
|
15
|
+
};
|
|
16
|
+
export const isSelectionNonMediaBlockNode = state => {
|
|
17
|
+
const {
|
|
18
|
+
node
|
|
19
|
+
} = state.selection;
|
|
20
|
+
return node && node.type !== state.schema.nodes.media && node.isBlock;
|
|
21
|
+
};
|
|
22
|
+
export const isSelectionMediaSingleNode = state => {
|
|
23
|
+
const {
|
|
24
|
+
node
|
|
25
|
+
} = state.selection;
|
|
26
|
+
return node && node.type === state.schema.nodes.mediaSingle;
|
|
27
|
+
};
|
|
28
|
+
export const posOfPrecedingMediaGroup = state => {
|
|
29
|
+
if (!atTheBeginningOfBlock(state)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
return posOfMediaGroupAbove(state, state.selection.$from);
|
|
33
|
+
};
|
|
34
|
+
const posOfMediaGroupNextToGapCursor = state => {
|
|
35
|
+
const {
|
|
36
|
+
selection
|
|
37
|
+
} = state;
|
|
38
|
+
if (selection instanceof GapCursorSelection) {
|
|
39
|
+
const $pos = state.selection.$from;
|
|
40
|
+
const mediaGroupType = state.schema.nodes.mediaGroup;
|
|
41
|
+
return posOfImmediatePrecedingMediaGroup($pos, mediaGroupType) || posOfImmediateFollowingMediaGroup($pos, mediaGroupType);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const posOfImmediatePrecedingMediaGroup = ($pos, mediaGroupType) => {
|
|
45
|
+
if ($pos.nodeBefore && $pos.nodeBefore.type === mediaGroupType) {
|
|
46
|
+
return $pos.pos - $pos.nodeBefore.nodeSize + 1;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const posOfImmediateFollowingMediaGroup = ($pos, mediaGroupType) => {
|
|
50
|
+
if ($pos.nodeAfter && $pos.nodeAfter.type === mediaGroupType) {
|
|
51
|
+
return $pos.pos + 1;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const posOfFollowingMediaGroup = state => {
|
|
55
|
+
if (!atTheEndOfBlock(state)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
return posOfMediaGroupBelow(state, state.selection.$to);
|
|
59
|
+
};
|
|
60
|
+
const posOfMediaGroupAbove = (state, $pos) => {
|
|
61
|
+
let adjacentPos;
|
|
62
|
+
let adjacentNode;
|
|
63
|
+
if (isSelectionNonMediaBlockNode(state)) {
|
|
64
|
+
adjacentPos = $pos.pos;
|
|
65
|
+
adjacentNode = $pos.nodeBefore;
|
|
66
|
+
} else {
|
|
67
|
+
adjacentPos = startPositionOfParent($pos) - 1;
|
|
68
|
+
adjacentNode = state.doc.resolve(adjacentPos).nodeBefore;
|
|
69
|
+
}
|
|
70
|
+
if (adjacentNode && adjacentNode.type === state.schema.nodes.mediaGroup) {
|
|
71
|
+
return adjacentPos - adjacentNode.nodeSize + 1;
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Determine whether the cursor is inside empty paragraph
|
|
78
|
+
* or the selection is the entire paragraph
|
|
79
|
+
*/
|
|
80
|
+
export const isInsidePotentialEmptyParagraph = state => {
|
|
81
|
+
const {
|
|
82
|
+
$from
|
|
83
|
+
} = state.selection;
|
|
84
|
+
return $from.parent.type === state.schema.nodes.paragraph && atTheBeginningOfBlock(state) && atTheEndOfBlock(state);
|
|
85
|
+
};
|
|
86
|
+
const posOfMediaGroupBelow = (state, $pos, prepend = true) => {
|
|
87
|
+
let adjacentPos;
|
|
88
|
+
let adjacentNode;
|
|
89
|
+
if (isSelectionNonMediaBlockNode(state)) {
|
|
90
|
+
adjacentPos = $pos.pos;
|
|
91
|
+
adjacentNode = $pos.nodeAfter;
|
|
92
|
+
} else {
|
|
93
|
+
adjacentPos = endPositionOfParent($pos);
|
|
94
|
+
adjacentNode = state.doc.nodeAt(adjacentPos);
|
|
95
|
+
}
|
|
96
|
+
if (adjacentNode && adjacentNode.type === state.schema.nodes.mediaGroup) {
|
|
97
|
+
return prepend ? adjacentPos + 1 : adjacentPos + adjacentNode.nodeSize - 1;
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
};
|
|
101
|
+
export const posOfParentMediaGroup = (state, $pos, prepend = false) => {
|
|
102
|
+
const {
|
|
103
|
+
$from
|
|
104
|
+
} = state.selection;
|
|
105
|
+
$pos = $pos || $from;
|
|
106
|
+
if ($pos.parent.type === state.schema.nodes.mediaGroup) {
|
|
107
|
+
return prepend ? startPositionOfParent($pos) : endPositionOfParent($pos) - 1;
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
};
|
|
111
|
+
export const removeMediaNode = (view, node, getPos) => {
|
|
112
|
+
const {
|
|
113
|
+
id
|
|
114
|
+
} = node.attrs;
|
|
115
|
+
const {
|
|
116
|
+
state
|
|
117
|
+
} = view;
|
|
118
|
+
const {
|
|
119
|
+
tr,
|
|
120
|
+
selection,
|
|
121
|
+
doc
|
|
122
|
+
} = state;
|
|
123
|
+
const currentMediaNodePos = getPos();
|
|
124
|
+
if (typeof currentMediaNodePos !== 'number') {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
tr.deleteRange(currentMediaNodePos, currentMediaNodePos + node.nodeSize);
|
|
128
|
+
if (isTemporary(id)) {
|
|
129
|
+
tr.setMeta('addToHistory', false);
|
|
130
|
+
}
|
|
131
|
+
const $currentMediaNodePos = doc.resolve(currentMediaNodePos);
|
|
132
|
+
const {
|
|
133
|
+
nodeBefore,
|
|
134
|
+
parent
|
|
135
|
+
} = $currentMediaNodePos;
|
|
136
|
+
const isLastMediaNode = $currentMediaNodePos.index() === parent.childCount - 1;
|
|
137
|
+
|
|
138
|
+
// If deleting a selected media node, we need to tell where the cursor to go next.
|
|
139
|
+
// Prosemirror didn't gave us the behaviour of moving left if the media node is not the last one.
|
|
140
|
+
// So we handle it ourselves.
|
|
141
|
+
if (selection.from === currentMediaNodePos && !isLastMediaNode && !atTheBeginningOfDoc(state) && nodeBefore && nodeBefore.type.name === 'media') {
|
|
142
|
+
const nodeBefore = findPositionOfNodeBefore(tr.selection);
|
|
143
|
+
if (nodeBefore) {
|
|
144
|
+
tr.setSelection(NodeSelection.create(tr.doc, nodeBefore));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
view.dispatch(tr);
|
|
148
|
+
};
|
|
149
|
+
export const splitMediaGroup = view => {
|
|
150
|
+
const {
|
|
151
|
+
selection
|
|
152
|
+
} = view.state;
|
|
153
|
+
|
|
154
|
+
// if selection is not a media node, do nothing.
|
|
155
|
+
if (!(selection instanceof NodeSelection) || selection.node.type !== view.state.schema.nodes.media) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
deleteSelection(view.state, view.dispatch);
|
|
159
|
+
if (selection.$to.nodeAfter) {
|
|
160
|
+
splitBlock(view.state, view.dispatch);
|
|
161
|
+
createParagraphNear(false)(view.state, view.dispatch);
|
|
162
|
+
} else {
|
|
163
|
+
createNewParagraphBelow(view.state, view.dispatch);
|
|
164
|
+
}
|
|
165
|
+
return true;
|
|
166
|
+
};
|
|
167
|
+
const isOptionalAttr = attr => attr.length > 1 && attr[0] === '_' && attr[1] === '_';
|
|
168
|
+
export const copyOptionalAttrsFromMediaState = (mediaState, node) => {
|
|
169
|
+
Object.keys(node.attrs).filter(isOptionalAttr).forEach(key => {
|
|
170
|
+
const mediaStateKey = key.substring(2);
|
|
171
|
+
const attrValue = mediaState[mediaStateKey];
|
|
172
|
+
if (attrValue !== undefined) {
|
|
173
|
+
// @ts-ignore - [unblock prosemirror bump] assigning to readonly prop
|
|
174
|
+
node.attrs[key] = attrValue;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
export const getMediaNodeFromSelection = state => {
|
|
179
|
+
if (!isSelectionMediaSingleNode(state)) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
const tr = state.tr;
|
|
183
|
+
const pos = tr.selection.from + 1;
|
|
184
|
+
const mediaNode = tr.doc.nodeAt(pos);
|
|
185
|
+
if (mediaNode && mediaNode.type === state.schema.nodes.media) {
|
|
186
|
+
return mediaNode;
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
};
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
2
|
+
import { atTheBeginningOfBlock, atTheEndOfBlock, atTheEndOfDoc, endPositionOfParent, startPositionOfParent } from '@atlaskit/editor-common/selection';
|
|
3
|
+
import { findFarthestParentNode, insideTableCell, isInLayoutColumn, isInListItem, isSupportedInParent, setNodeSelection, setTextSelection } from '@atlaskit/editor-common/utils';
|
|
4
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
5
|
+
import { canInsert, hasParentNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
6
|
+
import { copyOptionalAttrsFromMediaState, isInsidePotentialEmptyParagraph, isSelectionNonMediaBlockNode, posOfMediaGroupNearby, posOfParentMediaGroup, posOfPrecedingMediaGroup } from './media-common';
|
|
7
|
+
export const canInsertMediaInline = state => {
|
|
8
|
+
const node = state.schema.nodes.mediaInline.create({});
|
|
9
|
+
return canInsert(state.selection.$to, Fragment.from(node));
|
|
10
|
+
};
|
|
11
|
+
const getInsertMediaGroupAnalytics = (mediaState, inputMethod) => {
|
|
12
|
+
let media = '';
|
|
13
|
+
if (mediaState.length === 1) {
|
|
14
|
+
media = mediaState[0].fileMimeType || 'unknown';
|
|
15
|
+
} else if (mediaState.length > 1) {
|
|
16
|
+
media = 'multiple';
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
action: ACTION.INSERTED,
|
|
20
|
+
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
21
|
+
actionSubjectId: ACTION_SUBJECT_ID.MEDIA,
|
|
22
|
+
attributes: {
|
|
23
|
+
type: ACTION_SUBJECT_ID.MEDIA_GROUP,
|
|
24
|
+
inputMethod,
|
|
25
|
+
fileExtension: media
|
|
26
|
+
},
|
|
27
|
+
eventType: EVENT_TYPE.TRACK
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
const getInsertMediaInlineAnalytics = (mediaState, inputMethod) => {
|
|
31
|
+
const media = mediaState.fileMimeType || 'unknown';
|
|
32
|
+
return {
|
|
33
|
+
action: ACTION.INSERTED,
|
|
34
|
+
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
35
|
+
actionSubjectId: ACTION_SUBJECT_ID.MEDIA,
|
|
36
|
+
attributes: {
|
|
37
|
+
type: ACTION_SUBJECT_ID.MEDIA_INLINE,
|
|
38
|
+
inputMethod,
|
|
39
|
+
fileExtension: media
|
|
40
|
+
},
|
|
41
|
+
eventType: EVENT_TYPE.TRACK
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Check if current editor selections is a media group or not.
|
|
47
|
+
* @param state Editor state
|
|
48
|
+
*/
|
|
49
|
+
function isSelectionMediaGroup(state) {
|
|
50
|
+
const {
|
|
51
|
+
schema
|
|
52
|
+
} = state;
|
|
53
|
+
const selectionParent = state.selection.$anchor.node();
|
|
54
|
+
return selectionParent && selectionParent.type === schema.nodes.mediaGroup;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Insert a paragraph after if reach the end of doc
|
|
59
|
+
* and there is no media group in the front or selection is a non media block node
|
|
60
|
+
* @param node Node at insertion point
|
|
61
|
+
* @param state Editor state
|
|
62
|
+
*/
|
|
63
|
+
function shouldAppendParagraph(state, node) {
|
|
64
|
+
const {
|
|
65
|
+
schema: {
|
|
66
|
+
nodes: {
|
|
67
|
+
media
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} = state;
|
|
71
|
+
const wasMediaNode = node && node.type === media;
|
|
72
|
+
return (insideTableCell(state) || isInListItem(state) || isInLayoutColumn(state) || atTheEndOfDoc(state) && (!posOfPrecedingMediaGroup(state) || isSelectionNonMediaBlockNode(state))) && !wasMediaNode;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Create a new media inline to insert the new media.
|
|
77
|
+
* @param view Editor view
|
|
78
|
+
* @param mediaState Media file to be added to the editor
|
|
79
|
+
* @param collection Collection for the media to be added
|
|
80
|
+
*/
|
|
81
|
+
export const insertMediaInlineNode = editorAnalyticsAPI => (view, mediaState, collection, inputMethod) => {
|
|
82
|
+
const {
|
|
83
|
+
state,
|
|
84
|
+
dispatch
|
|
85
|
+
} = view;
|
|
86
|
+
const {
|
|
87
|
+
schema,
|
|
88
|
+
tr
|
|
89
|
+
} = state;
|
|
90
|
+
const {
|
|
91
|
+
mediaInline
|
|
92
|
+
} = schema.nodes;
|
|
93
|
+
|
|
94
|
+
// Do nothing if no media found
|
|
95
|
+
if (!mediaInline || !mediaState || collection === undefined) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const {
|
|
99
|
+
id
|
|
100
|
+
} = mediaState;
|
|
101
|
+
const mediaInlineNode = mediaInline.create({
|
|
102
|
+
id,
|
|
103
|
+
collection
|
|
104
|
+
});
|
|
105
|
+
const space = state.schema.text(' ');
|
|
106
|
+
let pos = state.selection.$to.pos;
|
|
107
|
+
|
|
108
|
+
// If the selection is inside an empty list item set pos inside paragraph
|
|
109
|
+
if (isInListItem(state) && isInsidePotentialEmptyParagraph(state)) {
|
|
110
|
+
pos = pos + 1;
|
|
111
|
+
}
|
|
112
|
+
let content = Fragment.from([mediaInlineNode, space]);
|
|
113
|
+
|
|
114
|
+
// Delete the selection if a selection is made
|
|
115
|
+
const deleteRange = findDeleteRange(state);
|
|
116
|
+
if (!deleteRange) {
|
|
117
|
+
tr.insert(pos, content);
|
|
118
|
+
} else {
|
|
119
|
+
tr.insert(pos, content).deleteRange(deleteRange.start, deleteRange.end);
|
|
120
|
+
}
|
|
121
|
+
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(getInsertMediaInlineAnalytics(mediaState, inputMethod))(tr);
|
|
122
|
+
dispatch(tr);
|
|
123
|
+
return true;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Insert a media into an existing media group
|
|
128
|
+
* or create a new media group to insert the new media.
|
|
129
|
+
* @param view Editor view
|
|
130
|
+
* @param mediaStates Media files to be added to the editor
|
|
131
|
+
* @param collection Collection for the media to be added
|
|
132
|
+
*/
|
|
133
|
+
export const insertMediaGroupNode = editorAnalyticsAPI => (view, mediaStates, collection, inputMethod) => {
|
|
134
|
+
const {
|
|
135
|
+
state,
|
|
136
|
+
dispatch
|
|
137
|
+
} = view;
|
|
138
|
+
const {
|
|
139
|
+
tr,
|
|
140
|
+
schema
|
|
141
|
+
} = state;
|
|
142
|
+
const {
|
|
143
|
+
media,
|
|
144
|
+
paragraph
|
|
145
|
+
} = schema.nodes;
|
|
146
|
+
|
|
147
|
+
// Do nothing if no media found
|
|
148
|
+
if (!media || !mediaStates.length) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const mediaNodes = createMediaFileNodes(mediaStates, collection, media);
|
|
152
|
+
const mediaInsertPos = findMediaInsertPos(state);
|
|
153
|
+
const resolvedInsertPos = tr.doc.resolve(mediaInsertPos);
|
|
154
|
+
const parent = resolvedInsertPos.parent;
|
|
155
|
+
const nodeAtInsertionPoint = tr.doc.nodeAt(mediaInsertPos);
|
|
156
|
+
const shouldSplit = !isSelectionMediaGroup(state) && isSupportedInParent(state, Fragment.from(state.schema.nodes.mediaGroup.createChecked({}, mediaNodes)));
|
|
157
|
+
const withParagraph = shouldAppendParagraph(state, nodeAtInsertionPoint);
|
|
158
|
+
let content = parent.type === schema.nodes.mediaGroup ? mediaNodes // If parent is a mediaGroup do not wrap items again.
|
|
159
|
+
: [schema.nodes.mediaGroup.createChecked({}, mediaNodes)];
|
|
160
|
+
if (shouldSplit) {
|
|
161
|
+
content = withParagraph ? content.concat(paragraph.create()) : content;
|
|
162
|
+
// delete the selection or empty paragraph
|
|
163
|
+
const deleteRange = findDeleteRange(state);
|
|
164
|
+
if (!deleteRange) {
|
|
165
|
+
tr.insert(mediaInsertPos, content);
|
|
166
|
+
} else if (mediaInsertPos <= deleteRange.start) {
|
|
167
|
+
tr.deleteRange(deleteRange.start, deleteRange.end).insert(mediaInsertPos, content);
|
|
168
|
+
} else {
|
|
169
|
+
tr.insert(mediaInsertPos, content).deleteRange(deleteRange.start, deleteRange.end);
|
|
170
|
+
}
|
|
171
|
+
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(getInsertMediaGroupAnalytics(mediaStates, inputMethod))(tr);
|
|
172
|
+
dispatch(tr);
|
|
173
|
+
setSelectionAfterMediaInsertion(view);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Don't append new paragraph when adding media to a existing mediaGroup
|
|
178
|
+
if (withParagraph && parent.type !== schema.nodes.mediaGroup) {
|
|
179
|
+
content.push(paragraph.create());
|
|
180
|
+
}
|
|
181
|
+
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(getInsertMediaGroupAnalytics(mediaStates, inputMethod))(tr);
|
|
182
|
+
dispatch(safeInsert(Fragment.fromArray(content), mediaInsertPos)(tr));
|
|
183
|
+
};
|
|
184
|
+
const createMediaFileNodes = (mediaStates, collection, media) => {
|
|
185
|
+
const nodes = mediaStates.map(mediaState => {
|
|
186
|
+
const {
|
|
187
|
+
id
|
|
188
|
+
} = mediaState;
|
|
189
|
+
const node = media.create({
|
|
190
|
+
id,
|
|
191
|
+
type: 'file',
|
|
192
|
+
collection
|
|
193
|
+
});
|
|
194
|
+
copyOptionalAttrsFromMediaState(mediaState, node);
|
|
195
|
+
return node;
|
|
196
|
+
});
|
|
197
|
+
return nodes;
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Find root list node if exist from current selection
|
|
202
|
+
* @param state Editor state
|
|
203
|
+
*/
|
|
204
|
+
const findRootListNode = state => {
|
|
205
|
+
const {
|
|
206
|
+
schema: {
|
|
207
|
+
nodes: {
|
|
208
|
+
bulletList,
|
|
209
|
+
orderedList
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} = state;
|
|
213
|
+
return findFarthestParentNode(node => node.type === bulletList || node.type === orderedList)(state.selection.$from);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Return position of media to be inserted, if it is inside a list
|
|
218
|
+
* @param content Content to be inserted
|
|
219
|
+
* @param state Editor State
|
|
220
|
+
*/
|
|
221
|
+
export const getPosInList = state => {
|
|
222
|
+
const {
|
|
223
|
+
schema: {
|
|
224
|
+
nodes: {
|
|
225
|
+
mediaGroup,
|
|
226
|
+
listItem
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
} = state;
|
|
230
|
+
|
|
231
|
+
// 1. Check if I am inside a list.
|
|
232
|
+
if (hasParentNode(node => node.type === listItem)(state.selection)) {
|
|
233
|
+
// 2. Get end position of root list
|
|
234
|
+
const rootListNode = findRootListNode(state);
|
|
235
|
+
if (rootListNode) {
|
|
236
|
+
const pos = rootListNode.pos + rootListNode.node.nodeSize;
|
|
237
|
+
// 3. Fint the first location inside the media group
|
|
238
|
+
const nextNode = state.doc.nodeAt(pos);
|
|
239
|
+
if (nextNode && nextNode.type === mediaGroup) {
|
|
240
|
+
return pos + 1;
|
|
241
|
+
}
|
|
242
|
+
return pos;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Find insertion point,
|
|
250
|
+
* If it is in a List it will return position to the next block,
|
|
251
|
+
* If there are any media group close it will return this position
|
|
252
|
+
* Otherwise, It will return the respective block given selection.
|
|
253
|
+
* @param content Content to be inserted
|
|
254
|
+
* @param state Editor state
|
|
255
|
+
*/
|
|
256
|
+
const findMediaInsertPos = state => {
|
|
257
|
+
const {
|
|
258
|
+
$from,
|
|
259
|
+
$to
|
|
260
|
+
} = state.selection;
|
|
261
|
+
|
|
262
|
+
// Check if selection is inside a list.
|
|
263
|
+
const posInList = getPosInList(state);
|
|
264
|
+
if (posInList) {
|
|
265
|
+
// If I have a position in lists, I should return, otherwise I am not inside a list
|
|
266
|
+
return posInList;
|
|
267
|
+
}
|
|
268
|
+
const nearbyMediaGroupPos = posOfMediaGroupNearby(state);
|
|
269
|
+
if (nearbyMediaGroupPos && (!isSelectionNonMediaBlockNode(state) || $from.pos < nearbyMediaGroupPos && $to.pos < nearbyMediaGroupPos)) {
|
|
270
|
+
return nearbyMediaGroupPos;
|
|
271
|
+
}
|
|
272
|
+
if (isSelectionNonMediaBlockNode(state)) {
|
|
273
|
+
return $to.pos;
|
|
274
|
+
}
|
|
275
|
+
if (atTheEndOfBlock(state)) {
|
|
276
|
+
return $to.pos + 1;
|
|
277
|
+
}
|
|
278
|
+
if (atTheBeginningOfBlock(state)) {
|
|
279
|
+
return $from.pos - 1;
|
|
280
|
+
}
|
|
281
|
+
return $to.pos;
|
|
282
|
+
};
|
|
283
|
+
const findDeleteRange = state => {
|
|
284
|
+
const {
|
|
285
|
+
$from,
|
|
286
|
+
$to
|
|
287
|
+
} = state.selection;
|
|
288
|
+
if (posOfParentMediaGroup(state)) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (!isInsidePotentialEmptyParagraph(state) || posOfMediaGroupNearby(state)) {
|
|
292
|
+
return range($from.pos, $to.pos);
|
|
293
|
+
}
|
|
294
|
+
return range(startPositionOfParent($from) - 1, endPositionOfParent($to));
|
|
295
|
+
};
|
|
296
|
+
const range = (start, end = start) => {
|
|
297
|
+
return {
|
|
298
|
+
start,
|
|
299
|
+
end
|
|
300
|
+
};
|
|
301
|
+
};
|
|
302
|
+
const setSelectionAfterMediaInsertion = view => {
|
|
303
|
+
const {
|
|
304
|
+
state
|
|
305
|
+
} = view;
|
|
306
|
+
const {
|
|
307
|
+
doc
|
|
308
|
+
} = state;
|
|
309
|
+
const mediaPos = posOfMediaGroupNearby(state);
|
|
310
|
+
if (!mediaPos) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const $mediaPos = doc.resolve(mediaPos);
|
|
314
|
+
const endOfMediaGroup = endPositionOfParent($mediaPos);
|
|
315
|
+
if (endOfMediaGroup + 1 >= doc.nodeSize - 1) {
|
|
316
|
+
// if nothing after the media group, fallback to select the newest uploaded media item
|
|
317
|
+
setNodeSelection(view, mediaPos);
|
|
318
|
+
} else {
|
|
319
|
+
setTextSelection(view, endOfMediaGroup + 1);
|
|
320
|
+
}
|
|
321
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
2
|
+
import { safeInsert, shouldSplitSelectedNodeOnNodeInsertion } from '@atlaskit/editor-common/insert';
|
|
3
|
+
import { getMaxWidthForNestedNodeNext, getMediaSingleInitialWidth, MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH } from '@atlaskit/editor-common/media-single';
|
|
4
|
+
import { atTheBeginningOfBlock } from '@atlaskit/editor-common/selection';
|
|
5
|
+
import { checkNodeDown, isEmptyParagraph } from '@atlaskit/editor-common/utils';
|
|
6
|
+
import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
|
|
7
|
+
import { safeInsert as pmSafeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
8
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
9
|
+
import { copyOptionalAttrsFromMediaState } from '../utils/media-common';
|
|
10
|
+
import { isImage } from './is-image';
|
|
11
|
+
const getInsertMediaAnalytics = (inputMethod, fileExtension) => ({
|
|
12
|
+
action: ACTION.INSERTED,
|
|
13
|
+
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
14
|
+
actionSubjectId: ACTION_SUBJECT_ID.MEDIA,
|
|
15
|
+
attributes: {
|
|
16
|
+
inputMethod,
|
|
17
|
+
fileExtension,
|
|
18
|
+
type: ACTION_SUBJECT_ID.MEDIA_SINGLE
|
|
19
|
+
},
|
|
20
|
+
eventType: EVENT_TYPE.TRACK
|
|
21
|
+
});
|
|
22
|
+
function shouldAddParagraph(state) {
|
|
23
|
+
return atTheBeginningOfBlock(state) && !checkNodeDown(state.selection, state.doc, isEmptyParagraph);
|
|
24
|
+
}
|
|
25
|
+
function insertNodesWithOptionalParagraph(nodes, analyticsAttributes = {}, editorAnalyticsAPI) {
|
|
26
|
+
return function (state, dispatch) {
|
|
27
|
+
const {
|
|
28
|
+
tr,
|
|
29
|
+
schema
|
|
30
|
+
} = state;
|
|
31
|
+
const {
|
|
32
|
+
paragraph
|
|
33
|
+
} = schema.nodes;
|
|
34
|
+
const {
|
|
35
|
+
inputMethod,
|
|
36
|
+
fileExtension
|
|
37
|
+
} = analyticsAttributes;
|
|
38
|
+
let openEnd = 0;
|
|
39
|
+
if (shouldAddParagraph(state)) {
|
|
40
|
+
nodes.push(paragraph.create());
|
|
41
|
+
openEnd = 1;
|
|
42
|
+
}
|
|
43
|
+
tr.replaceSelection(new Slice(Fragment.from(nodes), 0, openEnd));
|
|
44
|
+
if (inputMethod) {
|
|
45
|
+
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(getInsertMediaAnalytics(inputMethod, fileExtension))(tr);
|
|
46
|
+
}
|
|
47
|
+
if (dispatch) {
|
|
48
|
+
dispatch(tr);
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export const isMediaSingle = (schema, fileMimeType) => !!schema.nodes.mediaSingle && isImage(fileMimeType);
|
|
54
|
+
export const insertMediaAsMediaSingle = (view, node, inputMethod, editorAnalyticsAPI) => {
|
|
55
|
+
const {
|
|
56
|
+
state,
|
|
57
|
+
dispatch
|
|
58
|
+
} = view;
|
|
59
|
+
const {
|
|
60
|
+
mediaSingle,
|
|
61
|
+
media
|
|
62
|
+
} = state.schema.nodes;
|
|
63
|
+
if (!mediaSingle) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// if not an image type media node
|
|
68
|
+
if (node.type !== media || !isImage(node.attrs.__fileMimeType) && node.attrs.type !== 'external') {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
const mediaSingleNode = mediaSingle.create({}, node);
|
|
72
|
+
const nodes = [mediaSingleNode];
|
|
73
|
+
const analyticsAttributes = {
|
|
74
|
+
inputMethod,
|
|
75
|
+
fileExtension: node.attrs.__fileMimeType
|
|
76
|
+
};
|
|
77
|
+
return insertNodesWithOptionalParagraph(nodes, analyticsAttributes, editorAnalyticsAPI)(state, dispatch);
|
|
78
|
+
};
|
|
79
|
+
export const insertMediaSingleNode = (view, mediaState, inputMethod, collection, alignLeftOnInsert, newInsertionBehaviour, widthPluginState, editorAnalyticsAPI) => {
|
|
80
|
+
var _state$selection$$fro;
|
|
81
|
+
if (collection === undefined) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
const {
|
|
85
|
+
state,
|
|
86
|
+
dispatch
|
|
87
|
+
} = view;
|
|
88
|
+
const grandParentNodeType = (_state$selection$$fro = state.selection.$from.node(-1)) === null || _state$selection$$fro === void 0 ? void 0 : _state$selection$$fro.type;
|
|
89
|
+
const parentNodeType = state.selection.$from.parent.type;
|
|
90
|
+
|
|
91
|
+
// add undefined as fallback as we don't want media single width to have upper limit as 0
|
|
92
|
+
// if widthPluginState.width is 0, default 760 will be used
|
|
93
|
+
const contentWidth = getMaxWidthForNestedNodeNext(view, state.selection.$from.pos, true) || (widthPluginState === null || widthPluginState === void 0 ? void 0 : widthPluginState.lineLength) || (widthPluginState === null || widthPluginState === void 0 ? void 0 : widthPluginState.width) || undefined;
|
|
94
|
+
const node = createMediaSingleNode(state.schema, collection, contentWidth, mediaState.status !== 'error' && isVideo(mediaState.fileMimeType) ? MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH : MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, alignLeftOnInsert)(mediaState);
|
|
95
|
+
let fileExtension;
|
|
96
|
+
if (mediaState.fileName) {
|
|
97
|
+
const extensionIdx = mediaState.fileName.lastIndexOf('.');
|
|
98
|
+
fileExtension = extensionIdx >= 0 ? mediaState.fileName.substring(extensionIdx + 1) : undefined;
|
|
99
|
+
}
|
|
100
|
+
// should split if media is valid content for the grandparent of the selected node
|
|
101
|
+
// and the parent node is a paragraph
|
|
102
|
+
if (shouldSplitSelectedNodeOnNodeInsertion({
|
|
103
|
+
parentNodeType,
|
|
104
|
+
grandParentNodeType,
|
|
105
|
+
content: node
|
|
106
|
+
})) {
|
|
107
|
+
insertNodesWithOptionalParagraph([node], {
|
|
108
|
+
fileExtension,
|
|
109
|
+
inputMethod
|
|
110
|
+
}, editorAnalyticsAPI)(state, dispatch);
|
|
111
|
+
} else {
|
|
112
|
+
let tr = null;
|
|
113
|
+
if (newInsertionBehaviour) {
|
|
114
|
+
tr = safeInsert(node, state.selection.from)(state.tr);
|
|
115
|
+
}
|
|
116
|
+
if (!tr) {
|
|
117
|
+
const content = shouldAddParagraph(view.state) ? Fragment.fromArray([node, state.schema.nodes.paragraph.create()]) : node;
|
|
118
|
+
tr = pmSafeInsert(content, undefined, true)(state.tr);
|
|
119
|
+
}
|
|
120
|
+
if (inputMethod) {
|
|
121
|
+
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(getInsertMediaAnalytics(inputMethod, fileExtension))(tr);
|
|
122
|
+
}
|
|
123
|
+
dispatch(tr);
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
};
|
|
127
|
+
export const createMediaSingleNode = (schema, collection, maxWidth, minWidth, alignLeftOnInsert) => mediaState => {
|
|
128
|
+
const {
|
|
129
|
+
id,
|
|
130
|
+
dimensions,
|
|
131
|
+
contextId,
|
|
132
|
+
scaleFactor = 1
|
|
133
|
+
} = mediaState;
|
|
134
|
+
const {
|
|
135
|
+
width,
|
|
136
|
+
height
|
|
137
|
+
} = dimensions || {
|
|
138
|
+
height: undefined,
|
|
139
|
+
width: undefined
|
|
140
|
+
};
|
|
141
|
+
const {
|
|
142
|
+
media,
|
|
143
|
+
mediaSingle
|
|
144
|
+
} = schema.nodes;
|
|
145
|
+
const scaledWidth = width && Math.round(width / scaleFactor);
|
|
146
|
+
const mediaNode = media.create({
|
|
147
|
+
id,
|
|
148
|
+
type: 'file',
|
|
149
|
+
collection,
|
|
150
|
+
contextId,
|
|
151
|
+
width: scaledWidth,
|
|
152
|
+
height: height && Math.round(height / scaleFactor)
|
|
153
|
+
});
|
|
154
|
+
const mediaSingleAttrs = alignLeftOnInsert ? {
|
|
155
|
+
layout: 'align-start'
|
|
156
|
+
} : {};
|
|
157
|
+
const extendedMediaSingleAttrs = getBooleanFF('platform.editor.media.extended-resize-experience') ? {
|
|
158
|
+
...mediaSingleAttrs,
|
|
159
|
+
width: getMediaSingleInitialWidth(scaledWidth, maxWidth, minWidth),
|
|
160
|
+
// TODO: change to use enum
|
|
161
|
+
widthType: 'pixel'
|
|
162
|
+
} : mediaSingleAttrs;
|
|
163
|
+
copyOptionalAttrsFromMediaState(mediaState, mediaNode);
|
|
164
|
+
return mediaSingle.createChecked(extendedMediaSingleAttrs, mediaNode);
|
|
165
|
+
};
|
|
166
|
+
export function isCaptionNode(editorView) {
|
|
167
|
+
const {
|
|
168
|
+
$from
|
|
169
|
+
} = editorView.state.selection;
|
|
170
|
+
const immediateWrapperParentNode = editorView.state.doc.nodeAt($from.before(Math.max($from.depth, 1)));
|
|
171
|
+
if (immediateWrapperParentNode && immediateWrapperParentNode.type.name === 'caption') {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
export const isVideo = fileType => !!fileType && fileType.includes('video');
|