diff --git a/.eslintignore b/.eslintignore index da10fab99..226d664c8 100644 --- a/.eslintignore +++ b/.eslintignore @@ -221,6 +221,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js +packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js packages/app-desktop/gui/NoteEditor/NoteEditor.js diff --git a/.gitignore b/.gitignore index 8bbb1ed7a..8cc1ac940 100644 --- a/.gitignore +++ b/.gitignore @@ -209,6 +209,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js +packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js packages/app-desktop/gui/NoteEditor/NoteEditor.js diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx index fefec1a3b..796f714d6 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx @@ -24,6 +24,7 @@ import { MarkupToHtmlOptions } from '../../utils/useMarkupToHtml'; import { themeStyle } from '@joplin/lib/theme'; import { loadScript } from '../../../utils/loadScript'; import bridge from '../../../../services/bridge'; +import { TinyMceEditorEvents } from './utils/types'; const { clipboard } = require('electron'); const supportedLocales = require('./supportedLocales'); @@ -169,7 +170,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { const nodeName = event.target ? event.target.nodeName : ''; if (nodeName === 'INPUT' && event.target.getAttribute('type') === 'checkbox') { - editor.fire('joplinChange'); + editor.fire(TinyMceEditorEvents.JoplinChange); dispatchDidUpdate(editor); } @@ -261,7 +262,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { }, replaceSelection: (value: any) => { editor.selection.setContent(value); - editor.fire('joplinChange'); + editor.fire(TinyMceEditorEvents.JoplinChange); dispatchDidUpdate(editor); // It doesn't make sense but it seems calling setContent @@ -270,7 +271,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { // https://github.com/tinymce/tinymce/issues/3745 window.requestAnimationFrame(() => editor.undoManager.add()); }, - pasteAsText: () => editor.fire('pasteAsText'), + pasteAsText: () => editor.fire(TinyMceEditorEvents.PasteAsText), }; if (additionalCommands[cmd.name]) { @@ -674,7 +675,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { editor.on('ObjectResized', function(event: any) { if (event.target.nodeName === 'IMG') { - editor.fire('joplinChange'); + editor.fire(TinyMceEditorEvents.JoplinChange); dispatchDidUpdate(editor); } }); @@ -1085,35 +1086,35 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { await onPaste(createSyntheticClipboardEventWithoutHTML()); } - editor.on('keyup', onKeyUp); - editor.on('keydown', onKeyDown); - editor.on('keypress', onKeypress); - editor.on('paste', onPaste); - editor.on('pasteAsText', onPasteAsText); - editor.on('copy', onCopy); + editor.on(TinyMceEditorEvents.KeyUp, onKeyUp); + editor.on(TinyMceEditorEvents.KeyDown, onKeyDown); + editor.on(TinyMceEditorEvents.KeyPress, onKeypress); + editor.on(TinyMceEditorEvents.Paste, onPaste); + editor.on(TinyMceEditorEvents.PasteAsText, onPasteAsText); + editor.on(TinyMceEditorEvents.Copy, onCopy); // `compositionend` means that a user has finished entering a Chinese // (or other languages that require IME) character. - editor.on('compositionend', onChangeHandler); - editor.on('cut', onCut); - editor.on('joplinChange', onChangeHandler); - editor.on('Undo', onChangeHandler); - editor.on('Redo', onChangeHandler); - editor.on('ExecCommand', onExecCommand); + editor.on(TinyMceEditorEvents.CompositionEnd, onChangeHandler); + editor.on(TinyMceEditorEvents.Cut, onCut); + editor.on(TinyMceEditorEvents.JoplinChange, onChangeHandler); + editor.on(TinyMceEditorEvents.Undo, onChangeHandler); + editor.on(TinyMceEditorEvents.Redo, onChangeHandler); + editor.on(TinyMceEditorEvents.ExecCommand, onExecCommand); return () => { try { - editor.off('keyup', onKeyUp); - editor.off('keydown', onKeyDown); - editor.off('keypress', onKeypress); - editor.off('paste', onPaste); - editor.off('pasteAsText', onPasteAsText); - editor.off('copy', onCopy); - editor.off('compositionend', onChangeHandler); - editor.off('cut', onCut); - editor.off('joplinChange', onChangeHandler); - editor.off('Undo', onChangeHandler); - editor.off('Redo', onChangeHandler); - editor.off('ExecCommand', onExecCommand); + editor.off(TinyMceEditorEvents.KeyUp, onKeyUp); + editor.off(TinyMceEditorEvents.KeyDown, onKeyDown); + editor.off(TinyMceEditorEvents.KeyPress, onKeypress); + editor.off(TinyMceEditorEvents.Paste, onPaste); + editor.off(TinyMceEditorEvents.PasteAsText, onPasteAsText); + editor.off(TinyMceEditorEvents.Copy, onCopy); + editor.off(TinyMceEditorEvents.CompositionEnd, onChangeHandler); + editor.off(TinyMceEditorEvents.Cut, onCut); + editor.off(TinyMceEditorEvents.JoplinChange, onChangeHandler); + editor.off(TinyMceEditorEvents.Undo, onChangeHandler); + editor.off(TinyMceEditorEvents.Redo, onChangeHandler); + editor.off(TinyMceEditorEvents.ExecCommand, onExecCommand); } catch (error) { console.warn('Error removing events', error); } diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.ts index 6b1bf604b..cb286d124 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.ts @@ -1,5 +1,6 @@ import { _ } from '@joplin/lib/locale'; import { MarkupToHtml } from '@joplin/renderer'; +import { TinyMceEditorEvents } from './types'; const taboverride = require('taboverride'); interface SourceInfo { @@ -102,7 +103,7 @@ export default function openEditDialog(editor: any, markupToHtml: any, dispatchD } dialogApi.close(); - editor.fire('joplinChange'); + editor.fire(TinyMceEditorEvents.JoplinChange); dispatchDidUpdate(editor); }, onClose: () => { diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.ts new file mode 100644 index 000000000..b52af6ac9 --- /dev/null +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.ts @@ -0,0 +1,15 @@ +// eslint-disable-next-line import/prefer-default-export +export enum TinyMceEditorEvents { + KeyUp = 'keyup', + KeyDown = 'keydown', + KeyPress = 'keypress', + Paste = 'paste', + PasteAsText = 'pasteAsText', + Copy = 'copy', + CompositionEnd = 'compositionend', + Cut = 'cut', + JoplinChange = 'joplinChange', + Undo = 'Undo', + Redo = 'Redo', + ExecCommand = 'ExecCommand', +} diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts index 6ccae1aba..45c18f4d9 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts @@ -11,6 +11,7 @@ import convertToScreenCoordinates from '../../../../utils/convertToScreenCoordin import Setting from '@joplin/lib/models/Setting'; import Resource from '@joplin/lib/models/Resource'; +import { TinyMceEditorEvents } from './types'; const menuUtils = new MenuUtils(CommandService.instance()); @@ -77,6 +78,9 @@ export default function(editor: any, plugins: PluginStates, dispatch: Function) editor.insertContent(content); }, isReadOnly: false, + fireEditorEvent: (event: TinyMceEditorEvents) => { + editor.fire(event); + }, }; let template = []; diff --git a/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts b/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts index 2a2f904ad..f7abdfb2c 100644 --- a/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts @@ -10,6 +10,7 @@ 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'; +import { TinyMceEditorEvents } from '../NoteBody/TinyMCE/utils/types'; const fs = require('fs-extra'); const { writeFile } = require('fs-extra'); const { clipboard } = require('electron'); @@ -176,6 +177,13 @@ export function menuItems(dispatch: Function): ContextMenuItems { }, isActive: (_itemType: ContextMenuItemType, options: ContextMenuOptions) => !options.isReadOnly && (!!clipboard.readText() || !!clipboard.readHTML()), }, + pasteAsText: { + label: _('Paste as text'), + onAction: async (options: ContextMenuOptions) => { + options.fireEditorEvent(TinyMceEditorEvents.PasteAsText); + }, + isActive: (_itemType: ContextMenuItemType, options: ContextMenuOptions) => !options.isReadOnly && (!!clipboard.readText() || !!clipboard.readHTML()), + }, copyLinkUrl: { label: _('Copy Link Address'), onAction: async (options: ContextMenuOptions) => { diff --git a/packages/app-desktop/gui/NoteEditor/utils/contextMenuUtils.ts b/packages/app-desktop/gui/NoteEditor/utils/contextMenuUtils.ts index 2202bd558..45babce72 100644 --- a/packages/app-desktop/gui/NoteEditor/utils/contextMenuUtils.ts +++ b/packages/app-desktop/gui/NoteEditor/utils/contextMenuUtils.ts @@ -19,6 +19,7 @@ export interface ContextMenuOptions { htmlToCopy: string; insertContent: Function; isReadOnly?: boolean; + fireEditorEvent: Function; } export interface ContextMenuItem { diff --git a/packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.ts b/packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.ts index e16adbdb9..472cd0253 100644 --- a/packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.ts +++ b/packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.ts @@ -41,6 +41,7 @@ export default function useMessageHandler(scrollWhenReady: any, setScrollWhenRea linkToCopy: arg0.linkToCopy || null, htmlToCopy: '', insertContent: () => { console.warn('insertContent() not implemented'); }, + fireEditorEvent: () => { console.warn('fireEditorEvent() not implemented'); }, }, dispatch); menu.popup(bridge().window()); diff --git a/packages/app-desktop/gui/PdfViewer.tsx b/packages/app-desktop/gui/PdfViewer.tsx index d52d10f15..42f26eccd 100644 --- a/packages/app-desktop/gui/PdfViewer.tsx +++ b/packages/app-desktop/gui/PdfViewer.tsx @@ -59,6 +59,7 @@ export default function PdfViewer(props: Props) { linkToCopy: null, htmlToCopy: '', insertContent: () => { console.warn('insertContent() not implemented'); }, + fireEditorEvent: () => { console.warn('fireEditorEvent() not implemented'); }, } as ContextMenuOptions, props.dispatch); menu.popup(bridge().window());