Skip to content

Commit

Permalink
fix paste issue (#7493)
Browse files Browse the repository at this point in the history
  • Loading branch information
reactoholic authored Jan 23, 2025
1 parent 6990e84 commit 15b073c
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 66 deletions.
5 changes: 4 additions & 1 deletion src/core/ui/forms/MarkdownInput/FormikMarkdownField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { MarkdownTextMaxLength } from '../field-length.constants';
import { error as logError } from '@/core/logging/sentry/log';
import { isMarkdownMaxLengthError } from './MarkdownValidator';
import { useTranslation } from 'react-i18next';
import { useStorageConfigContext } from '@/domain/storage/StorageBucket/StorageConfigContext';

interface MarkdownFieldProps extends InputProps {
title: string;
Expand Down Expand Up @@ -120,6 +121,8 @@ export const FormikMarkdownField = ({

const labelOffset = inputElement?.getLabelOffset();

const storageConfig = useStorageConfigContext();

return (
<FormControl required={required} disabled={disabled} error={isError} fullWidth>
<CharacterCountContextProvider>
Expand All @@ -141,7 +144,7 @@ export const FormikMarkdownField = ({
onChange={handleChange}
onBlur={handleBlur}
label={title}
inputComponent={MarkdownInput}
inputComponent={props => <MarkdownInput {...props} storageBucketId={storageConfig?.storageBucketId} />}
inputRef={inputRef}
inputProps={{
controlsVisible,
Expand Down
133 changes: 68 additions & 65 deletions src/core/ui/forms/MarkdownInput/MarkdownInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import { Selection } from 'prosemirror-state';
import { EditorOptions } from '@tiptap/core';
import { Iframe } from '../MarkdownInputControls/InsertEmbedCodeButton/Iframe';
import { EditorView } from '@tiptap/pm/view';
import { useStorageConfigContext } from '@/domain/storage/StorageBucket/StorageConfigContext';
import { useUploadFileMutation } from '@/core/apollo/generated/apollo-hooks';
import { useNotification } from '../../notifications/useNotification';

Expand All @@ -37,6 +36,7 @@ interface MarkdownInputProps extends InputBaseComponentProps {
maxLength?: number;
hideImageOptions?: boolean;
temporaryLocation?: boolean;
storageBucketId: string | undefined;
}

type Offset = {
Expand Down Expand Up @@ -72,6 +72,7 @@ export const MarkdownInput = memo(
hideImageOptions,
onFocus,
onBlur,
storageBucketId,
temporaryLocation = false,
},
ref
Expand Down Expand Up @@ -121,85 +122,87 @@ export const MarkdownInput = memo(
return false; // Not an image or HTML with images
};

const storageConfig = useStorageConfigContext();
/**
* Handles the paste event in the editor.
*
* @param _view - The editor view instance.
* @param event - The clipboard event triggered by pasting.
* @returns {boolean} - Returns true if the paste event is handled, otherwise false - continue execution of the default.
*
* Reference to alternative way of handling paste events in Tiptap: https://tiptap.dev/docs/editor/extensions/functionality/filehandler
*
*/
const handlePaste = useCallback(
(_view: EditorView, event: ClipboardEvent): boolean => {
const clipboardData = event.clipboardData;
const items = clipboardData?.items;

if (!items) {
return false;
}

const editorOptions: Partial<EditorOptions> = useMemo(
() => ({
extensions: [StarterKit, ImageExtension, Link, Highlight, Iframe],
editorProps: {
/**
* Handles the paste event in the editor.
*
* @param _view - The editor view instance.
* @param event - The clipboard event triggered by pasting.
* @returns {boolean} - Returns true if the paste event is handled, otherwise false - continue execution of the default.
*/
handlePaste: (_view: EditorView, event: ClipboardEvent): boolean => {
const clipboardData = event.clipboardData;
const items = clipboardData?.items;

if (!items) {
return false;
}
if (!storageBucketId) {
return false;
}

const storageBucketId = storageConfig?.storageBucketId;
let imageProcessed = false;

if (!storageBucketId) {
return false;
}
for (const item of items) {
const isImage = isImageOrHtmlWithImage(item, clipboardData);

let imageProcessed = false;
if (hideImageOptions && isImage) {
event.preventDefault();

for (const item of items) {
const isImage = isImageOrHtmlWithImage(item, clipboardData);
return true; // Block paste of images or HTML with images
}

if (hideImageOptions && isImage) {
event.preventDefault();
if (!imageProcessed && isImage) {
if (item.kind === 'file' && item.type.startsWith('image/')) {
const file = item.getAsFile();

return true; // Block paste of images or HTML with images
}
if (file) {
const reader = new FileReader();

if (!imageProcessed && isImage) {
if (item.kind === 'file' && item.type.startsWith('image/')) {
const file = item.getAsFile();

if (file) {
const reader = new FileReader();

reader.onload = () => {
uploadFile({
variables: {
file,
uploadData: { storageBucketId, temporaryLocation },
},
});
};

reader.readAsDataURL(file);
imageProcessed = true;
}
} else if (item.kind === 'string' && item.type === 'text/html') {
imageProcessed = true; // HTML with images
}
}
reader.onload = () => {
uploadFile({
variables: {
file,
uploadData: { storageBucketId, temporaryLocation },
},
});
};

if (imageProcessed) {
// Stop if we have already processed an image
break;
reader.readAsDataURL(file);
imageProcessed = true;
}
} else if (item.kind === 'string' && item.type === 'text/html') {
imageProcessed = true; // HTML with images
}
}

if (imageProcessed) {
event.preventDefault();
if (imageProcessed) {
// Stop if we have already processed an image
break;
}
}

return true; // Block default behavior for images
}
if (imageProcessed) {
event.preventDefault();

return false; // Allow default behavior for text
},
},
return true; // Block default behavior for images
}

return false; // Allow default behavior for text
},
[storageBucketId, hideImageOptions, temporaryLocation, uploadFile, isImageOrHtmlWithImage]
);

const editorOptions: Partial<EditorOptions> = useMemo(
() => ({
extensions: [StarterKit, ImageExtension, Link, Highlight, Iframe],
editorProps: { handlePaste },
}),
[storageConfig, temporaryLocation, uploadFile]
[handlePaste]
);

const editor = useEditor({ ...editorOptions, content: htmlContent }, [htmlContent]);
Expand Down

0 comments on commit 15b073c

Please sign in to comment.