1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-11 18:24:43 +02:00

context menu

This commit is contained in:
Laurent Cozic 2023-08-11 19:19:17 +01:00
parent c1c6fb203a
commit 47ecb47189
10 changed files with 86 additions and 52 deletions

View File

@ -284,6 +284,7 @@ packages/app-desktop/gui/NoteListItem/NoteListItem.js
packages/app-desktop/gui/NoteListItem/utils/types.js
packages/app-desktop/gui/NoteListItem/utils/useItemElement.js
packages/app-desktop/gui/NoteListItem/utils/useItemEventHandlers.js
packages/app-desktop/gui/NoteListItem/utils/useOnContextMenu.js
packages/app-desktop/gui/NoteListItem/utils/useRootElement.js
packages/app-desktop/gui/NoteListWrapper/NoteListWrapper.js
packages/app-desktop/gui/NotePropertiesDialog.js

1
.gitignore vendored
View File

@ -270,6 +270,7 @@ packages/app-desktop/gui/NoteListItem/NoteListItem.js
packages/app-desktop/gui/NoteListItem/utils/types.js
packages/app-desktop/gui/NoteListItem/utils/useItemElement.js
packages/app-desktop/gui/NoteListItem/utils/useItemEventHandlers.js
packages/app-desktop/gui/NoteListItem/utils/useOnContextMenu.js
packages/app-desktop/gui/NoteListItem/utils/useRootElement.js
packages/app-desktop/gui/NoteListWrapper/NoteListWrapper.js
packages/app-desktop/gui/NotePropertiesDialog.js

View File

@ -1,6 +1,7 @@
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
import * as React from 'react';
import NoteListUtils from './utils/NoteListUtils';
import { Dispatch } from 'redux';
const { buildStyle } = require('@joplin/lib/theme');
const bridge = require('@electron/remote').require('./bridge').default;
@ -9,8 +10,7 @@ interface MultiNoteActionsProps {
themeId: number;
selectedNoteIds: string[];
notes: any[];
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
dispatch: Function;
dispatch: Dispatch;
watchedNoteFiles: string[];
plugins: PluginStates;
inConflictFolder: boolean;

View File

@ -1,4 +1,3 @@
// eslint-disable-next-line no-unused-vars
import AsyncActionQueue from '@joplin/lib/AsyncActionQueue';
import { ToolbarButtonInfo } from '@joplin/lib/services/commands/ToolbarButtonUtils';
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
@ -6,6 +5,7 @@ import { State as ShareState } from '@joplin/lib/services/share/reducer';
import { MarkupLanguage } from '@joplin/renderer';
import { RenderResult, RenderResultPluginAsset } from '@joplin/renderer/MarkupToHtml';
import { MarkupToHtmlOptions } from './useMarkupToHtml';
import { Dispatch } from 'redux';
export interface AllAssetsOptions {
contentMaxWidthTarget?: string;
@ -16,11 +16,9 @@ export interface ToolbarButtonInfos {
}
export interface NoteEditorProps {
// style: any;
noteId: string;
themeId: number;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
dispatch: Function;
dispatch: Dispatch;
selectedNoteIds: string[];
selectedFolderId: string;
notes: any[];

View File

@ -12,6 +12,7 @@ import defaultListRenderer from './utils/defaultListRenderer';
import NoteListItem from '../NoteListItem/NoteListItem';
import useRenderedNotes from './utils/useRenderedNote';
import useItemCss from './utils/useItemCss';
import useOnContextMenu from '../NoteListItem/utils/useOnContextMenu';
const NoteList = (props: Props) => {
const listRenderer = defaultListRenderer;
@ -63,6 +64,16 @@ const NoteList = (props: Props) => {
useItemCss(listRenderer.itemCss);
const onItemContextMenu = useOnContextMenu(
props.selectedNoteIds,
props.selectedFolderId,
props.notes,
props.dispatch,
props.watchedNoteFiles,
props.plugins,
props.customCss
);
const renderNotes = () => {
const output: JSX.Element[] = [];
@ -76,6 +87,7 @@ const NoteList = (props: Props) => {
noteHtml={renderedNote.html}
itemSize={itemSize}
style={noteItemStyle}
onContextMenu={onItemContextMenu}
/>
);
}

View File

@ -2,7 +2,6 @@ import * as React from 'react';
import { useMemo, useEffect, useState, useRef, useCallback } from 'react';
import { AppState } from '../../app.reducer';
import eventManager from '@joplin/lib/eventManager';
import NoteListUtils from '../utils/NoteListUtils';
import { _ } from '@joplin/lib/locale';
import time from '@joplin/lib/time';
import BaseModel, { ModelType } from '@joplin/lib/BaseModel';
@ -16,7 +15,6 @@ import { themeStyle } from '@joplin/lib/theme';
import ItemList from '../ItemList';
const { connect } = require('react-redux');
import Note from '@joplin/lib/models/Note';
import Folder from '@joplin/lib/models/Folder';
import { Props } from './utils/types';
import usePrevious from '../hooks/usePrevious';
import { itemIsReadOnlySync, ItemSlice } from '@joplin/lib/models/utils/readOnly';
@ -67,31 +65,6 @@ const NoteListComponent = (props: Props) => {
return {};
}, []);
const itemContextMenu = useCallback((event: any) => {
const currentItemId = event.currentTarget.getAttribute('data-id');
if (!currentItemId) return;
let noteIds = [];
if (props.selectedNoteIds.indexOf(currentItemId) < 0) {
noteIds = [currentItemId];
} else {
noteIds = props.selectedNoteIds;
}
if (!noteIds.length) return;
const menu = NoteListUtils.makeContextMenu(noteIds, {
notes: props.notes,
dispatch: props.dispatch,
watchedNoteFiles: props.watchedNoteFiles,
plugins: props.plugins,
inConflictFolder: props.selectedFolderId === Folder.conflictFolderId(),
customCss: props.customCss,
});
menu.popup({ window: bridge().window() });
}, [props.selectedNoteIds, props.notes, props.dispatch, props.watchedNoteFiles, props.plugins, props.selectedFolderId, props.customCss]);
const onGlobalDrop_ = () => {
unregisterGlobalDragEndEvent_();
setDragOverTargetNoteIndex(null);
@ -228,7 +201,7 @@ const NoteListComponent = (props: Props) => {
onDragStart={noteItem_dragStart}
onNoteDragOver={noteItem_noteDragOver}
onTitleClick={() => {}}
onContextMenu={itemContextMenu}
onContextMenu={() => {}}
draggable={!props.parentFolderIsReadOnly}
/>;
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied

View File

@ -1,13 +1,13 @@
import { FolderEntity, ItemRendererDatabaseDependency, NoteEntity } from '@joplin/lib/services/database/types';
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
import { Size } from '@joplin/utils/types';
import { Dispatch } from 'redux';
export interface Props {
themeId: any;
selectedNoteIds: string[];
notes: NoteEntity[];
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
dispatch: Function;
dispatch: Dispatch;
watchedNoteFiles: any[];
plugins: PluginStates;
selectedFolderId: string;

View File

@ -14,6 +14,7 @@ interface NoteItemProps {
noteHtml: string;
style: React.CSSProperties;
itemSize: Size;
onContextMenu: React.MouseEventHandler;
}
const NoteListItem = (props: NoteItemProps) => {
@ -39,7 +40,11 @@ const NoteListItem = (props: NoteItemProps) => {
useItemEventHandlers(rootElement, itemElement, idPrefix, onCheckboxChange);
return <div id={elementId}></div>;
return <div
id={elementId}
data-note-id={props.noteId}
onContextMenu={props.onContextMenu}
></div>;
};
export default NoteListItem;

View File

@ -0,0 +1,44 @@
import Folder from '@joplin/lib/models/Folder';
import { NoteEntity } from '@joplin/lib/services/database/types';
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
import { useCallback } from 'react';
import { Dispatch } from 'redux';
import bridge from '../../../services/bridge';
import NoteListUtils from '../../utils/NoteListUtils';
const useOnContextMenu = (
selectedNoteIds: string[],
selectedFolderId: string,
notes: NoteEntity[],
dispatch: Dispatch,
watchedNoteFiles: string[],
plugins: PluginStates,
customCss: string
) => {
return useCallback((event: any) => {
const currentNoteId = event.currentTarget.getAttribute('data-note-id');
if (!currentNoteId) return;
let noteIds = [];
if (selectedNoteIds.indexOf(currentNoteId) < 0) {
noteIds = [currentNoteId];
} else {
noteIds = selectedNoteIds;
}
if (!noteIds.length) return;
const menu = NoteListUtils.makeContextMenu(noteIds, {
notes: notes,
dispatch: dispatch,
watchedNoteFiles: watchedNoteFiles,
plugins: plugins,
inConflictFolder: selectedFolderId === Folder.conflictFolderId(),
customCss: customCss,
});
menu.popup({ window: bridge().window() });
}, [selectedNoteIds, notes, dispatch, watchedNoteFiles, plugins, selectedFolderId, customCss]);
};
export default useOnContextMenu;

View File

@ -7,19 +7,19 @@ import InteropServiceHelper from '../../InteropServiceHelper';
import { _ } from '@joplin/lib/locale';
import { MenuItemLocation } from '@joplin/lib/services/plugins/api/types';
import { getNoteCallbackUrl } from '@joplin/lib/callbackUrlUtils';
import bridge from '../../services/bridge';
import BaseModel from '@joplin/lib/BaseModel';
const bridge = require('@electron/remote').require('./bridge').default;
const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem;
import Note from '@joplin/lib/models/Note';
import Setting from '@joplin/lib/models/Setting';
const { clipboard } = require('electron');
import { Dispatch } from 'redux';
const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem;
interface ContextMenuProps {
notes: any[];
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
dispatch: Function;
dispatch: Dispatch;
watchedNoteFiles: string[];
plugins: PluginStates;
inConflictFolder: boolean;
@ -45,26 +45,26 @@ export default class NoteListUtils {
if (!hasEncrypted) {
menu.append(
new MenuItem(menuUtils.commandToStatefulMenuItem('setTags', noteIds))
new MenuItem(menuUtils.commandToStatefulMenuItem('setTags', noteIds) as any)
);
menu.append(
new MenuItem(menuUtils.commandToStatefulMenuItem('moveToFolder', noteIds))
new MenuItem(menuUtils.commandToStatefulMenuItem('moveToFolder', noteIds) as any)
);
menu.append(
new MenuItem(menuUtils.commandToStatefulMenuItem('duplicateNote', noteIds))
new MenuItem(menuUtils.commandToStatefulMenuItem('duplicateNote', noteIds) as any)
);
if (singleNoteId) {
const cmd = props.watchedNoteFiles.includes(singleNoteId) ? 'stopExternalEditing' : 'startExternalEditing';
menu.append(new MenuItem(menuUtils.commandToStatefulMenuItem(cmd, singleNoteId)));
menu.append(new MenuItem(menuUtils.commandToStatefulMenuItem(cmd, singleNoteId) as any));
}
if (noteIds.length <= 1) {
menu.append(
new MenuItem(
menuUtils.commandToStatefulMenuItem('toggleNoteType', noteIds)
menuUtils.commandToStatefulMenuItem('toggleNoteType', noteIds) as any
)
);
} else {
@ -125,7 +125,7 @@ export default class NoteListUtils {
if ([9, 10].includes(Setting.value('sync.target'))) {
menu.append(
new MenuItem(
menuUtils.commandToStatefulMenuItem('showShareNoteDialog', noteIds.slice())
menuUtils.commandToStatefulMenuItem('showShareNoteDialog', noteIds.slice()) as any
)
);
}
@ -156,7 +156,7 @@ export default class NoteListUtils {
exportMenu.append(
new MenuItem(
menuUtils.commandToStatefulMenuItem('exportPdf', noteIds)
menuUtils.commandToStatefulMenuItem('exportPdf', noteIds) as any
)
);
@ -167,7 +167,7 @@ export default class NoteListUtils {
menu.append(
new MenuItem(
menuUtils.commandToStatefulMenuItem('deleteNote', noteIds)
menuUtils.commandToStatefulMenuItem('deleteNote', noteIds) as any
)
);
@ -179,7 +179,7 @@ export default class NoteListUtils {
if (cmdService.isEnabled(info.view.commandName)) {
menu.append(
new MenuItem(menuUtils.commandToStatefulMenuItem(info.view.commandName, noteIds))
new MenuItem(menuUtils.commandToStatefulMenuItem(info.view.commandName, noteIds) as any)
);
}
}