diff --git a/assets/base.html b/assets/base.html index b6d7bcd0d..24c188859 100644 --- a/assets/base.html +++ b/assets/base.html @@ -7,8 +7,14 @@ var electron = require('electron') var localLog = console.log var localError = console.error - var remoteLog = electron.remote.getGlobal('console').log - var remoteError = electron.remote.getGlobal('console').error + var remoteLog = function (o) { + const payload = JSON.parse(JSON.stringify(o, null, 2)) + electron.ipcRenderer.invoke('consoleLog', `${payload}`) + } + var remoteError = function (o) { + const payload = JSON.parse(JSON.stringify(o, null, 2)) + electron.ipcRenderer.invoke('consoleError', `${payload}`) + } console.log = function (...args) { localLog.apply(console, args) @@ -20,12 +26,35 @@ remoteError(...args) } - process.exit = electron.remote.app.quit + process.exit = function(status) {electron.ipcRenderer.sendSync('exit')} // redirect errors to stderr window.addEventListener('error', function (e) { e.preventDefault() - console.error(e.error.stack || 'Uncaught ' + e.error) + console.log(e) + console.error(e.error?.stack || 'Uncaught ' + e.error) + }) + + electron.ipcRenderer.once('window-setup', (event, msg) => { + const { + config, + rootPath, + data, + title, + } = msg + var rootView = require(rootPath) + var h = require('mutant/h') + + electron.webFrame.setVisualZoomLevelLimits(1, 1) + + document.documentElement.querySelector('head').appendChild( + h('title', title) + ) + + document.documentElement.replaceChild(h('body', [ + rootView(config, data) + ]), document.body) }) + diff --git a/index.js b/index.js index 1673efa1b..74db8c87e 100644 --- a/index.js +++ b/index.js @@ -150,13 +150,66 @@ electron.app.on('ready', () => { quitting = true }) - electron.ipcMain.on('open-background-devtools', function () { - if (windows.background) { - windows.background.webContents.openDevTools({ mode: 'detach' }) - } + electron.ipcMain.handle('navigation-menu-popup', (event, data) => { + const {items, x, y} = data + const window = event.sender + const factor = event.sender.zoomFactor + const menuItems = buildMenu(items, window) + const menu = electron.Menu.buildFromTemplate(menuItems); + menu.popup({ + window, + x: Math.round(x * factor), + y: Math.round(y * factor) + 4, + }); }) + + electron.ipcMain.handle('consoleLog', (ev, o) => console.log(o)) + electron.ipcMain.handle('consoleError', (ev, o) => console.error(o)) + electron.ipcMain.handle('badgeCount', (ev, count) => { + electron.app.badgeCount = count; + }); + electron.ipcMain.on('exit', (ev, code) => process.exit(code)) + }) +function openServerDevTools () { + if (windows.background) { + windows.background.webContents.openDevTools({ mode: 'detach' }) + } +} + +function buildMenu(items, window) { + const result = [] + for (let item of items) { + switch (item.type) { + case 'separator': + result.push(item) + break + case 'submenu': + result.push({ + ...item, + submenu: buildMenu(item.submenu, window), + }) + break + case 'normal': + result.push({ + ...item, + click: () => navigateTo(item.target) + }) + break + default: + throw Error(`Unknown menu item of type "${item.type}": ${JSON.stringify(item, null, 2)}`); + } + } + return result +} + +function navigateTo(target) { + if (windows?.main) { + windows.main.send('navigate-to', target) + } +} + function openMainWindow () { if (!windows.main) { const windowState = WindowState({ @@ -174,8 +227,11 @@ function openMainWindow () { title: 'Patchwork', show: true, backgroundColor: '#EEE', - icon: Path.join(__dirname, 'assets/icon.png') - }) + icon: Path.join(__dirname, 'assets/icon.png'), + }, + openServerDevTools, + navigateTo, + ) windowState.manage(windows.main) windows.main.setSheetOffset(40) diff --git a/lib/context-menu-and-spellcheck.js b/lib/context-menu-and-spellcheck.js deleted file mode 100644 index a6dd0c410..000000000 --- a/lib/context-menu-and-spellcheck.js +++ /dev/null @@ -1,196 +0,0 @@ -const { remote, shell, clipboard, ipcRenderer } = require('electron') -const { SpellCheckHandler, ContextMenuListener, ContextMenuBuilder } = require('electron-spellchecker') -const { MenuItem, Menu } = remote -const ref = require('ssb-ref') - -let navigateHandler = null -module.exports = setupContextMenuAndSpellCheck - -function setupContextMenuAndSpellCheck (config, { navigate, getMessageText, language }) { - navigateHandler = navigate - const spellCheckHandler = new SpellCheckHandler() - spellCheckHandler.attachToInput() - - // Start off as US English, America #1 (lol) - spellCheckHandler.switchLanguage(language || 'en-US') - - const contextMenuBuilder = new ContextMenuBuilder(spellCheckHandler, null, true, (menu, menuInfo) => { - const ddg = new MenuItem({ - label: 'Search With DuckDuckGo', - click: () => { - const url = `https://duckduckgo.com/?q=${encodeURIComponent(menuInfo.selectionText)}` - shell.openExternal(url) - } - }) - - // There's no menu.remove(id) so this is a convoluted way of removing the - // 'Search with Google' menu item - const oldItems = menu.items - menu.clear() - - oldItems.forEach(oldItem => { - if (oldItem.label === 'Search with Google') { - menu.append(ddg) - } else { - menu.append(oldItem) - } - }) - - if (menuInfo.mediaType !== 'none') { - console.log(menuInfo) - const copyEmbed = new MenuItem({ - label: 'Copy Embed Markdown', - click: () => { - // Omit the mailto: portion of the link; we just want the address - const extractedRef = ref.extract(menuInfo.srcURL) - clipboard.writeText(`![${menuInfo.titleText}](${extractedRef})`) - } - }) - menu.append(copyEmbed) - const openImageInBrowser = new MenuItem({ - label: 'Open Image With Browser', - click: () => { - shell.openExternal(menuInfo.srcURL) - } - }) - menu.append(openImageInBrowser) - } - }) - - contextMenuBuilder.buildMenuForLink = function (menuInfo) { - const element = document.elementFromPoint(menuInfo.x, menuInfo.y) - - const menu = new Menu() - const isEmailAddress = menuInfo.linkURL.startsWith('mailto:') - const isFile = menuInfo.linkURL.startsWith('file:') - - // use the anchor of a link if it directly references an ID - const extractedRef = element && ref.isLink(element.anchor) ? element.anchor : ref.extract(menuInfo.linkURL) - - if (!isFile) { - const copyLink = new MenuItem({ - label: isEmailAddress ? this.stringTable.copyMail() : this.stringTable.copyLinkUrl(), - click: () => { - // Omit the mailto: portion of the link; we just want the address - clipboard.writeText(isEmailAddress ? menuInfo.linkText : menuInfo.linkURL) - } - }) - - const openLink = new MenuItem({ - label: this.stringTable.openLinkUrl(), - click: () => { - shell.openExternal(menuInfo.linkURL) - } - }) - - menu.append(copyLink) - menu.append(openLink) - } - - if (extractedRef) { - if (navigateHandler) { - menu.append(new MenuItem({ - label: 'Find Link References', - click: function () { - navigateHandler('?' + extractedRef) - } - })) - this.addSeparator(menu) - } - const copyRef = new MenuItem({ - label: `Copy Link Ref (${extractedRef.slice(0, 10)}...)`, - click: () => { - // Omit the mailto: portion of the link; we just want the address - clipboard.writeText(extractedRef) - } - }) - menu.append(copyRef) - } - - if (this.isSrcUrlValid(menuInfo)) { - if (!isFile) this.addSeparator(menu) - this.addImageItems(menu, menuInfo) - } - - this.addInspectElement(menu, menuInfo) - this.processMenu(menu, menuInfo) - - return menu - } - - module.exports.menu = new ContextMenuListener((info) => { - contextMenuBuilder.buildMenuForElement(info).then((menu) => { - let element = document.elementFromPoint(info.x, info.y) - while (element && !element.msg) { - element = element.parentNode - } - - menu.append(new MenuItem({ - label: 'Inspect Server Process', - click: function () { - ipcRenderer.send('open-background-devtools') - } - })) - - menu.append(new MenuItem({ - type: 'separator' - })) - - menu.append(new MenuItem({ - label: 'Reload', - click: function (item, focusedWindow) { - if (focusedWindow) { - focusedWindow.reload() - } - } - })) - - if (element && element.msg) { - menu.append(new MenuItem({ - type: 'separator' - })) - menu.append(new MenuItem({ - label: 'Copy Message ID', - click: function () { - clipboard.writeText(element.msg.key) - } - })) - menu.append(new MenuItem({ - label: 'Copy Message Text', - click: function () { - getMessageText(element.msg.key, (err, value) => { - if (!err) { - clipboard.writeText(value) - } else { - showDialog({ - type: 'error', - title: 'Error', - buttons: ['OK'], - message: 'Could not get message text.', - detail: err && err.message - }) - } - }) - } - })) - menu.append(new MenuItem({ - label: 'Copy External Link', - click: function () { - const key = element.msg.key - const gateway = config.gateway || - 'https://viewer.scuttlebot.io' - const url = `${gateway}/${encodeURIComponent(key)}` - clipboard.writeText(url) - } - })) - } - menu.popup(remote.getCurrentWindow()) - }).catch((err) => { - throw err - }) - }) -} - -function showDialog (opts) { - remote.dialog.showMessageBox(remote.getCurrentWindow(), opts) -} diff --git a/lib/context-menu.js b/lib/context-menu.js new file mode 100644 index 000000000..dc0ed91c8 --- /dev/null +++ b/lib/context-menu.js @@ -0,0 +1,247 @@ +const { shell, clipboard } = require('electron') +const { BrowserWindow, ContextMenuParams, ipcMain, MenuItemConstructorOptions, WebContents } = require('electron') +const contextMenu = require('electron-context-menu') +const ref = require('ssb-ref') + +// used to receive out-of-band information about context-menu events +// see below, Ctrl-F "context-menu-info" +var lastClickInfo; + +module.exports = function ( + config, + serverDevToolsCallback, + navigateHandler, + window +) { + ipcMain.handle("context-menu-info", (event, info) => { + lastClickInfo = info; + return true; + }); + contextMenu({ + window, + menu: (defaultActions, parameters, _, dictionarySuggestions) => { + // elementAtPosition(window, parameters.x, parameters.y) + const isFileProtocol = parameters.linkURL.startsWith("file:"); + + // This is very similar to the boilerplate from electron-context-menu even + // though we don't use all the options. Some of the options are disabled + // via "condition && " guards just to clarify where we differ from the + // boilerplate. + // See the original menu structure here: + // https://github.com/sindresorhus/electron-context-menu/blob/621c29a8a133925ac25529e4bea2a738394e8609/index.js#L230 + // We could probably get away with heavy, heavy modification instead of + // menu but this seems more understandable, all things considered + let menuTemplate = [ + dictionarySuggestions.length > 0 && defaultActions.separator(), + ...dictionarySuggestions, + defaultActions.separator(), + + defaultActions.learnSpelling(), + defaultActions.separator(), + + defaultActions.lookUpSelection(), + defaultActions.separator(), + + searchwithDDG(parameters), // instead of defaultActions.searchWithGoogle() + defaultActions.separator(), + + defaultActions.cut(), + defaultActions.copy(), + defaultActions.paste(), + defaultActions.separator(), + + // We typically don't want to copy links, only external ones + copyEmbedMd(parameters), + copyMsgText(window), + // this and the next one might return the same id. Bit redundant but + // only if we right-click on the message timestamp or such + copyMsgKey(), + copyRef(parameters), + copyEmail(parameters), + // We could make our own copyLink() instead which sets + // visible: !isFileProtocol but this is easier + !isFileProtocol && defaultActions.copyLink(), + copyExternalLink(config), + openOnExternalViewer(config), + findRefs(parameters, navigateHandler), + defaultActions.separator(), + + openMediaInBrowser(parameters), + defaultActions.saveImage(), + defaultActions.saveImageAs(), + defaultActions.copyImage(), + defaultActions.copyImageAddress(), + defaultActions.separator(), + + // this could trigger a web request from within patchwork and we don't want that + false && defaultActions.saveLinkAs(), + defaultActions.separator(), + + defaultActions.inspect(), + openServerDevTools(serverDevToolsCallback), + defaultActions.services(), + defaultActions.separator(), + + reloadWindow(), + ]; + + return menuTemplate; + }, + }); +}; + +// Every function below here will produce one MenuItemConstructorOptions object + +function copyMsgKey() { + const msgKey = lastClickInfo?.msg?.key + return { + label: "Copy Message Reference", + visible: !!msgKey, + click: function () { + } + } +} + +function copyMsgText(window) { + const msgKey = lastClickInfo?.msg?.key + return { + label: "Copy Message Text", + visible: !!msgKey, + click: function () { + window.webContents.send('copy-message-text', msgKey) + }, + }; +} + +function openOnExternalViewer(config) { + const msgKey = lastClickInfo?.msg?.key + return { + label: 'Open In Online Viewer', + visible: !!msgKey, + click: function () { + const key = msgKey + const gateway = config.gateway || + 'https://viewer.scuttlebot.io' + const url = `${gateway}/${encodeURIComponent(key)}` + shell.openExternal(url); + } + } +} + +function copyExternalLink(config) { + const msgKey = lastClickInfo?.msg?.key + return { + label: 'Copy External Link', + visible: !!msgKey, + click: function () { + const key = msgKey + const gateway = config.gateway || + 'https://viewer.scuttlebot.io' + const url = `${gateway}/${encodeURIComponent(key)}` + clipboard.writeText(url) + } + } +} + +function findRefs(parameters, navigate) { + const extractedRef = + parameters.mediaType === "none" + ? ref.extract(parameters.linkURL) + : ref.extract(parameters.srcURL); + const usageOrRef = extractedRef && parameters.mediaType === "none" + ? 'References To' + : 'Usages Of' + const label = !!extractedRef + ? `Find ${usageOrRef} ${extractedRef.slice(0, 10).replaceAll("&", "&&&")}...` + : ""; + return { + label, + visible: !!extractedRef, + click: () => { + navigate(`?${extractedRef}`); + }, + }; +} + +function copyRef(parameters) { + const extractedRef = + parameters.mediaType === "none" + ? ref.extract(parameters.linkURL) + : ref.extract(parameters.srcURL); + const label = !!extractedRef + ? `Copy Reference ${extractedRef.slice(0, 10).replaceAll("&", "&&&")}...` + : ""; + return { + label, + visible: !!extractedRef, + click: () => { + clipboard.writeText(extractedRef); + }, + }; +} + +function copyEmail(parameters) { + return { + label: "Copy Email Address", + // FIXME: this fails for "mailto:" links that actually are hand-coded in markdown + // example: Mail me at my [work address](mailto:daan@business.corp) + visible: parameters.linkURL.startsWith("mailto:"), + click: () => { + // Omit the mailto: portion of the link; we just want the address + clipboard.writeText(parameters.linkText); + }, + }; +} + +function copyEmbedMd(parameters) { + return { + label: "Copy Embed Markdown", + visible: parameters.mediaType !== "none", + click: () => { + const extractedRef = ref.extract(parameters.srcURL); + clipboard.writeText(`![${parameters.titleText}](${extractedRef})`); + }, + }; +} + +function openMediaInBrowser(parameters) { + return { + label: "Open With Browser", + visible: parameters.mediaType !== "none", + click: () => { + shell.openExternal(parameters.srcURL); + }, + }; +} + +function searchwithDDG(parameters) { + return { + label: "Search With DuckDuckGo", + // Only show it when right-clicking text + visible: parameters.selectionText.trim().length > 0, + click: () => { + const url = `https://duckduckgo.com/?q=${encodeURIComponent( + parameters.selectionText + )}`; + shell.openExternal(url); + }, + }; +} + +function reloadWindow() { + return { + label: "Reload", + click: function (item, focusedWindow) { + if (focusedWindow) { + focusedWindow.reload(); + } + }, + }; +} + +function openServerDevTools(serverDevToolsCallback) { + return { + label: "Inspect Server Process", + click: serverDevToolsCallback, + }; +} \ No newline at end of file diff --git a/lib/fullscreen.js b/lib/fullscreen.js index 9e7d5ba85..12a921a36 100644 --- a/lib/fullscreen.js +++ b/lib/fullscreen.js @@ -2,12 +2,12 @@ const electron = require('electron') const { Value } = require('mutant') module.exports = function () { - const win = electron.remote.getCurrentWindow() - const isFullScreen = Value(win.isFullScreen()) - win.on('enter-full-screen', () => { + const isFullScreen = Value(false) + // receive the OS window state from the main process + electron.ipcRenderer.on('enter-full-screen', () => { isFullScreen.set(true) }) - win.on('leave-full-screen', () => { + electron.ipcRenderer.on('leave-full-screen', () => { isFullScreen.set(false) }) return isFullScreen diff --git a/lib/main-window.js b/lib/main-window.js index 5022528b9..237813aaa 100644 --- a/lib/main-window.js +++ b/lib/main-window.js @@ -10,7 +10,6 @@ const themes = require('../styles') const nest = require('depnest') const LatestUpdate = require('./latest-update') const ref = require('ssb-ref') -const setupContextMenuAndSpellCheck = require('./context-menu-and-spellcheck') const watch = require('mutant/watch') const requireStyle = require('require-style') const ssbUri = require('ssb-uri') @@ -55,7 +54,6 @@ module.exports = function (config) { const i18n = api.intl.sync.i18n const language = api.settings.obs.get('patchwork.lang', '')() moment.locale(language) - setupContextMenuAndSpellCheck(api.config.sync.load(), { navigate, getMessageText, language }) const id = api.keys.sync.id() const latestUpdate = LatestUpdate() @@ -136,7 +134,7 @@ module.exports = function (config) { const pendingCount = views.get('/mentions').pendingUpdates watch(pendingCount, count => { - electron.remote.app.badgeCount = count + electron.ipcRenderer.invoke('badgeCount', count) }) electron.ipcRenderer.on('goForward', views.goForward) @@ -144,6 +142,43 @@ module.exports = function (config) { electron.ipcRenderer.on('goToSettings', () => api.app.navigate('/settings')) + electron.ipcRenderer.on("navigate-to", (ev, target) => { + navigate(target); + }); + + // context menus are handled on the server. however, we need to know some + // information about the element under the cursor at the time of clicking. + // Sadly, electron doesn't seem to allow us to attach arbitrary information to + // an event and have it be transferred to the server directly. so we need to + // transfer that information "out of band" via sendSync. + // Note that invoke() might cause race conditions here IFF messages can change + // order in the queue between Renderer and Server, or if the IPC and document + // events use different queues. I'm not sure whether that's the case, but I + // haven't observed this happening yet. + document.addEventListener("contextmenu", (ev) => { + let element = document.elementFromPoint(ev.x, ev.y) + while (element && !element.msg) { + element = element.parentNode + } + // we only send the id, because that's cheap + // if the server actually wants to copy the text, it will + // ask us (see "copy-message-text" handler below) + electron.ipcRenderer.invoke("context-menu-info", { + msg: element?.msg || null, + }); + }) + + // for when the server process asks us to please copy a message text to + // clipboard needed for context menu popups, because we want to call the + // getMessage only *if* the text is actually to be copied + electron.ipcRenderer.on("copy-message-text", (ev, key) => { + getMessageText(key, (err, value) => { + electron.clipboard.writeText( + !err ? value : `Error while retrieving message ${key}:\n${err}` + ); + }); + }); + document.head.appendChild( h('style', { innerHTML: computed(api.settings.obs.get('patchwork.theme', 'light'), themeName => { @@ -213,21 +248,7 @@ module.exports = function (config) { h('span.nav', [ tab(i18n('Public'), '/public'), tab(i18n('Private'), '/private'), - dropTab(i18n('More'), [ - getSubscribedChannelMenu, - subMenu(i18n('Participating'), [ - [i18n('All Threads'), '/participating'], - [i18n('Threads Started By You'), '/your-posts'] - ]), - subMenu(i18n('Gatherings'), [ - [i18n('All'), '/gatherings'], - [i18n('Attending'), '/attending-gatherings'] - ]), - [i18n('Tags'), `/tags/all/${encodeURIComponent(id)}`], - [i18n('Extended Network'), '/all'], - { separator: true }, - [i18n('Settings'), '/settings'] - ]) + dropTab(i18n('More')) ]), h('span.appTitle', [ h('span.title', i18n('Patchwork')), @@ -267,78 +288,99 @@ module.exports = function (config) { // scoped - function subMenu (label, items) { - return function () { - return { - label, - submenu: items.map(item => { - return { - label: item[0], - click () { - navigate(item[1]) - } - } - }) - } - } - } - function getSubscribedChannelMenu () { const channels = Array.from(subscribedChannels()).sort(localeCompare) if (channels.length) { return { + type: 'submenu', label: i18n('Channels'), submenu: [ { + type: 'normal', label: i18n('Browse Recently Active'), - click () { - navigate('/channels') - } + target: '/channels' }, { type: 'separator' } - ].concat(channels.map(channel => { - return { - label: `#${channel}`, - click () { - navigate(`#${channel}`) - } - } - })) + ].concat(channels.map(channel => ({ + type: 'normal', + label: `#${channel}`, + target: `#${channel}`, + }))) } } else { return { + type: 'normal', label: i18n('Browse Channels'), - click () { - navigate('/channels') - } + target: '/channels', } } } - function dropTab (title, items) { + function buildDropdownMenuItems() { + const dropTabItems = [ + getSubscribedChannelMenu(), + { + type: 'submenu', + label: i18n("Participating"), + submenu: [ + { + type: "normal", + label: i18n("All Threads"), + target: "/participating", + }, + { + type: "normal", + label: i18n("Threads Started By You"), + target: "/your-posts", + }, + ], + }, + { + type: "submenu", + label: i18n("Gatherings"), + submenu: [ + { + type: "normal", + label: i18n("All"), + target: "/gatherings", + }, + { + type: "normal", + label: i18n("Attending"), + target: "/attending-gatherings", + }, + ], + }, + { + type: "normal", + label: i18n("Tags"), + target: `/tags/all/${encodeURIComponent(id)}`, + }, + { + type: "normal", + label: i18n("Extended Network"), + target: "/all", + }, + { type: "separator" }, + { + type: "normal", + label: i18n("Settings"), + target: "/settings", + }, + ]; + return dropTabItems + } + + function dropTab (title) { const element = h('a -drop', { 'ev-click': () => { + const dropTabItems = buildDropdownMenuItems() const rects = element.getBoundingClientRect() - const factor = electron.remote.getCurrentWindow().webContents.zoomFactor - const menu = electron.remote.Menu.buildFromTemplate(items.map(item => { - if (typeof item === 'function') { - return item() - } else if (item.separator) { - return { type: 'separator' } - } else { - return { - label: item[0], - click () { - navigate(item[1]) - } - } - } - })) - menu.popup({ - window: electron.remote.getCurrentWindow(), - x: Math.round(rects.left * factor), - y: Math.round(rects.bottom * factor) + 4 + electron.ipcRenderer.invoke('navigation-menu-popup', { + x: rects.left, + y: rects.bottom, + items: dropTabItems, }) } }, title) diff --git a/lib/window.js b/lib/window.js index 5d13cf88b..e08d93657 100644 --- a/lib/window.js +++ b/lib/window.js @@ -1,40 +1,34 @@ const Path = require('path') const electron = require('electron') const extend = require('xtend/mutable') +const setupContextMenu = require('./context-menu') -module.exports = function Window (config, path, opts) { +module.exports = function Window (config, path, opts, serverDevToolsCallback, navigateHandler) { const window = new electron.BrowserWindow(extend({ show: false, webPreferences: { - nodeIntegration: true // XXX: Maybe not always necessary (?) + nodeIntegration: true, // XXX: Maybe not always necessary (?) + enableRemoteModule: true, } }, opts)) + // have to forward the OS window state to the renderer because it cannot + // access directly + window.on('enter-full-screen', (event, alwaysOnTop) => { + window.webContents.send("enter-full-screen"); + }) + window.on('leave-full-screen', (event, alwaysOnTop) => { + window.webContents.send("leave-full-screen"); + }) electron.ipcMain.on('ready-to-show', handleReadyToShow) window.webContents.on('dom-ready', function () { - window.webContents.executeJavaScript(` - var electron = require('electron') - var rootView = require(${JSON.stringify(path)}) - var h = require('mutant/h') - - electron.webFrame.setVisualZoomLevelLimits(1, 1) - - var config = ${JSON.stringify(config)} - var data = ${JSON.stringify(opts.data)} - var title = ${JSON.stringify(opts.title || 'Patchwork')} - - document.documentElement.querySelector('head').appendChild( - h('title', title) - ) - - var shouldShow = ${opts.show !== false} - var shouldConnect = ${opts.connect !== false} - - document.documentElement.replaceChild(h('body', [ - rootView(config, data) - ]), document.body) - `) + window.webContents.send('window-setup', { + rootPath: path, + config: config, + data: opts.data || '', + title: opts.title || 'Patchwork', + }) }) // setTimeout(function () { @@ -55,6 +49,16 @@ module.exports = function Window (config, path, opts) { electron.ipcMain.removeListener('ready-to-show', handleReadyToShow) }) + // TODO: better way to determine whether this is the main window ? + if (opts.title === "Patchwork") { + setupContextMenu( + config, + serverDevToolsCallback, + navigateHandler, + window + ); + } + window.loadURL('file://' + Path.join(__dirname, '..', 'assets', 'base.html')) return window diff --git a/package-lock.json b/package-lock.json index a13e8f1f7..92863711b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,26 +10,6 @@ "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==", "dev": true }, - "@aabuhijleh/electron-remote": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@aabuhijleh/electron-remote/-/electron-remote-1.4.0.tgz", - "integrity": "sha512-EG4ZXxqbFY4lpX55vctwz14mFrEOcOHFCMLH5z5lOl6fiviTqscy86tSlKwEE3/o3ExtdPr2tECgCogYYL7d+g==", - "requires": { - "debug": "^2.5.1", - "hashids": "^1.1.1", - "lodash.get": "^4.4.2", - "pify": "^2.3.0", - "rxjs": "^5.0.0-beta.12", - "xmlhttprequest": "^1.8.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -130,9 +110,9 @@ } }, "@electron/get": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.2.tgz", - "integrity": "sha512-vAuHUbfvBQpYTJ5wB7uVIDq5c/Ry0fiTBMs7lnEYAo/qXXppIVcWdfBr57u6eRnKdVso7KSiH6p/LbQAG6Izrg==", + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.4.tgz", + "integrity": "sha512-6nr9DbJPUR9Xujw6zD3y+rS95TyItEVM0NVjt1EehY2vUWfIgPiIPVHxCvaTS0xr2B+DRxovYVKbuOWqC35kjg==", "dev": true, "requires": { "debug": "^4.1.1", @@ -142,17 +122,17 @@ "global-tunnel-ng": "^2.7.1", "got": "^9.6.0", "progress": "^2.0.3", - "sanitize-filename": "^1.6.2", + "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "dependencies": { "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { @@ -213,14 +193,6 @@ } } }, - "@felixrieseberg/spellchecker": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/@felixrieseberg/spellchecker/-/spellchecker-4.0.12.tgz", - "integrity": "sha512-jLAPnRALB1I6Un8ldHVJfJid7m2R1qXoafFF/95sdm7R5VPOsZ3xTreZ/wLKO5x9AdsD2t9zpOcjDFTsCf3VzQ==", - "requires": { - "nan": "^2.14.0" - } - }, "@sammacbeth/random-access-idb-mutable-file": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@sammacbeth/random-access-idb-mutable-file/-/random-access-idb-mutable-file-0.1.1.tgz", @@ -1250,11 +1222,6 @@ "resolved": "https://registry.npmjs.org/bash-color/-/bash-color-0.0.4.tgz", "integrity": "sha1-6b6M4zVAytpIgXaMWb1jhlc26RM=" }, - "bcp47": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/bcp47/-/bcp47-1.1.2.tgz", - "integrity": "sha1-NUvjMH/9CEM6ePXh4glYRfifx/4=" - }, "bencode": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/bencode/-/bencode-1.0.0.tgz", @@ -1368,9 +1335,9 @@ } }, "boolean": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.1.tgz", - "integrity": "sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.2.tgz", + "integrity": "sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g==", "dev": true, "optional": true }, @@ -1915,23 +1882,87 @@ "indexof": "0.0.1" } }, - "cld": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/cld/-/cld-2.5.1.tgz", - "integrity": "sha512-DwdvvcFVizwDdPCocoPPReFk3BwLEaTZ3RzFgJ4jLzsBzJKUC3cTna0ZmAZG4tFtMmQdl0ciso3+ijkH3OPZPA==", - "requires": { - "glob": "^5.0.10", - "nan": "^2.9.2", - "rimraf": "^2.4.0", - "underscore": "^1.6.0" - } - }, "cli-boxes": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", "dev": true }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -2694,9 +2725,9 @@ } }, "electron": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/electron/-/electron-8.5.5.tgz", - "integrity": "sha512-e355H+tRDial0m+X2v+l+0SnaATAPw4sNjv9qmdk/6MJz/glteVJwVJEnxTjPfEELIJSChrBWDBVpjdDvoBF4Q==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-11.3.0.tgz", + "integrity": "sha512-MhdS0gok3wZBTscLBbYrOhLaQybCSAfkupazbK1dMP5c+84eVMxJE/QGohiWQkzs0tVFIJsAHyN19YKPbelNrQ==", "dev": true, "requires": { "@electron/get": "^1.0.1", @@ -2705,9 +2736,9 @@ }, "dependencies": { "@types/node": { - "version": "12.19.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.14.tgz", - "integrity": "sha512-2U9uLN46+7dv9PiS8VQJcHhuoOjiDPZOLAt0WuA1EanEknIMae+2QbMhayF7cgGqjvRVIfNpt+6jLPczJZFiRw==", + "version": "12.20.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.4.tgz", + "integrity": "sha512-xRCgeE0Q4pT5UZ189TJ3SpYuX/QGl6QIAOAIeDSbAVAd2gX1NxSZup4jNVK7cxIeP8KDSbJgcckun495isP1jQ==", "dev": true } } @@ -2821,11 +2852,36 @@ } } }, + "electron-context-menu": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-2.5.0.tgz", + "integrity": "sha512-kzvp8XUmbp2TG2hELJUl7Yjlq4Ag549JQu/C8mxvy1CmAU15UFmPC3bPdXMGE/e3xbi97shgxfttxeQ/6h4MoQ==", + "requires": { + "cli-truncate": "^2.1.0", + "electron-dl": "^3.1.0", + "electron-is-dev": "^1.2.0" + } + }, "electron-default-menu": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/electron-default-menu/-/electron-default-menu-1.0.2.tgz", "integrity": "sha512-YAL/UNR3kPG58wOOlmDpTG3i6+bzwhHx6NllIOaLuVrU7uYifeYGGdk5IH2Hap4wVEx2YTA8cqQ2PGSplYwDWQ==" }, + "electron-dl": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-3.2.0.tgz", + "integrity": "sha512-Wz6YZi0fwy/hmdkrtrBwj7W4JlrFd1tY5jvNdLHd0PUTlJFJ6pGi9mPQGtZRdjodkXYpaiD1uio+wh01hqrZNg==", + "requires": { + "ext-name": "^5.0.0", + "pupa": "^2.0.1", + "unused-filename": "^2.1.0" + } + }, + "electron-is-dev": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz", + "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==" + }, "electron-publish": { "version": "22.9.1", "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.9.1.tgz", @@ -2935,40 +2991,6 @@ } } }, - "electron-spellchecker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/electron-spellchecker/-/electron-spellchecker-2.2.1.tgz", - "integrity": "sha512-IqxJmYq/5qyTNo9ONxHr9D/9UxiXVvDbl01s2f71S3aAHtDIc7I7qqEycvNUlFGR1WVBgFc/VzV4+deQwxgikA==", - "requires": { - "@aabuhijleh/electron-remote": "^1.4.0", - "@felixrieseberg/spellchecker": "^4.0.12", - "bcp47": "^1.1.2", - "cld": "^2.5.1", - "debug": "^4.1.1", - "keyboard-layout": "^2.0.16", - "lru-cache": "^5.1.1", - "mkdirp": "^0.5.1", - "pify": "^4.0.1", - "rxjs": "^5.0.1", - "rxjs-serial-subscription": "^0.1.1", - "spawn-rx": "^2.0.7" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, "electron-window-state": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/electron-window-state/-/electron-window-state-5.0.3.tgz", @@ -3246,8 +3268,7 @@ "escape-goat": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" }, "escape-html": { "version": "1.0.3", @@ -3800,11 +3821,6 @@ "es5-ext": "~0.10.14" } }, - "event-kit": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.3.tgz", - "integrity": "sha512-b7Qi1JNzY4BfAYfnIRanLk0DOD1gdkWHT4GISIn8Q2tAf3LpU8SP2CMwWaq40imYoKWbtN4ZhbSRxvsnikooZQ==" - }, "execa": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/execa/-/execa-0.5.1.tgz", @@ -3861,6 +3877,23 @@ "vary": "~1.1.2" } }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, "extract-zip": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", @@ -4450,18 +4483,6 @@ "pinkie-promise": "^2.0.0" } }, - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, "glob-parent": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", @@ -4488,18 +4509,21 @@ }, "dependencies": { "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", - "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.9.0.tgz", + "integrity": "sha512-PyFBJaLq93FlyYdsndE5VaueA9K5cNB7CGzeCj191YYLhkQM0gdZR2SKihM70oF0wdqKSKClv/tEBOpoRmdOVQ==", "dev": true, "optional": true }, "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "dev": true, - "optional": true + "optional": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -4531,9 +4555,9 @@ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" }, "globalthis": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz", - "integrity": "sha512-mJPRTc/P39NH/iNG4mXa9aIhNymaQikTrnspeCa2ZuJ+mH2QN/rXwtX3XwKrHqWgUQFbNZKtHM105aHzJalElw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz", + "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==", "dev": true, "optional": true, "requires": { @@ -4623,11 +4647,6 @@ "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", "dev": true }, - "hashids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/hashids/-/hashids-1.2.2.tgz", - "integrity": "sha512-dEHCG2LraR6PNvSGxosZHIRgxF5sNLOIBFEHbj8lfP9WWmu/PWPMzsip1drdVSOFi51N2pU7gZavrgn7sbGFuw==" - }, "hashlru": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz", @@ -5102,6 +5121,11 @@ "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", "dev": true }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, "is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", @@ -5545,15 +5569,6 @@ } } }, - "keyboard-layout": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/keyboard-layout/-/keyboard-layout-2.0.16.tgz", - "integrity": "sha512-eGrxmlV6jbm/mbPEOpYGuH53XEC7wIUj9ZxKcT2z9QHJ/RwrT9iVkvxka9zRxqHZHwQzcffgsa5OxoVAKnhK9w==", - "requires": { - "event-kit": "^2.0.0", - "nan": "^2.13.2" - } - }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -5796,11 +5811,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" - }, "lodash.concat": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.concat/-/lodash.concat-4.5.0.tgz", @@ -5883,11 +5893,13 @@ } }, "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "optional": true, "requires": { - "yallist": "^3.0.2" + "yallist": "^4.0.0" } }, "ltgt": { @@ -5965,15 +5977,6 @@ "optional": true, "requires": { "escape-string-regexp": "^4.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "optional": true - } } }, "math-interval-parser": { @@ -6113,6 +6116,11 @@ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, + "modify-filename": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/modify-filename/-/modify-filename-1.1.0.tgz", + "integrity": "sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE=" + }, "moment": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", @@ -6361,11 +6369,6 @@ "zerr": "^1.0.4" } }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" - }, "napi-macros": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", @@ -7116,7 +7119,8 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true }, "pinkie": { "version": "2.0.4", @@ -7890,7 +7894,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, "requires": { "escape-goat": "^2.0.0" } @@ -8435,13 +8438,13 @@ "integrity": "sha1-30PoDZvIKtRDC8/vA/SccX6LLow=" }, "roarr": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.3.tgz", - "integrity": "sha512-AEjYvmAhlyxOeB9OqPUzQCo3kuAkNfuDk/HqWbZdFsqDFpapkTjiw+p4svNEoRLvuqNTxqfL+s+gtD4eDgZ+CA==", + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", "dev": true, "optional": true, "requires": { - "boolean": "^3.0.0", + "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", @@ -8472,22 +8475,6 @@ "resolved": "https://registry.npmjs.org/rwlock/-/rwlock-5.0.0.tgz", "integrity": "sha1-iI1qd6M1HMGiCSBO8u4XIgk4Ns8=" }, - "rxjs": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", - "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", - "requires": { - "symbol-observable": "1.0.1" - } - }, - "rxjs-serial-subscription": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/rxjs-serial-subscription/-/rxjs-serial-subscription-0.1.1.tgz", - "integrity": "sha1-pCsdsL8QlLCSMRkeJ3jKP8+e0Uc=", - "requires": { - "rxjs": "^5.0.0-beta.12" - } - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -8928,6 +8915,22 @@ } } }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", + "requires": { + "sort-keys": "^1.0.0" + } + }, "sorted-array-functions": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz", @@ -8951,16 +8954,6 @@ "resolved": "https://registry.npmjs.org/spacetime/-/spacetime-6.13.0.tgz", "integrity": "sha512-gHOtAjPG2e2VK7o9yNevMrj9oJcACrazTI6pER97PfPF2Vdmp10aJPYc0QnrPmB6zHFJtbVboPk296rIICi0lw==" }, - "spawn-rx": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-2.0.12.tgz", - "integrity": "sha512-gOPXiQQFQ9lTOLuys0iMn3jfxxv9c7zzwhbYLOEbQGvEShHVJ5sSR1oD3Daj88os7jKArDYT7rbOKdvNhe7iEg==", - "requires": { - "debug": "^2.5.1", - "lodash.assign": "^4.2.0", - "rxjs": "^5.1.1" - } - }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", @@ -10756,12 +10749,12 @@ }, "dependencies": { "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { @@ -10777,11 +10770,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" - }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -11092,11 +11080,6 @@ "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" }, - "underscore": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", - "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" - }, "unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", @@ -11122,6 +11105,22 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "unused-filename": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-2.1.0.tgz", + "integrity": "sha512-BMiNwJbuWmqCpAM1FqxCTD7lXF97AvfQC8Kr/DIeA6VtvhJaMDupZ82+inbjl5yVP44PcxOuCSxye1QMS0wZyg==", + "requires": { + "modify-filename": "^1.1.0", + "path-exists": "^4.0.0" + }, + "dependencies": { + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + } + } + }, "update-notifier": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", @@ -11603,11 +11602,6 @@ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, - "xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" - }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -11620,9 +11614,11 @@ "dev": true }, "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "optional": true }, "yargs": { "version": "16.2.0", diff --git a/package.json b/package.json index 8b22fcadf..46f701fab 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,8 @@ "deep-equal": "^2.0.1", "depject": "^4.1.1", "depnest": "^1.3.0", + "electron-context-menu": "^2.5.0", "electron-default-menu": "~1.0.1", - "electron-spellchecker": "^2.2.1", "electron-window-state": "^5.0.3", "escape-string-regexp": "^4.0.0", "fix-path": "^3.0.0", @@ -104,7 +104,7 @@ "devDependencies": { "changelog-version": "^2.0.0", "colors": "^1.3.3", - "electron": "^8.5.5", + "electron": "^11.3.0", "electron-builder": "^22.9.1", "standard": "^16.0.3" },