diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 1abd15a9..59782e08 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -20,7 +20,7 @@ import styles from '../components/CodeEditor.styl' const { ipcRenderer, remote, clipboard } = require('electron') import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily' const spellcheck = require('browser/lib/spellcheck') -const buildEditorContextMenu = require('browser/lib/contextMenuBuilder') +const buildEditorContextMenu = require('browser/lib/contextMenuBuilder').buildEditorContextMenu import TurndownService from 'turndown' import {languageMaps} from '../lib/CMLanguageList' import snippetManager from '../lib/SnippetManager' diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index bb663c5e..a407651e 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -18,15 +18,13 @@ import mdurl from 'mdurl' import exportNote from 'browser/main/lib/dataApi/exportNote' import { escapeHtmlCharacters } from 'browser/lib/utils' import yaml from 'js-yaml' -import context from 'browser/lib/context' -import i18n from 'browser/lib/i18n' -import fs from 'fs' import { render } from 'react-dom' import Carousel from 'react-image-carousel' import ConfigManager from '../main/lib/ConfigManager' const { remote, shell } = require('electron') const attachmentManagement = require('../main/lib/dataApi/attachmentManagement') +const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder').buildMarkdownPreviewContextMenu const { app } = remote const path = require('path') @@ -34,8 +32,6 @@ const fileUrl = require('file-url') const dialog = remote.dialog -const uri2path = require('file-uri-to-path') - const markdownStyle = require('!!css!stylus?sourceMap!./markdown.styl')[0][1] const appPath = fileUrl( process.env.NODE_ENV === 'production' ? app.getAppPath() : path.resolve() @@ -249,30 +245,9 @@ export default class MarkdownPreview extends React.Component { } handleContextMenu (event) { - // If a contextMenu handler was passed to us, use it instead of the self-defined one -> return - if (_.isFunction(this.props.onContextMenu)) { - this.props.onContextMenu(event) - return - } - // No contextMenu was passed to us -> execute our own link-opener - if (event.target.tagName.toLowerCase() === 'a' && event.target.getAttribute('href')) { - const href = event.target.href - const isLocalFile = href.startsWith('file:') - if (isLocalFile) { - const absPath = uri2path(href) - try { - if (fs.lstatSync(absPath).isFile()) { - context.popup([ - { - label: i18n.__('Show in explorer'), - click: (e) => shell.showItemInFolder(absPath) - } - ]) - } - } catch (e) { - console.log('Error while evaluating if the file is locally available', e) - } - } + const menu = buildMarkdownPreviewContextMenu(this, event) + if (menu != null) { + setTimeout(() => menu.popup(remote.getCurrentWindow()), 30) } } diff --git a/browser/lib/contextMenuBuilder.js b/browser/lib/contextMenuBuilder.js index cf92f52e..c46f0dc4 100644 --- a/browser/lib/contextMenuBuilder.js +++ b/browser/lib/contextMenuBuilder.js @@ -1,6 +1,12 @@ +import i18n from 'browser/lib/i18n' +import fs from 'fs' + const {remote} = require('electron') const {Menu} = remote.require('electron') +const {clipboard} = remote.require('electron') +const {shell} = remote.require('electron') const spellcheck = require('./spellcheck') +const uri2path = require('file-uri-to-path') /** * Creates the context menu that is shown when there is a right click in the editor of a (not-snippet) note. @@ -62,4 +68,61 @@ const buildEditorContextMenu = function (editor, event) { return Menu.buildFromTemplate(template) } -module.exports = buildEditorContextMenu +/** + * Creates the context menu that is shown when there is a right click Markdown preview of a (not-snippet) note. + * @param {MarkdownPreview} markdownPreview + * @param {MouseEvent} event that has triggered the creation of the context menu + * @returns {Electron.Menu} The created electron context menu + */ +const buildMarkdownPreviewContextMenu = function (markdownPreview, event) { + if (markdownPreview == null || event == null || event.pageX == null || event.pageY == null) { + return null + } + + // Default context menu inclusions + const template = [{ + role: 'cut' + }, { + role: 'copy' + }, { + role: 'paste' + }, { + role: 'selectall' + }] + + if (event.target.tagName.toLowerCase() === 'a' && event.target.getAttribute('href')) { + // Link opener for files on the local system pointed to by href + const href = event.target.href + const isLocalFile = href.startsWith('file:') + if (isLocalFile) { + const absPath = uri2path(href) + try { + if (fs.lstatSync(absPath).isFile()) { + template.push( + { + label: i18n.__('Show in explorer'), + click: (e) => shell.showItemInFolder(absPath) + } + ) + } + } catch (e) { + console.log('Error while evaluating if the file is locally available', e) + } + } + + // Add option to context menu to copy url + template.push( + { + label: i18n.__('Copy Url'), + click: (e) => clipboard.writeText(href) + } + ) + } + return Menu.buildFromTemplate(template) +} + +module.exports = +{ + buildEditorContextMenu: buildEditorContextMenu, + buildMarkdownPreviewContextMenu: buildMarkdownPreviewContextMenu +} diff --git a/tests/lib/contextMenuBuilder.test.js b/tests/lib/contextMenuBuilder.test.js index 12ed2c32..e61d4b73 100644 --- a/tests/lib/contextMenuBuilder.test.js +++ b/tests/lib/contextMenuBuilder.test.js @@ -5,11 +5,13 @@ jest.mock('electron', () => { const spellcheck = require('browser/lib/spellcheck') const buildEditorContextMenu = require('browser/lib/contextMenuBuilder') +const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder') beforeEach(() => { menuBuilderParameter = null }) +// Editor Context Menu it('should make sure that no context menu is build if the passed editor instance was null', function () { const event = { pageX: 12, @@ -124,3 +126,13 @@ it('should make sure that word suggestions creates a correct menu if there was a expect(menuBuilderParameter[7].role).toEqual('selectall') expect(spellcheck.getSpellingSuggestion).toHaveBeenCalledWith(wordToCorrect) }) + +// Markdown Preview Context Menu +it('should make sure that no context menu is built if the Markdown Preview instance was null', function () { + const event = { + pageX: 12, + pageY: 12 + } + buildMarkdownPreviewContextMenu(null, event) + expect(menuBuilderParameter).toEqual(null) +})