mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-02 12:47:41 +02:00
Desktop: Fixes #11274: Fix content dropped into the Markdown editor is missing a cursor preview or dropped at the wrong location (#11289)
This commit is contained in:
parent
2974465882
commit
612d72d765
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
import { RefObject, useMemo } from 'react';
|
import { RefObject, useMemo } from 'react';
|
||||||
import { CommandValue } from '../../../utils/types';
|
import { CommandValue, DropCommandValue } from '../../../utils/types';
|
||||||
import { commandAttachFileToBody } from '../../../utils/resourceHandling';
|
import { commandAttachFileToBody } from '../../../utils/resourceHandling';
|
||||||
import { _ } from '@joplin/lib/locale';
|
import { _ } from '@joplin/lib/locale';
|
||||||
import dialogs from '../../../../dialogs';
|
import dialogs from '../../../../dialogs';
|
||||||
import { EditorCommandType } from '@joplin/editor/types';
|
import { EditorCommandType, UserEventSource } from '@joplin/editor/types';
|
||||||
import Logger from '@joplin/utils/Logger';
|
import Logger from '@joplin/utils/Logger';
|
||||||
import CodeMirrorControl from '@joplin/editor/CodeMirror/CodeMirrorControl';
|
import CodeMirrorControl from '@joplin/editor/CodeMirror/CodeMirrorControl';
|
||||||
import { MarkupLanguage } from '@joplin/renderer';
|
import { MarkupLanguage } from '@joplin/renderer';
|
||||||
@ -38,13 +38,22 @@ const useEditorCommands = (props: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
dropItems: async (cmd: DropCommandValue) => {
|
||||||
dropItems: async (cmd: any) => {
|
let pos = cmd.pos && editorRef.current.editor.posAtCoords({ x: cmd.pos.clientX, y: cmd.pos.clientY });
|
||||||
if (cmd.type === 'notes') {
|
if (cmd.type === 'notes') {
|
||||||
editorRef.current.insertText(cmd.markdownTags.join('\n'));
|
const text = cmd.markdownTags.join('\n');
|
||||||
|
if ((pos ?? null) !== null) {
|
||||||
|
editorRef.current.select(pos, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
editorRef.current.insertText(text, UserEventSource.Drop);
|
||||||
} else if (cmd.type === 'files') {
|
} else if (cmd.type === 'files') {
|
||||||
const pos = props.selectionRange.from;
|
pos ??= props.selectionRange.from;
|
||||||
const newBody = await commandAttachFileToBody(props.editorContent, cmd.paths, { createFileURL: !!cmd.createFileURL, position: pos, markupLanguage: props.contentMarkupLanguage });
|
const newBody = await commandAttachFileToBody(props.editorContent, cmd.paths, {
|
||||||
|
createFileURL: !!cmd.createFileURL,
|
||||||
|
position: pos,
|
||||||
|
markupLanguage: props.contentMarkupLanguage,
|
||||||
|
});
|
||||||
editorRef.current.updateBody(newBody);
|
editorRef.current.updateBody(newBody);
|
||||||
} else {
|
} else {
|
||||||
logger.warn('CodeMirror: unsupported drop item: ', cmd);
|
logger.warn('CodeMirror: unsupported drop item: ', cmd);
|
||||||
|
@ -252,3 +252,19 @@ export interface CommandValue {
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
value?: any; // For TinyMCE only
|
value?: any; // For TinyMCE only
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DropCommandBase = {
|
||||||
|
pos: {
|
||||||
|
clientX: number;
|
||||||
|
clientY: number;
|
||||||
|
}|undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DropCommandValue = ({
|
||||||
|
type: 'notes';
|
||||||
|
markdownTags: string[];
|
||||||
|
}|{
|
||||||
|
type: 'files';
|
||||||
|
paths: string[];
|
||||||
|
createFileURL: boolean;
|
||||||
|
}) & DropCommandBase;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import Note from '@joplin/lib/models/Note';
|
import Note from '@joplin/lib/models/Note';
|
||||||
import { DragEvent as ReactDragEvent } from 'react';
|
import { DragEvent as ReactDragEvent } from 'react';
|
||||||
|
import { DropCommandValue } from './types';
|
||||||
|
|
||||||
interface HookDependencies {
|
interface HookDependencies {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
@ -19,6 +20,11 @@ export default function useDropHandler(dependencies: HookDependencies): DropHand
|
|||||||
const dt = event.dataTransfer;
|
const dt = event.dataTransfer;
|
||||||
const createFileURL = event.altKey;
|
const createFileURL = event.altKey;
|
||||||
|
|
||||||
|
const eventPosition = {
|
||||||
|
clientX: event.clientX,
|
||||||
|
clientY: event.clientY,
|
||||||
|
};
|
||||||
|
|
||||||
if (dt.types.indexOf('text/x-jop-note-ids') >= 0) {
|
if (dt.types.indexOf('text/x-jop-note-ids') >= 0) {
|
||||||
const noteIds = JSON.parse(dt.getData('text/x-jop-note-ids'));
|
const noteIds = JSON.parse(dt.getData('text/x-jop-note-ids'));
|
||||||
|
|
||||||
@ -29,12 +35,15 @@ export default function useDropHandler(dependencies: HookDependencies): DropHand
|
|||||||
noteMarkdownTags.push(Note.markdownTag(note));
|
noteMarkdownTags.push(Note.markdownTag(note));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const props: DropCommandValue = {
|
||||||
|
type: 'notes',
|
||||||
|
pos: eventPosition,
|
||||||
|
markdownTags: noteMarkdownTags,
|
||||||
|
};
|
||||||
|
|
||||||
editorRef.current.execCommand({
|
editorRef.current.execCommand({
|
||||||
name: 'dropItems',
|
name: 'dropItems',
|
||||||
value: {
|
value: props,
|
||||||
type: 'notes',
|
|
||||||
markdownTags: noteMarkdownTags,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
void dropNotes();
|
void dropNotes();
|
||||||
@ -51,13 +60,16 @@ export default function useDropHandler(dependencies: HookDependencies): DropHand
|
|||||||
paths.push(file.path);
|
paths.push(file.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const props: DropCommandValue = {
|
||||||
|
type: 'files',
|
||||||
|
pos: eventPosition,
|
||||||
|
paths: paths,
|
||||||
|
createFileURL: createFileURL,
|
||||||
|
};
|
||||||
|
|
||||||
editorRef.current.execCommand({
|
editorRef.current.execCommand({
|
||||||
name: 'dropItems',
|
name: 'dropItems',
|
||||||
value: {
|
value: props,
|
||||||
type: 'files',
|
|
||||||
paths: paths,
|
|
||||||
createFileURL: createFileURL,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import { classHighlighter } from '@lezer/highlight';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
EditorView, drawSelection, highlightSpecialChars, ViewUpdate, Command, rectangularSelection,
|
EditorView, drawSelection, highlightSpecialChars, ViewUpdate, Command, rectangularSelection,
|
||||||
|
dropCursor,
|
||||||
} from '@codemirror/view';
|
} from '@codemirror/view';
|
||||||
import { history, undoDepth, redoDepth, standardKeymap } from '@codemirror/commands';
|
import { history, undoDepth, redoDepth, standardKeymap } from '@codemirror/commands';
|
||||||
|
|
||||||
@ -253,6 +254,8 @@ const createEditor = (
|
|||||||
|
|
||||||
// Apply styles to entire lines (block-display decorations)
|
// Apply styles to entire lines (block-display decorations)
|
||||||
decoratorExtension,
|
decoratorExtension,
|
||||||
|
dropCursor(),
|
||||||
|
|
||||||
biDirectionalTextExtension,
|
biDirectionalTextExtension,
|
||||||
|
|
||||||
// Adds additional CSS classes to tokens (the default CSS classes are
|
// Adds additional CSS classes to tokens (the default CSS classes are
|
||||||
|
@ -90,6 +90,7 @@ export interface ContentScriptData {
|
|||||||
// Intended to correspond with https://codemirror.net/docs/ref/#state.Transaction%5EuserEvent
|
// Intended to correspond with https://codemirror.net/docs/ref/#state.Transaction%5EuserEvent
|
||||||
export enum UserEventSource {
|
export enum UserEventSource {
|
||||||
Paste = 'input.paste',
|
Paste = 'input.paste',
|
||||||
|
Drop = 'input.drop',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EditorControl {
|
export interface EditorControl {
|
||||||
|
Loading…
Reference in New Issue
Block a user