You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	| @@ -163,7 +163,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { | ||||
| 	const { scrollToPercent } = useScroll({ editor, onScroll: props.onScroll }); | ||||
|  | ||||
| 	usePluginServiceRegistration(ref); | ||||
| 	useContextMenu(editor, props.plugins); | ||||
| 	useContextMenu(editor, props.plugins, props.dispatch); | ||||
|  | ||||
| 	const dispatchDidUpdate = (editor: any) => { | ||||
| 		if (dispatchDidUpdateIID_) shim.clearTimeout(dispatchDidUpdateIID_); | ||||
|   | ||||
| @@ -39,11 +39,11 @@ interface ContextMenuActionOptions { | ||||
|  | ||||
| const contextMenuActionOptions: ContextMenuActionOptions = { current: null }; | ||||
|  | ||||
| export default function(editor: any, plugins: PluginStates) { | ||||
| export default function(editor: any, plugins: PluginStates, dispatch: Function) { | ||||
| 	useEffect(() => { | ||||
| 		if (!editor) return () => {}; | ||||
|  | ||||
| 		const contextMenuItems = menuItems(); | ||||
| 		const contextMenuItems = menuItems(dispatch); | ||||
|  | ||||
| 		function onContextMenu(_event: any, params: any) { | ||||
| 			const element = contextMenuElement(editor, params.x, params.y); | ||||
| @@ -110,5 +110,5 @@ export default function(editor: any, plugins: PluginStates) { | ||||
| 				bridge().window().webContents.off('context-menu', onContextMenu); | ||||
| 			} | ||||
| 		}; | ||||
| 	}, [editor, plugins]); | ||||
| 	}, [editor, plugins, dispatch]); | ||||
| } | ||||
|   | ||||
| @@ -6,7 +6,10 @@ const bridge = require('electron').remote.require('./bridge').default; | ||||
| const Menu = bridge().Menu; | ||||
| const MenuItem = bridge().MenuItem; | ||||
| import Resource from '@joplin/lib/models/Resource'; | ||||
| import BaseItem from '@joplin/lib/models/BaseItem'; | ||||
| import BaseModel from '@joplin/lib/BaseModel'; | ||||
| import { processPastedHtml } from './resourceHandling'; | ||||
| import { NoteEntity, ResourceEntity } from '@joplin/lib/services/database/types'; | ||||
| const fs = require('fs-extra'); | ||||
| const { clipboard } = require('electron'); | ||||
| const { toSystemSlashes } = require('@joplin/lib/path-utils'); | ||||
| @@ -53,17 +56,50 @@ function handleCopyToClipboard(options: ContextMenuOptions) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export function menuItems(): ContextMenuItems { | ||||
| export async function openItemById(itemId: string, dispatch: Function, hash: string = '') { | ||||
|  | ||||
| 	const item = await BaseItem.loadItemById(itemId); | ||||
|  | ||||
| 	if (!item) throw new Error(`No item with ID ${itemId}`); | ||||
|  | ||||
| 	if (item.type_ === BaseModel.TYPE_RESOURCE) { | ||||
| 		const resource = item as ResourceEntity; | ||||
| 		const localState = await Resource.localState(resource); | ||||
| 		if (localState.fetch_status !== Resource.FETCH_STATUS_DONE || !!resource.encryption_blob_encrypted) { | ||||
| 			if (localState.fetch_status === Resource.FETCH_STATUS_ERROR) { | ||||
| 				bridge().showErrorMessageBox(`${_('There was an error downloading this attachment:')}\n\n${localState.fetch_error}`); | ||||
| 			} else { | ||||
| 				bridge().showErrorMessageBox(_('This attachment is not downloaded or not decrypted yet')); | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		try { | ||||
| 			await ResourceEditWatcher.instance().openAndWatch(resource.id); | ||||
| 		} catch (error) { | ||||
| 			console.error(error); | ||||
| 			bridge().showErrorMessageBox(error.message); | ||||
| 		} | ||||
| 	} else if (item.type_ === BaseModel.TYPE_NOTE) { | ||||
| 		const note = item as NoteEntity; | ||||
|  | ||||
| 		dispatch({ | ||||
| 			type: 'FOLDER_AND_NOTE_SELECT', | ||||
| 			folderId: note.parent_id, | ||||
| 			noteId: note.id, | ||||
| 			hash, | ||||
| 		}); | ||||
| 	} else { | ||||
| 		throw new Error(`Unsupported item type: ${item.type_}`); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export function menuItems(dispatch: Function): ContextMenuItems { | ||||
| 	return { | ||||
| 		open: { | ||||
| 			label: _('Open...'), | ||||
| 			onAction: async (options: ContextMenuOptions) => { | ||||
| 				try { | ||||
| 					await ResourceEditWatcher.instance().openAndWatch(options.resourceId); | ||||
| 				} catch (error) { | ||||
| 					console.error(error); | ||||
| 					bridge().showErrorMessageBox(error.message); | ||||
| 				} | ||||
| 				await openItemById(options.resourceId, dispatch); | ||||
| 			}, | ||||
| 			isActive: (itemType: ContextMenuItemType) => itemType === ContextMenuItemType.Image || itemType === ContextMenuItemType.Resource, | ||||
| 		}, | ||||
| @@ -134,10 +170,10 @@ export function menuItems(): ContextMenuItems { | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| export default async function contextMenu(options: ContextMenuOptions) { | ||||
| export default async function contextMenu(options: ContextMenuOptions, dispatch: Function) { | ||||
| 	const menu = new Menu(); | ||||
|  | ||||
| 	const items = menuItems(); | ||||
| 	const items = menuItems(dispatch); | ||||
|  | ||||
| 	if (!('readyOnly' in options)) options.isReadOnly = true; | ||||
|  | ||||
|   | ||||
| @@ -1,13 +1,9 @@ | ||||
| import { useCallback } from 'react'; | ||||
| import { FormNote } from './types'; | ||||
| import contextMenu from './contextMenu'; | ||||
| import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index'; | ||||
| import contextMenu, { openItemById } from './contextMenu'; | ||||
| import { _ } from '@joplin/lib/locale'; | ||||
| import CommandService from '@joplin/lib/services/CommandService'; | ||||
| import PostMessageService from '@joplin/lib/services/PostMessageService'; | ||||
| import BaseItem from '@joplin/lib/models/BaseItem'; | ||||
| import BaseModel from '@joplin/lib/BaseModel'; | ||||
| import Resource from '@joplin/lib/models/Resource'; | ||||
| const bridge = require('electron').remote.require('./bridge').default; | ||||
| const { urlDecode } = require('@joplin/lib/string-utils'); | ||||
| const urlUtils = require('@joplin/lib/urlUtils'); | ||||
| @@ -46,43 +42,13 @@ export default function useMessageHandler(scrollWhenReady: any, setScrollWhenRea | ||||
| 				linkToCopy: arg0.linkToCopy || null, | ||||
| 				htmlToCopy: '', | ||||
| 				insertContent: () => { console.warn('insertContent() not implemented'); }, | ||||
| 			}); | ||||
| 			}, dispatch); | ||||
|  | ||||
| 			menu.popup(bridge().window()); | ||||
| 		} else if (msg.indexOf('joplin://') === 0) { | ||||
| 			const resourceUrlInfo = urlUtils.parseResourceUrl(msg); | ||||
| 			const itemId = resourceUrlInfo.itemId; | ||||
| 			const item = await BaseItem.loadItemById(itemId); | ||||
| 			const { itemId, hash } = urlUtils.parseResourceUrl(msg); | ||||
| 			await openItemById(itemId, dispatch, hash); | ||||
|  | ||||
| 			if (!item) throw new Error(`No item with ID ${itemId}`); | ||||
|  | ||||
| 			if (item.type_ === BaseModel.TYPE_RESOURCE) { | ||||
| 				const localState = await Resource.localState(item); | ||||
| 				if (localState.fetch_status !== Resource.FETCH_STATUS_DONE || !!item.encryption_blob_encrypted) { | ||||
| 					if (localState.fetch_status === Resource.FETCH_STATUS_ERROR) { | ||||
| 						bridge().showErrorMessageBox(`${_('There was an error downloading this attachment:')}\n\n${localState.fetch_error}`); | ||||
| 					} else { | ||||
| 						bridge().showErrorMessageBox(_('This attachment is not downloaded or not decrypted yet')); | ||||
| 					} | ||||
| 					return; | ||||
| 				} | ||||
|  | ||||
| 				try { | ||||
| 					await ResourceEditWatcher.instance().openAndWatch(item.id); | ||||
| 				} catch (error) { | ||||
| 					console.error(error); | ||||
| 					bridge().showErrorMessageBox(error.message); | ||||
| 				} | ||||
| 			} else if (item.type_ === BaseModel.TYPE_NOTE) { | ||||
| 				dispatch({ | ||||
| 					type: 'FOLDER_AND_NOTE_SELECT', | ||||
| 					folderId: item.parent_id, | ||||
| 					noteId: item.id, | ||||
| 					hash: resourceUrlInfo.hash, | ||||
| 				}); | ||||
| 			} else { | ||||
| 				throw new Error(`Unsupported item type: ${item.type_}`); | ||||
| 			} | ||||
| 		} else if (urlUtils.urlProtocol(msg)) { | ||||
| 			if (msg.indexOf('file://') === 0) { | ||||
| 				// When using the file:// protocol, openPath doesn't work (does nothing) with URL-encoded paths | ||||
|   | ||||
		Reference in New Issue
	
	Block a user