From a674aa977d3e9fbf121fbe648f25edb94d92658a Mon Sep 17 00:00:00 2001 From: vsvipul Date: Thu, 18 Jul 2019 16:45:36 +0530 Subject: [PATCH 01/28] BrowserView: Add View wrapper Class for BrowserView. View extends the BrowserView class in the main process and provides and interface similar to webview. Other functions can be added later when required. --- app/main/view.ts | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 app/main/view.ts diff --git a/app/main/view.ts b/app/main/view.ts new file mode 100644 index 000000000..6358e04d3 --- /dev/null +++ b/app/main/view.ts @@ -0,0 +1,93 @@ +'use strict'; + +import { BrowserView } from 'electron'; + +import ConfigUtil = require('../renderer/js/utils/config-util'); +const shouldSilentWebview = ConfigUtil.getConfigItem('silent'); + +export interface ViewProps { + index: number; + url: string; + name: string; + nodeIntegration: boolean; + preload: boolean; +} + +export class View extends BrowserView { + index: number; + url: string; + zoomFactor: number; + loading: true; + badgeCount: number; + customCSS: boolean; + + constructor(public props: ViewProps) { + super({ + webPreferences: { + preload: props.preload ? `${__dirname}/../renderer/js/preload.js` : '', + nodeIntegration: props.nodeIntegration, + partition: 'persist:view', + plugins: true + } + }); + this.index = props.index; + this.url = props.url; + this.zoomFactor = 1.0; + this.loading = true; + this.badgeCount = 0; + this.customCSS = ConfigUtil.getConfigItem('customCSS'); + this.registerListeners(); + } + + registerListeners(): void { + if (shouldSilentWebview) { + this.webContents.addListener('dom-ready', () => { + this.webContents.setAudioMuted(true); + }); + } + } + + zoomIn(): void { + this.zoomFactor += 0.1; + this.webContents.setZoomFactor(this.zoomFactor); + } + + zoomOut(): void { + this.zoomFactor -= 0.1; + this.webContents.setZoomFactor(this.zoomFactor); + } + + zoomActualSize(): void { + this.zoomFactor = 1.0; + this.webContents.setZoomFactor(this.zoomFactor); + } + + reload(): void { + this.loading = true; + this.webContents.reload(); + } + + forward(): void { + if (this.webContents.canGoForward()) { + this.webContents.goForward(); + } + } + + back(): void { + if (this.webContents.canGoBack()) { + this.webContents.goBack(); + } + } + + logOut(): void { + this.webContents.executeJavaScript('logout()'); + } + + showShortcut(): void { + this.webContents.executeJavaScript('shortcut()'); + } + + toggleDevTools(): void { + this.webContents.toggleDevTools(); + } +} From 6ce25b9a9c0a308f90bb41b4a91d26d5d3efaf1e Mon Sep 17 00:00:00 2001 From: vsvipul Date: Thu, 18 Jul 2019 16:46:45 +0530 Subject: [PATCH 02/28] BrowserView: Add ViewManager for managing multiple Views. Adds ViewManager class which makes it easier to create, manage and delete views. Also, created some basic listeners which will be required later. --- app/main/viewmanager.ts | 128 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 app/main/viewmanager.ts diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts new file mode 100644 index 000000000..7c4ef87f1 --- /dev/null +++ b/app/main/viewmanager.ts @@ -0,0 +1,128 @@ +'use strict'; + +import { BrowserWindow, ipcMain } from 'electron'; +import { View, ViewProps } from './view'; + +import ConfigUtil = require('../renderer/js/utils/config-util'); + +class ViewManager { + views: { [key: number]: View }; + selectedIndex: number; + + constructor() { + this.views = {}; + this.selectedIndex = 0; + this.registerIpcs(); + } + + registerIpcs(): void { + ipcMain.on('view-create', (e: Event, props: ViewProps) => { + this.create(props); + }); + + ipcMain.on('view-select', (e: Event, index: number) => { + this.select(index); + }); + + ipcMain.on('view-destroy', (e: Event, index: number) => { + this.destroy(index); + }); + + ipcMain.on('view-destroy-all', () => { + this.destroyAll(); + }); + + ipcMain.on('forward-message-view', (e: Event, name: string, ...params: any[]) => { + this.views[this.selectedIndex].webContents.send(name, ...params); + }); + + ipcMain.on('forward-message-all', (e: Event, name: string, ...params: any[]) => { + this.forwardMessageAll(name, ...params); + }); + + ipcMain.on('call-view-function', (e: Event, name: string, ...params: any[]) => { + const fn = this.views[this.selectedIndex][name as keyof View]; + if (typeof fn === 'function') { + // Type checking requires spread elements to match up with a rest parameter. + // So, using a workaround here. + (fn as any)(...params); + } + }); + } + + create(props: ViewProps): void { + if (this.views[props.index]) { + return; + } + const view = new View(props); + this.views[props.index] = view; + view.webContents.loadURL(props.url); + } + + select(index: number): void { + const mainWindow = BrowserWindow.getAllWindows()[0]; + const view = this.views[index]; + if (!view || view.isDestroyed()) { + console.log('Attempt to select a view that does not exist.'); + return; + } + this.selectedIndex = index; + if (!view.webContents.getURL()) { + const { url } = view; + view.webContents.loadURL(url); + } + mainWindow.setBrowserView(view); + view.webContents.focus(); + this.fixBounds(); + } + + fixBounds(): void { + const SIDEBAR_WIDTH = 54; + const view = this.views[this.selectedIndex]; + const showSidebar = ConfigUtil.getConfigItem('showSidebar', true); + if (!view || view.isDestroyed()) { + console.log('Attempt to fix bounds for a view that does not exist.'); + return; + } + const mainWindow = BrowserWindow.getAllWindows()[0]; + const { width, height } = mainWindow.getContentBounds(); + + view.setBounds({ + x: showSidebar ? SIDEBAR_WIDTH : 0, + y: 0, + width: showSidebar ? width - SIDEBAR_WIDTH : width, + height + }); + view.setAutoResize({ width: true, height: true }); + } + + destroy(index: number): void { + const mainWindow = BrowserWindow.getAllWindows()[0]; + const view = this.views[index]; + if (!view || view.isDestroyed()) { + console.log('Attempt to delete a view that does not exist.'); + return; + } + if (mainWindow.getBrowserView() === view) { + mainWindow.setBrowserView(null); + } + view.destroy(); + delete this.views[index]; + } + + destroyAll(): void { + const mainWindow = BrowserWindow.getAllWindows()[0]; + mainWindow.setBrowserView(null); + for (const id in this.views) { + this.destroy(this.views[id].index); + } + } + + forwardMessageAll(name: string, ...args: any[]): void { + for (const id in this.views) { + this.views[id].webContents.send(name, ...args); + } + } +} + +export = new ViewManager(); From b87f69730f293f5c338d4cd4833327bf82a596df Mon Sep 17 00:00:00 2001 From: vsvipul Date: Fri, 19 Jul 2019 04:20:10 +0530 Subject: [PATCH 03/28] BrowserView: Add BrowserView to index.ts. --- app/main/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/main/index.ts b/app/main/index.ts index f9fa62611..7c4b51db0 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -14,6 +14,7 @@ import AppMenu = require('./menu'); import BadgeSettings = require('../renderer/js/pages/preference/badge-settings'); import ConfigUtil = require('../renderer/js/utils/config-util'); import ProxyUtil = require('../renderer/js/utils/proxy-util'); +import ViewManager = require('./viewmanager'); interface PatchedGlobal extends NodeJS.Global { mainWindowState: windowStateKeeper.State; @@ -261,6 +262,10 @@ app.on('ready', () => { page.send('toggle-autohide-menubar', showMenubar, true); }); + ipcMain.on('toggle-sidebar', () => { + ViewManager.fixBounds(); + }); + ipcMain.on('update-badge', (_event: Electron.IpcMessageEvent, messageCount: number) => { badgeCount = messageCount; BadgeSettings.updateBadge(badgeCount, mainWindow); @@ -279,7 +284,7 @@ app.on('ready', () => { AppMenu.setMenu(props); const activeTab = props.tabs[props.activeTabIndex]; if (activeTab) { - mainWindow.setTitle(`Zulip - ${activeTab.webview.props.name}`); + mainWindow.setTitle(`Zulip - ${activeTab.props.name}`); } }); From de2752fb82407d33ced9110ec253efd63d57c44e Mon Sep 17 00:00:00 2001 From: vsvipul Date: Fri, 19 Jul 2019 04:29:19 +0530 Subject: [PATCH 04/28] BrowserView: Remove webview props from tab.ts. --- app/renderer/js/components/tab.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/renderer/js/components/tab.ts b/app/renderer/js/components/tab.ts index 04ded25e3..d4131dba1 100644 --- a/app/renderer/js/components/tab.ts +++ b/app/renderer/js/components/tab.ts @@ -1,6 +1,5 @@ 'use strict'; -import WebView = require('./webview'); import BaseComponent = require('./base'); // TODO: TypeScript - Type annotate props @@ -10,13 +9,10 @@ interface TabProps { class Tab extends BaseComponent { props: TabProps; - webview: WebView; $el: Element; constructor(props: TabProps) { super(); - this.props = props; - this.webview = this.props.webview; } registerListeners(): void { @@ -27,17 +23,14 @@ class Tab extends BaseComponent { activate(): void { this.$el.classList.add('active'); - this.webview.load(); } deactivate(): void { this.$el.classList.remove('active'); - this.webview.hide(); } destroy(): void { this.$el.parentNode.removeChild(this.$el); - this.webview.$el.parentNode.removeChild(this.webview.$el); } } From de48c226599a33f0a6775640ca00640b2910ac84 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Sat, 20 Jul 2019 04:39:00 +0530 Subject: [PATCH 05/28] BrowserView: Remove webview usage and initialize BrowserView. Removes all instances of webview from main.ts and adds an initial working instance of BrowserView. --- app/main/index.ts | 2 +- app/main/view.ts | 52 +++++++++++- app/main/viewmanager.ts | 10 +-- app/renderer/js/main.ts | 170 +++++++++++++++++----------------------- 4 files changed, 125 insertions(+), 109 deletions(-) diff --git a/app/main/index.ts b/app/main/index.ts index 7c4b51db0..d7cfce437 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -262,7 +262,7 @@ app.on('ready', () => { page.send('toggle-autohide-menubar', showMenubar, true); }); - ipcMain.on('toggle-sidebar', () => { + ipcMain.on('fix-bounds', () => { ViewManager.fixBounds(); }); diff --git a/app/main/view.ts b/app/main/view.ts index 6358e04d3..e93cfaf65 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -1,6 +1,6 @@ 'use strict'; -import { BrowserView } from 'electron'; +import { BrowserView, BrowserWindow } from 'electron'; import ConfigUtil = require('../renderer/js/utils/config-util'); const shouldSilentWebview = ConfigUtil.getConfigItem('silent'); @@ -17,7 +17,7 @@ export class View extends BrowserView { index: number; url: string; zoomFactor: number; - loading: true; + loading: boolean; badgeCount: number; customCSS: boolean; @@ -33,7 +33,7 @@ export class View extends BrowserView { this.index = props.index; this.url = props.url; this.zoomFactor = 1.0; - this.loading = true; + this.loading = false; this.badgeCount = 0; this.customCSS = ConfigUtil.getConfigItem('customCSS'); this.registerListeners(); @@ -45,6 +45,34 @@ export class View extends BrowserView { this.webContents.setAudioMuted(true); }); } + + this.webContents.addListener('did-navigate-in-page', () => { + const isSettingsPage = this.url.includes('renderer/preference.html'); + if (isSettingsPage) { + return; + } + this.canGoBackButton(); + }); + + this.webContents.addListener('did-navigate', () => { + this.canGoBackButton(); + }); + + this.webContents.addListener('did-start-loading', () => { + const isSettingsPage = this.url.includes('renderer/preference.html'); + if (!isSettingsPage) { + this.sendAction('switch-loading', true, this.url); + } + }); + + this.webContents.addListener('dom-ready', () => { + this.loading = false; + this.sendAction('switch-loading', false, this.url); + }); + + this.webContents.addListener('did-stop-loading', () => { + this.sendAction('switch-loading', false, this.url); + }); } zoomIn(): void { @@ -90,4 +118,22 @@ export class View extends BrowserView { toggleDevTools(): void { this.webContents.toggleDevTools(); } + + canGoBackButton(): void { + if (this.webContents.canGoBack()) { + this.sendAction('switch-back', true); + } else { + this.sendAction('switch-back', false); + } + } + + sendAction(action: any, ...params: any[]): void { + const win = BrowserWindow.getAllWindows()[0]; + + if (process.platform === 'darwin') { + win.restore(); + } + + win.webContents.send(action, ...params); + } } diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index 7c4ef87f1..2d1c445ed 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -41,12 +41,9 @@ class ViewManager { }); ipcMain.on('call-view-function', (e: Event, name: string, ...params: any[]) => { - const fn = this.views[this.selectedIndex][name as keyof View]; - if (typeof fn === 'function') { - // Type checking requires spread elements to match up with a rest parameter. - // So, using a workaround here. - (fn as any)(...params); - } + // Type checking requires spread elements to match up with a rest parameter. + // So, using a workaround here. + (this.views[this.selectedIndex] as any)[name as keyof View](...params); }); } @@ -67,6 +64,7 @@ class ViewManager { return; } this.selectedIndex = index; + mainWindow.setBrowserView(null); if (!view.webContents.getURL()) { const { url } = view; view.webContents.loadURL(url); diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 236e47872..3a73b1c5a 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -12,7 +12,6 @@ const { session, app, Menu, dialog } = remote; require('./tray'); import DomainUtil = require('./utils/domain-util'); -import WebView = require('./components/webview'); import ServerTab = require('./components/server-tab'); import FunctionalTab = require('./components/functional-tab'); import ConfigUtil = require('./utils/config-util'); @@ -163,13 +162,13 @@ class ServerManagerView { const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy'); if (proxyEnabled) { - session.fromPartition('persist:webviewsession').setProxy({ + session.fromPartition('persist:view').setProxy({ pacScript: ConfigUtil.getConfigItem('proxyPAC', ''), proxyRules: ConfigUtil.getConfigItem('proxyRules', ''), proxyBypassRules: ConfigUtil.getConfigItem('proxyBypass', '') }, resolve); } else { - session.fromPartition('persist:webviewsession').setProxy({ + session.fromPartition('persist:view').setProxy({ pacScript: '', proxyRules: '', proxyBypassRules: '' @@ -328,7 +327,6 @@ class ServerManagerView { continue; } DomainUtil.updateSavedServer(servers[i].url, i); - this.tabs[i].webview.load(); } // Remove focus from the settings icon at sidebar bottom this.$settingsButton.classList.remove('active'); @@ -352,30 +350,17 @@ class ServerManagerView { tabIndex, onHover: this.onHover.bind(this, index), onHoverOut: this.onHoverOut.bind(this, index), - webview: new WebView({ - $root: this.$webviewsContainer, - index, - tabIndex, - url: server.url, - role: 'server', - name: CommonUtil.decodeString(server.alias), - isActive: () => { - return index === this.activeTabIndex; - }, - switchLoading: (loading: boolean, url: string) => { - if (!loading && this.loading[url]) { - this.loading[url] = false; - } else if (loading && !this.loading[url]) { - this.loading[url] = true; - } - this.showLoading(this.loading[this.tabs[this.activeTabIndex].webview.props.url]); - }, - onNetworkError: this.openNetworkTroubleshooting.bind(this), - onTitleChange: this.updateBadge.bind(this), - nodeIntegration: false, - preload: true - }) + url: server.url })); + const props = { + index, + url: server.url, + role: 'server', + name: CommonUtil.decodeString(server.alias), + nodeIntegration: false, + preload: true + }; + ipcRenderer.send('view-create', props); this.loading[server.url] = true; } @@ -404,7 +389,7 @@ class ServerManagerView { ipcRenderer.send('forward-message', 'toggle-dnd', dndUtil.dnd, dndUtil.newSettings); }); this.$reloadButton.addEventListener('click', () => { - this.tabs[this.activeTabIndex].webview.reload(); + ipcRenderer.send('call-view-function', 'reload'); }); this.$addServerButton.addEventListener('click', () => { this.openSettings('AddServer'); @@ -413,7 +398,7 @@ class ServerManagerView { this.openSettings('General'); }); this.$backButton.addEventListener('click', () => { - this.tabs[this.activeTabIndex].webview.back(); + ipcRenderer.send('call-view-function', 'back'); }); this.sidebarHoverEvent(this.$addServerButton, this.$addServerTooltip, true); @@ -436,7 +421,7 @@ class ServerManagerView { } getCurrentActiveServer(): string { - return this.tabs[this.activeTabIndex].webview.props.url; + return this.tabs[this.activeTabIndex].props.url; } displayInitialCharLogo($img: HTMLImageElement, index: number): void { @@ -518,31 +503,17 @@ class ServerManagerView { tabIndex, onClick: this.activateTab.bind(this, this.functionalTabs[tabProps.name]), onDestroy: this.destroyTab.bind(this, tabProps.name, this.functionalTabs[tabProps.name]), - webview: new WebView({ - $root: this.$webviewsContainer, - index: this.functionalTabs[tabProps.name], - tabIndex, - url: tabProps.url, - role: 'function', - name: tabProps.name, - isActive: () => { - return this.functionalTabs[tabProps.name] === this.activeTabIndex; - }, - switchLoading: (loading: AnyObject, url: string) => { - if (!loading && this.loading[url]) { - this.loading[url] = false; - } else if (loading && !this.loading[url]) { - this.loading[url] = true; - } - this.showLoading(this.loading[this.tabs[this.activeTabIndex].webview.props.url]); - }, - onNetworkError: this.openNetworkTroubleshooting.bind(this), - onTitleChange: this.updateBadge.bind(this), - nodeIntegration: true, - preload: false - }) + url: tabProps.url })); - + const props = { + index: this.functionalTabs[tabProps.name], + url: tabProps.url, + role: 'function', + name: tabProps.name, + nodeIntegration: true, + preload: false + }; + ipcRenderer.send('view-create', props); // To show loading indicator the first time a functional tab is opened, indicator is // closed when the functional tab DOM is ready, handled in webview.js this.$webviewsContainer.classList.remove('loaded'); @@ -557,7 +528,7 @@ class ServerManagerView { url: `file://${rendererDirectory}/preference.html#${nav}` }); this.$settingsButton.classList.add('active'); - this.tabs[this.functionalTabs.Settings].webview.send('switch-settings-nav', nav); + ipcRenderer.send('forward-message-view', 'switch-settings-nav', nav); } openAbout(): void { @@ -592,10 +563,6 @@ class ServerManagerView { this.tabs.forEach((tab: ServerOrFunctionalTab) => { const proto = Object.create(Object.getPrototypeOf(tab)); const tabClone = Object.assign(proto, tab); - - tabClone.webview = { props: {} }; - tabClone.webview.props.name = tab.webview.props.name; - delete tabClone.props.webview; tabs.push(tabClone); }); @@ -619,16 +586,11 @@ class ServerManagerView { } } - try { - this.tabs[index].webview.canGoBackButton(); - } catch (err) { - } - this.activeTabIndex = index; this.tabs[index].activate(); - - this.showLoading(this.loading[this.tabs[this.activeTabIndex].webview.props.url]); - + ipcRenderer.send('view-select', index); + this.showLoading(this.loading[this.tabs[this.activeTabIndex].props.url]); + ipcRenderer.send('call-view-function', 'canGoBackButton'); ipcRenderer.send('update-menu', { // JSON stringify this.tabs to avoid a crash // util.inspect is being used to handle circular references @@ -650,10 +612,6 @@ class ServerManagerView { } destroyTab(name: string, index: number): void { - if (this.tabs[index].webview.loading) { - return; - } - this.tabs[index].destroy(); delete this.tabs[index]; @@ -669,6 +627,8 @@ class ServerManagerView { // Show loading indicator this.$webviewsContainer.classList.remove('loaded'); + ipcRenderer.send('view-destroy-all'); + // Clear global variables this.activeTabIndex = -1; this.tabs = []; @@ -697,25 +657,19 @@ class ServerManagerView { } updateBadge(): void { - let messageCountAll = 0; - for (const tab of this.tabs) { - if (tab && tab instanceof ServerTab && tab.updateBadge) { - const count = tab.webview.badgeCount; - messageCountAll += count; - tab.updateBadge(count); - } - } - - ipcRenderer.send('update-badge', messageCountAll); + // let messageCountAll = 0; + // for (const tab of this.tabs) { + // if (tab && tab instanceof ServerTab && tab.updateBadge) { + // const count = tab.webview.badgeCount; + // messageCountAll += count; + // tab.updateBadge(count); + // } + // } + // ipcRenderer.send('update-badge', messageCountAll); } updateGeneralSettings(setting: string, value: any): void { - const selector = 'webview:not([class*=disabled])'; - const webview: Electron.WebviewTag = document.querySelector(selector); - if (webview) { - const webContents = webview.getWebContents(); - webContents.send(setting, value); - } + ipcRenderer.send('forward-message-view', setting, value); } toggleSidebar(show: boolean): void { @@ -724,6 +678,12 @@ class ServerManagerView { } else { this.$sidebar.classList.add('sidebar-hide'); } + this.fixBounds(); + } + + // Fixes bounds for view + fixBounds(): void { + ipcRenderer.send('fix-bounds'); } // Toggles the dnd button icon. @@ -770,9 +730,9 @@ class ServerManagerView { registerIpcs(): void { const webviewListeners: AnyObject = { - 'webview-reload': 'reload', + // 'webview-reload': 'reload', back: 'back', - focus: 'focus', + // focus: 'focus', forward: 'forward', zoomIn: 'zoomIn', zoomOut: 'zoomOut', @@ -784,10 +744,7 @@ class ServerManagerView { for (const key in webviewListeners) { ipcRenderer.on(key, () => { - const activeWebview = this.tabs[this.activeTabIndex].webview; - if (activeWebview) { - activeWebview[webviewListeners[key] as string](); - } + ipcRenderer.send('view-call-function', webviewListeners[key]); }); } @@ -860,18 +817,17 @@ class ServerManagerView { tabs: this.tabsForIpc, activeTabIndex: this.activeTabIndex }); + this.fixBounds(); return; } this.updateGeneralSettings('toggle-menubar-setting', autoHideMenubar); + this.fixBounds(); }); ipcRenderer.on('toggle-dnd', (event: Event, state: boolean, newSettings: SettingsOptions) => { this.toggleDNDButton(state); ipcRenderer.send('forward-message', 'toggle-silent', newSettings.silent); - const selector = 'webview:not([class*=disabled])'; - const webview: Electron.WebviewTag = document.querySelector(selector); - const webContents = webview.getWebContents(); - webContents.send('toggle-dnd', state, newSettings); + ipcRenderer.send('forward-message-view', 'toggle-dnd', state, newSettings); }); ipcRenderer.on('update-realm-name', (event: Event, serverURL: string, realmName: string) => { @@ -882,7 +838,7 @@ class ServerManagerView { const serverTooltips = document.querySelectorAll(serverTooltipSelector); serverTooltips[index].innerHTML = escape(realmName); this.tabs[index].props.name = escape(realmName); - this.tabs[index].webview.props.name = realmName; + // this.tabs[index].webview.props.name = realmName; domain.alias = escape(realmName); DomainUtil.db.push(`/domains[${index}]`, domain, true); @@ -986,7 +942,23 @@ class ServerManagerView { const webviews: NodeListOf = document.querySelectorAll('webview'); webviews.forEach(webview => { webview.send('set-idle'); - }); + }); + + ipcRenderer.on('switch-back', (e: Event, state: boolean) => { + if (state === true) { + this.$backButton.classList.remove('disable'); + } else { + this.$backButton.classList.add('disable'); + } + }); + + ipcRenderer.on('switch-loading', (e: Event, loading: boolean, url: string) => { + if (!loading && this.loading[url]) { + this.loading[url] = false; + } else if (loading && !this.loading[url]) { + this.loading[url] = true; + } + this.showLoading(this.loading[this.tabs[this.activeTabIndex].props.url]); }); } } From 713f9f0a39771b2abe7507ff2c48e8a8826a636e Mon Sep 17 00:00:00 2001 From: vsvipul Date: Mon, 22 Jul 2019 23:48:43 +0530 Subject: [PATCH 06/28] BrowserView: Add logic for badgeCount update. Implements logic for updating badgeCount to show message count in sidebar. --- app/main/view.ts | 12 ++++++++++-- app/renderer/js/main.ts | 25 ++++++++++++++++--------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/app/main/view.ts b/app/main/view.ts index e93cfaf65..4ba88e5eb 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -18,7 +18,6 @@ export class View extends BrowserView { url: string; zoomFactor: number; loading: boolean; - badgeCount: number; customCSS: boolean; constructor(public props: ViewProps) { @@ -34,7 +33,6 @@ export class View extends BrowserView { this.url = props.url; this.zoomFactor = 1.0; this.loading = false; - this.badgeCount = 0; this.customCSS = ConfigUtil.getConfigItem('customCSS'); this.registerListeners(); } @@ -73,6 +71,11 @@ export class View extends BrowserView { this.webContents.addListener('did-stop-loading', () => { this.sendAction('switch-loading', false, this.url); }); + + this.webContents.addListener('page-title-updated', (e: Event, title: string) => { + const badgeCount = this.getBadgeCount(title); + this.sendAction('update-badge-count', badgeCount, this.url); + }); } zoomIn(): void { @@ -127,6 +130,11 @@ export class View extends BrowserView { } } + getBadgeCount(title: string): number { + const messageCountInTitle = (/\((\d+)\)/).exec(title); + return messageCountInTitle ? Number(messageCountInTitle[1]) : 0; + } + sendAction(action: any, ...params: any[]): void { const win = BrowserWindow.getAllWindows()[0]; diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 3a73b1c5a..9e9c59af4 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -90,6 +90,7 @@ class ServerManagerView { $fullscreenPopup: Element; $fullscreenEscapeKey: string; loading: AnyObject; + badgeCounts: AnyObject; activeTabIndex: number; tabs: ServerOrFunctionalTab[]; functionalTabs: AnyObject; @@ -128,6 +129,7 @@ class ServerManagerView { this.$fullscreenPopup.innerHTML = `Press ${this.$fullscreenEscapeKey} to exit full screen`; this.loading = {}; + this.badgeCounts = {}; this.activeTabIndex = -1; this.tabs = []; this.presetOrgs = []; @@ -657,15 +659,15 @@ class ServerManagerView { } updateBadge(): void { - // let messageCountAll = 0; - // for (const tab of this.tabs) { - // if (tab && tab instanceof ServerTab && tab.updateBadge) { - // const count = tab.webview.badgeCount; - // messageCountAll += count; - // tab.updateBadge(count); - // } - // } - // ipcRenderer.send('update-badge', messageCountAll); + let messageCountAll = 0; + for (const tab of this.tabs) { + if (tab && tab instanceof ServerTab && tab.updateBadge) { + const count = this.badgeCounts[tab.props.url]; + messageCountAll += count; + tab.updateBadge(count); + } + } + ipcRenderer.send('update-badge', messageCountAll); } updateGeneralSettings(setting: string, value: any): void { @@ -960,6 +962,11 @@ class ServerManagerView { } this.showLoading(this.loading[this.tabs[this.activeTabIndex].props.url]); }); + + ipcRenderer.on('update-badge-count', (e: Event, count: number, url: string) => { + this.badgeCounts[url] = count; + this.updateBadge(); + }); } } From b58fa6248fb1a18ca1b8b268cc89eafa983010e7 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Tue, 23 Jul 2019 01:01:31 +0530 Subject: [PATCH 07/28] BrowserView: Remove tooltips and use title instead. Removes tooltips that we show for orgs and settings, as these tooltips are no more visible over the BrowserViews, so there is no use of keeping them. Instead, uses title property of HTMLElements, which can be displayed over BrowserViews. --- app/renderer/js/components/server-tab.ts | 3 +- app/renderer/js/main.ts | 71 ++---------------------- app/renderer/main.html | 20 +++---- 3 files changed, 12 insertions(+), 82 deletions(-) diff --git a/app/renderer/js/components/server-tab.ts b/app/renderer/js/components/server-tab.ts index 9ad23fecb..1ab4b671e 100644 --- a/app/renderer/js/components/server-tab.ts +++ b/app/renderer/js/components/server-tab.ts @@ -10,9 +10,8 @@ class ServerTab extends Tab { template(): string { return `
-
-
+
${this.generateShortcutText()}
diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 9e9c59af4..74d309dad 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -79,13 +79,6 @@ class ServerManagerView { $webviewsContainer: Element; $backButton: HTMLButtonElement; $dndButton: HTMLButtonElement; - $addServerTooltip: HTMLElement; - $reloadTooltip: HTMLElement; - $loadingTooltip: HTMLElement; - $settingsTooltip: HTMLElement; - $serverIconTooltip: HTMLCollectionOf; - $backTooltip: HTMLElement; - $dndTooltip: HTMLElement; $sidebar: Element; $fullscreenPopup: Element; $fullscreenEscapeKey: string; @@ -108,20 +101,6 @@ class ServerManagerView { this.$backButton = $actionsContainer.querySelector('#back-action'); this.$dndButton = $actionsContainer.querySelector('#dnd-action'); - this.$addServerTooltip = document.querySelector('#add-server-tooltip'); - this.$reloadTooltip = $actionsContainer.querySelector('#reload-tooltip'); - this.$loadingTooltip = $actionsContainer.querySelector('#loading-tooltip'); - this.$settingsTooltip = $actionsContainer.querySelector('#setting-tooltip'); - - // TODO: This should have been querySelector but the problem is that - // querySelector doesn't return elements not present in dom whereas somehow - // getElementsByClassName does. To fix this we need to call this after this.initTabs - // is called in this.init. - // eslint-disable-next-line unicorn/prefer-query-selector - this.$serverIconTooltip = document.getElementsByClassName('server-tooltip') as HTMLCollectionOf; - this.$backTooltip = $actionsContainer.querySelector('#back-tooltip'); - this.$dndTooltip = $actionsContainer.querySelector('#dnd-tooltip'); - this.$sidebar = document.querySelector('#sidebar'); this.$fullscreenPopup = document.querySelector('#fullscreen-popup'); @@ -350,8 +329,6 @@ class ServerManagerView { onClick: this.activateLastTab.bind(this, index), index, tabIndex, - onHover: this.onHover.bind(this, index), - onHoverOut: this.onHoverOut.bind(this, index), url: server.url })); const props = { @@ -402,13 +379,6 @@ class ServerManagerView { this.$backButton.addEventListener('click', () => { ipcRenderer.send('call-view-function', 'back'); }); - - this.sidebarHoverEvent(this.$addServerButton, this.$addServerTooltip, true); - this.sidebarHoverEvent(this.$loadingIndicator, this.$loadingTooltip); - this.sidebarHoverEvent(this.$settingsButton, this.$settingsTooltip); - this.sidebarHoverEvent(this.$reloadButton, this.$reloadTooltip); - this.sidebarHoverEvent(this.$backButton, this.$backTooltip); - this.sidebarHoverEvent(this.$dndButton, this.$dndTooltip); } initDNDButton(): void { @@ -454,38 +424,6 @@ class ServerManagerView { this.addContextMenu($altIcon as HTMLImageElement, index); } - sidebarHoverEvent(SidebarButton: HTMLButtonElement, SidebarTooltip: HTMLElement, addServer = false): void { - SidebarButton.addEventListener('mouseover', () => { - SidebarTooltip.removeAttribute('style'); - // To handle position of add server tooltip due to scrolling of list of organizations - // This could not be handled using CSS, hence the top of the tooltip is made same - // as that of its parent element. - // This needs to handled only for the add server tooltip and not others. - if (addServer) { - const { top } = SidebarButton.getBoundingClientRect(); - SidebarTooltip.style.top = top + 'px'; - } - }); - SidebarButton.addEventListener('mouseout', () => { - SidebarTooltip.style.display = 'none'; - }); - } - - onHover(index: number): void { - // this.$serverIconTooltip[index].innerHTML already has realm name, so we are just - // removing the style. - this.$serverIconTooltip[index].removeAttribute('style'); - // To handle position of servers' tooltip due to scrolling of list of organizations - // This could not be handled using CSS, hence the top of the tooltip is made same - // as that of its parent element. - const { top } = this.$serverIconTooltip[index].parentElement.getBoundingClientRect(); - this.$serverIconTooltip[index].style.top = top + 'px'; - } - - onHoverOut(index: number): void { - this.$serverIconTooltip[index].style.display = 'none'; - } - openFunctionalTab(tabProps: FunctionalTabProps): void { if (this.functionalTabs[tabProps.name] !== undefined) { this.activateTab(this.functionalTabs[tabProps.name]); @@ -690,7 +628,7 @@ class ServerManagerView { // Toggles the dnd button icon. toggleDNDButton(alert: boolean): void { - this.$dndTooltip.textContent = (alert ? 'Disable' : 'Enable') + ' Do Not Disturb'; + this.$dndButton.title = (alert ? 'Disable' : 'Enable') + ' Do Not Disturb'; this.$dndButton.querySelector('i').textContent = alert ? 'notifications_off' : 'notifications'; } @@ -836,11 +774,10 @@ class ServerManagerView { // TODO: TypeScript - Type annotate getDomains() or this domain paramter. DomainUtil.getDomains().forEach((domain: any, index: number) => { if (domain.url.includes(serverURL)) { - const serverTooltipSelector = `.tab .server-tooltip`; - const serverTooltips = document.querySelectorAll(serverTooltipSelector); - serverTooltips[index].innerHTML = escape(realmName); + const serverTabSelector = `.server-tab`; + const serverTabs = document.querySelectorAll(serverTabSelector); + (serverTabs[index] as HTMLElement).title = escape(realmName); this.tabs[index].props.name = escape(realmName); - // this.tabs[index].webview.props.name = realmName; domain.alias = escape(realmName); DomainUtil.db.push(`/domains[${index}]`, domain, true); diff --git a/app/renderer/main.html b/app/renderer/main.html index bc71f01fd..b1ec26f79 100644 --- a/app/renderer/main.html +++ b/app/renderer/main.html @@ -17,32 +17,26 @@
-
- add +
+ add
-
-
+
notifications -
-
+
refresh -
-
+
loop -
-
+
arrow_back -
-
+
settings -
From 8d35f29c8e5f0d0377aed2b56a3c06b8d9916240 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Wed, 24 Jul 2019 02:27:56 +0530 Subject: [PATCH 08/28] BrowserView: Add favicon-update event and fix view function calls. --- app/main/view.ts | 15 ++++++++++++++- app/renderer/js/main.ts | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/main/view.ts b/app/main/view.ts index 4ba88e5eb..b6c70fa8f 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -1,6 +1,6 @@ 'use strict'; -import { BrowserView, BrowserWindow } from 'electron'; +import { BrowserView, BrowserWindow, app } from 'electron'; import ConfigUtil = require('../renderer/js/utils/config-util'); const shouldSilentWebview = ConfigUtil.getConfigItem('silent'); @@ -76,6 +76,19 @@ export class View extends BrowserView { const badgeCount = this.getBadgeCount(title); this.sendAction('update-badge-count', badgeCount, this.url); }); + + this.webContents.addListener('page-favicon-updated', (e: Event, favicons: string[]) => { + // This returns a string of favicons URL. If there is a PM counts in unread messages then the URL would be like + // https://chat.zulip.org/static/images/favicon/favicon-pms.png + if (favicons[0].indexOf('favicon-pms') > 0 && process.platform === 'darwin') { + // This api is only supported on macOS + app.dock.setBadge('●'); + // bounce the dock + if (ConfigUtil.getConfigItem('dockBouncing')) { + app.dock.bounce(); + } + } + }); } zoomIn(): void { diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 74d309dad..2981b28b4 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -679,12 +679,12 @@ class ServerManagerView { zoomActualSize: 'zoomActualSize', 'log-out': 'logOut', shortcut: 'showShortcut', - 'tab-devtools': 'openDevTools' + 'tab-devtools': 'toggleDevTools' }; for (const key in webviewListeners) { ipcRenderer.on(key, () => { - ipcRenderer.send('view-call-function', webviewListeners[key]); + ipcRenderer.send('call-view-function', webviewListeners[key]); }); } From a5eedd3e8b24e0406edeb9c123e372a9e5e3e7f3 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Fri, 26 Jul 2019 02:40:02 +0530 Subject: [PATCH 09/28] BrowserView: Destroy all views during reload-app. Destroys all views to recreate them later when app is reloaded. Also, set lastActiveIndex to 0 when a tab is removed. --- app/main/index.ts | 1 + app/renderer/js/main.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/main/index.ts b/app/main/index.ts index d7cfce437..9f91c8313 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -234,6 +234,7 @@ app.on('ready', () => { // Reload full app not just webview, useful in debugging ipcMain.on('reload-full-app', () => { + ViewManager.destroyAll(); mainWindow.reload(); page.send('destroytray'); }); diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 2981b28b4..39002dc5c 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -647,6 +647,8 @@ class ServerManagerView { }, response => { if (response === 0) { if (DomainUtil.removeDomain(index)) { + // Set lastActiveTab to 0th index + ConfigUtil.setConfigItem('lastActiveTab', 0); ipcRenderer.send('reload-full-app'); } else { const { title, content } = Messages.orgRemovalError(DomainUtil.getDomain(index).url); From c76fa3b485eb368d82c2bd33ad7654816207a4c0 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Fri, 26 Jul 2019 03:14:10 +0530 Subject: [PATCH 10/28] BrowserView: Improvements to loading indicator. --- app/main/view.ts | 19 ++++++++++--------- app/renderer/main.html | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/main/view.ts b/app/main/view.ts index b6c70fa8f..97734c590 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -17,7 +17,6 @@ export class View extends BrowserView { index: number; url: string; zoomFactor: number; - loading: boolean; customCSS: boolean; constructor(public props: ViewProps) { @@ -32,7 +31,6 @@ export class View extends BrowserView { this.index = props.index; this.url = props.url; this.zoomFactor = 1.0; - this.loading = false; this.customCSS = ConfigUtil.getConfigItem('customCSS'); this.registerListeners(); } @@ -57,19 +55,15 @@ export class View extends BrowserView { }); this.webContents.addListener('did-start-loading', () => { - const isSettingsPage = this.url.includes('renderer/preference.html'); - if (!isSettingsPage) { - this.sendAction('switch-loading', true, this.url); - } + this.switchLoadingIndicator(true); }); this.webContents.addListener('dom-ready', () => { - this.loading = false; this.sendAction('switch-loading', false, this.url); }); this.webContents.addListener('did-stop-loading', () => { - this.sendAction('switch-loading', false, this.url); + this.switchLoadingIndicator(false); }); this.webContents.addListener('page-title-updated', (e: Event, title: string) => { @@ -107,10 +101,17 @@ export class View extends BrowserView { } reload(): void { - this.loading = true; + this.switchLoadingIndicator(true); this.webContents.reload(); } + switchLoadingIndicator(state: boolean): void { + const isSettingsPage = this.url.includes('renderer/preference.html'); + if (!isSettingsPage) { + this.sendAction('switch-loading', state, this.url); + } + } + forward(): void { if (this.webContents.canGoForward()) { this.webContents.goForward(); diff --git a/app/renderer/main.html b/app/renderer/main.html index b1ec26f79..b5746a761 100644 --- a/app/renderer/main.html +++ b/app/renderer/main.html @@ -29,7 +29,7 @@
refresh
-
+
loop
From bb1c0a7b26fa083c3f7be9a04e63d4a1c9ad2f43 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Fri, 26 Jul 2019 19:38:43 +0530 Subject: [PATCH 11/28] BrowserView: Improve ipc names. --- app/main/viewmanager.ts | 11 ++++++----- app/renderer/js/main.ts | 14 +++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index 2d1c445ed..cee549918 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -16,23 +16,23 @@ class ViewManager { } registerIpcs(): void { - ipcMain.on('view-create', (e: Event, props: ViewProps) => { + ipcMain.on('create-view', (e: Event, props: ViewProps) => { this.create(props); }); - ipcMain.on('view-select', (e: Event, index: number) => { + ipcMain.on('select-view', (e: Event, index: number) => { this.select(index); }); - ipcMain.on('view-destroy', (e: Event, index: number) => { + ipcMain.on('destroy-view', (e: Event, index: number) => { this.destroy(index); }); - ipcMain.on('view-destroy-all', () => { + ipcMain.on('destroy-all-views', () => { this.destroyAll(); }); - ipcMain.on('forward-message-view', (e: Event, name: string, ...params: any[]) => { + ipcMain.on('forward-view-message', (e: Event, name: string, ...params: any[]) => { this.views[this.selectedIndex].webContents.send(name, ...params); }); @@ -75,6 +75,7 @@ class ViewManager { } fixBounds(): void { + // Any updates to the sidebar width should reflect both here and in css const SIDEBAR_WIDTH = 54; const view = this.views[this.selectedIndex]; const showSidebar = ConfigUtil.getConfigItem('showSidebar', true); diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 39002dc5c..ddee07120 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -339,7 +339,7 @@ class ServerManagerView { nodeIntegration: false, preload: true }; - ipcRenderer.send('view-create', props); + ipcRenderer.send('create-view', props); this.loading[server.url] = true; } @@ -453,7 +453,7 @@ class ServerManagerView { nodeIntegration: true, preload: false }; - ipcRenderer.send('view-create', props); + ipcRenderer.send('create-view', props); // To show loading indicator the first time a functional tab is opened, indicator is // closed when the functional tab DOM is ready, handled in webview.js this.$webviewsContainer.classList.remove('loaded'); @@ -468,7 +468,7 @@ class ServerManagerView { url: `file://${rendererDirectory}/preference.html#${nav}` }); this.$settingsButton.classList.add('active'); - ipcRenderer.send('forward-message-view', 'switch-settings-nav', nav); + ipcRenderer.send('forward-view-message', 'switch-settings-nav', nav); } openAbout(): void { @@ -528,7 +528,7 @@ class ServerManagerView { this.activeTabIndex = index; this.tabs[index].activate(); - ipcRenderer.send('view-select', index); + ipcRenderer.send('select-view', index); this.showLoading(this.loading[this.tabs[this.activeTabIndex].props.url]); ipcRenderer.send('call-view-function', 'canGoBackButton'); ipcRenderer.send('update-menu', { @@ -567,7 +567,7 @@ class ServerManagerView { // Show loading indicator this.$webviewsContainer.classList.remove('loaded'); - ipcRenderer.send('view-destroy-all'); + ipcRenderer.send('destroy-all-views'); // Clear global variables this.activeTabIndex = -1; @@ -609,7 +609,7 @@ class ServerManagerView { } updateGeneralSettings(setting: string, value: any): void { - ipcRenderer.send('forward-message-view', setting, value); + ipcRenderer.send('forward-view-message', setting, value); } toggleSidebar(show: boolean): void { @@ -769,7 +769,7 @@ class ServerManagerView { ipcRenderer.on('toggle-dnd', (event: Event, state: boolean, newSettings: SettingsOptions) => { this.toggleDNDButton(state); ipcRenderer.send('forward-message', 'toggle-silent', newSettings.silent); - ipcRenderer.send('forward-message-view', 'toggle-dnd', state, newSettings); + ipcRenderer.send('forward-view-message', 'toggle-dnd', state, newSettings); }); ipcRenderer.on('update-realm-name', (event: Event, serverURL: string, realmName: string) => { From 2321503d00402c9711668927d22e233019e99ce3 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Sat, 27 Jul 2019 21:33:52 +0530 Subject: [PATCH 12/28] BrowserView: Add logic to handle external links. --- app/main/view.ts | 13 +++++++++++++ app/main/viewmanager.ts | 6 ++++++ app/renderer/js/components/handle-external-link.ts | 13 ++++--------- app/renderer/js/components/webview.ts | 4 ++-- app/renderer/js/main.ts | 5 +++++ 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/app/main/view.ts b/app/main/view.ts index 97734c590..8f26d4b12 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -83,6 +83,11 @@ export class View extends BrowserView { } } }); + + this.webContents.addListener('new-window', (e: Event, urlToOpen: string) => { + e.preventDefault(); + this.sendAction('handle-link', this.index, urlToOpen); + }); } zoomIn(): void { @@ -149,6 +154,14 @@ export class View extends BrowserView { return messageCountInTitle ? Number(messageCountInTitle[1]) : 0; } + downloadUrl(url: string): void { + this.webContents.downloadURL(url); + } + + loadUrl(url: string): void { + this.webContents.loadURL(url); + } + sendAction(action: any, ...params: any[]): void { const win = BrowserWindow.getAllWindows()[0]; diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index cee549918..d0ab1c452 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -45,6 +45,12 @@ class ViewManager { // So, using a workaround here. (this.views[this.selectedIndex] as any)[name as keyof View](...params); }); + + ipcMain.on('call-specific-view-function', (e: Event, index: number, name: string, ...params: any[]) => { + // Type checking requires spread elements to match up with a rest parameter. + // So, using a workaround here. + (this.views[index] as any)[name as keyof View](...params); + }); } create(props: ViewProps): void { diff --git a/app/renderer/js/components/handle-external-link.ts b/app/renderer/js/components/handle-external-link.ts index 076e978b1..49f28b811 100644 --- a/app/renderer/js/components/handle-external-link.ts +++ b/app/renderer/js/components/handle-external-link.ts @@ -8,10 +8,8 @@ const { shell, app } = remote; const dingSound = new Audio('../resources/sounds/ding.ogg'); -// TODO: TypeScript - Figure out a way to pass correct type here. -function handleExternalLink(this: any, event: any): void { - const { url } = event; - const domainPrefix = DomainUtil.getDomain(this.props.index).url; +function handleExternalLink(index: number, url: string): void { + const domainPrefix = DomainUtil.getDomain(index).url; const downloadPath = ConfigUtil.getConfigItem('downloadsPath', `${app.getPath('downloads')}`); const shouldShowInFolder = ConfigUtil.getConfigItem('showDownloadFolder', false); @@ -22,8 +20,6 @@ function handleExternalLink(this: any, event: any): void { } = LinkUtil.isInternal(domainPrefix, url); if (isWhiteListURL) { - event.preventDefault(); - // Code to show pdf in a new BrowserWindow (currently commented out due to bug-upstream) // Show pdf attachments in a new window // if (LinkUtil.isPDF(url) && isUploadsURL) { @@ -66,16 +62,15 @@ function handleExternalLink(this: any, event: any): void { ipcRenderer.once('downloadFileFailed', () => { // Automatic download failed, so show save dialog prompt and download // through webview - this.$el.downloadURL(url); + ipcRenderer.send('call-specific-view-function', index, 'downloadUrl', url); ipcRenderer.removeAllListeners('downloadFileCompleted'); }); return; } // open internal urls inside the current webview. - this.$el.loadURL(url); + ipcRenderer.send('call-specific-view-function', index, 'loadUrl', url); } else { - event.preventDefault(); shell.openExternal(url); } } diff --git a/app/renderer/js/components/webview.ts b/app/renderer/js/components/webview.ts index afdf75ad8..b95cbe4da 100644 --- a/app/renderer/js/components/webview.ts +++ b/app/renderer/js/components/webview.ts @@ -6,7 +6,7 @@ import fs = require('fs'); import ConfigUtil = require('../utils/config-util'); import SystemUtil = require('../utils/system-util'); import BaseComponent = require('../components/base'); -import handleExternalLink = require('../components/handle-external-link'); +// import handleExternalLink = require('../components/handle-external-link'); const { app, dialog } = remote; @@ -64,7 +64,7 @@ class WebView extends BaseComponent { registerListeners(): void { this.$el.addEventListener('new-window', event => { - handleExternalLink.call(this, event); + // handleExternalLink.call(this, event); }); if (shouldSilentWebview) { diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index ddee07120..dcc1e9924 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -21,6 +21,7 @@ import Logger = require('./utils/logger-util'); import CommonUtil = require('./utils/common-util'); import EnterpriseUtil = require('./utils/enterprise-util'); import Messages = require('./../../resources/messages'); +import handleExternalLink = require('./components/handle-external-link'); const logger = new Logger({ file: 'errors.log', @@ -906,6 +907,10 @@ class ServerManagerView { this.badgeCounts[url] = count; this.updateBadge(); }); + + ipcRenderer.on('handle-link', (e: Event, index: number, url: string) => { + handleExternalLink(index, url); + }); } } From 86e4f416f64966c4f25d6f7efe20d4332b33f975 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Sat, 27 Jul 2019 21:38:44 +0530 Subject: [PATCH 13/28] BrowserView: Rename canGoBackButton to maybeEnableGoBackButton. --- app/main/view.ts | 6 +++--- app/main/viewmanager.ts | 1 + app/renderer/js/main.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/main/view.ts b/app/main/view.ts index 8f26d4b12..a9be4d2d6 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -47,11 +47,11 @@ export class View extends BrowserView { if (isSettingsPage) { return; } - this.canGoBackButton(); + this.maybeEnableGoBackButton(); }); this.webContents.addListener('did-navigate', () => { - this.canGoBackButton(); + this.maybeEnableGoBackButton(); }); this.webContents.addListener('did-start-loading', () => { @@ -141,7 +141,7 @@ export class View extends BrowserView { this.webContents.toggleDevTools(); } - canGoBackButton(): void { + maybeEnableGoBackButton(): void { if (this.webContents.canGoBack()) { this.sendAction('switch-back', true); } else { diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index d0ab1c452..e8a8971bd 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -70,6 +70,7 @@ class ViewManager { return; } this.selectedIndex = index; + // Unset old view before setting new view mainWindow.setBrowserView(null); if (!view.webContents.getURL()) { const { url } = view; diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index dcc1e9924..da10f75d5 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -531,7 +531,7 @@ class ServerManagerView { this.tabs[index].activate(); ipcRenderer.send('select-view', index); this.showLoading(this.loading[this.tabs[this.activeTabIndex].props.url]); - ipcRenderer.send('call-view-function', 'canGoBackButton'); + ipcRenderer.send('call-view-function', 'maybeEnableGoBackButton'); ipcRenderer.send('update-menu', { // JSON stringify this.tabs to avoid a crash // util.inspect is being used to handle circular references From af79ff61cd53733ab1af0080ea67fbf4b07672a0 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Tue, 30 Jul 2019 05:01:38 +0530 Subject: [PATCH 14/28] BrowserView: Implement userAgent and updateBadge onload. Add logic to set user agent for each browserview. Also, the badgeCount was not shown initially, on opening the app. Adds that too. --- app/main/view.ts | 25 ++++++++++++++++++++++-- app/renderer/js/components/server-tab.ts | 4 ++-- app/renderer/js/utils/system-util.ts | 8 ++++---- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/app/main/view.ts b/app/main/view.ts index a9be4d2d6..1bde257d3 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -3,6 +3,7 @@ import { BrowserView, BrowserWindow, app } from 'electron'; import ConfigUtil = require('../renderer/js/utils/config-util'); +import SystemUtil = require('../renderer/js/utils/system-util'); const shouldSilentWebview = ConfigUtil.getConfigItem('silent'); export interface ViewProps { @@ -33,6 +34,7 @@ export class View extends BrowserView { this.zoomFactor = 1.0; this.customCSS = ConfigUtil.getConfigItem('customCSS'); this.registerListeners(); + this.setUserAgent(); } registerListeners(): void { @@ -62,13 +64,17 @@ export class View extends BrowserView { this.sendAction('switch-loading', false, this.url); }); + this.webContents.addListener('did-finish-load', () => { + const title = this.webContents.getTitle(); + this.updateBadgeCount(title); + }); + this.webContents.addListener('did-stop-loading', () => { this.switchLoadingIndicator(false); }); this.webContents.addListener('page-title-updated', (e: Event, title: string) => { - const badgeCount = this.getBadgeCount(title); - this.sendAction('update-badge-count', badgeCount, this.url); + this.updateBadgeCount(title); }); this.webContents.addListener('page-favicon-updated', (e: Event, favicons: string[]) => { @@ -90,6 +96,16 @@ export class View extends BrowserView { }); } + setUserAgent(): void { + let userAgent = SystemUtil.getUserAgent(); + if (!userAgent) { + const viewUserAgent = this.webContents.getUserAgent(); + SystemUtil.setUserAgent(viewUserAgent); + userAgent = SystemUtil.getUserAgent(); + } + this.webContents.setUserAgent(userAgent); + } + zoomIn(): void { this.zoomFactor += 0.1; this.webContents.setZoomFactor(this.zoomFactor); @@ -162,6 +178,11 @@ export class View extends BrowserView { this.webContents.loadURL(url); } + updateBadgeCount(title: string): void { + const badgeCount = this.getBadgeCount(title); + this.sendAction('update-badge-count', badgeCount, this.url); + } + sendAction(action: any, ...params: any[]): void { const win = BrowserWindow.getAllWindows()[0]; diff --git a/app/renderer/js/components/server-tab.ts b/app/renderer/js/components/server-tab.ts index 1ab4b671e..2864e1163 100644 --- a/app/renderer/js/components/server-tab.ts +++ b/app/renderer/js/components/server-tab.ts @@ -2,8 +2,8 @@ import { ipcRenderer } from 'electron'; +import os = require('os'); import Tab = require('./tab'); -import SystemUtil = require('../utils/system-util'); class ServerTab extends Tab { $badge: Element; @@ -51,7 +51,7 @@ class ServerTab extends Tab { let shortcutText = ''; - if (SystemUtil.getOS() === 'Mac') { + if (os.platform() === 'darwin') { shortcutText = `⌘ ${shownIndex}`; } else { shortcutText = `Ctrl+${shownIndex}`; diff --git a/app/renderer/js/utils/system-util.ts b/app/renderer/js/utils/system-util.ts index 96fbbd931..62e62cc5c 100644 --- a/app/renderer/js/utils/system-util.ts +++ b/app/renderer/js/utils/system-util.ts @@ -1,9 +1,8 @@ 'use strict'; -import { remote } from 'electron'; +import { app } from 'electron'; import os = require('os'); -const { app } = remote; let instance: null | SystemUtil = null; class SystemUtil { @@ -48,8 +47,9 @@ class SystemUtil { } } - setUserAgent(webViewUserAgent: string): void { - this.userAgent = `ZulipElectron/${app.getVersion()} ${webViewUserAgent}`; + setUserAgent(viewUserAgent: string): void { + const appVersion = app.getVersion(); + this.userAgent = 'ZulipElectron/' + appVersion + ' ' + viewUserAgent; } getUserAgent(): string | null { From 593b07c74311387651416de0629ada459cd17428 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Wed, 31 Jul 2019 01:41:25 +0530 Subject: [PATCH 15/28] BrowserView: Add logic to show network error page. --- app/main/view.ts | 10 +++++++++- app/renderer/js/main.ts | 9 +++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/main/view.ts b/app/main/view.ts index 1bde257d3..7adb912bb 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -61,7 +61,15 @@ export class View extends BrowserView { }); this.webContents.addListener('dom-ready', () => { - this.sendAction('switch-loading', false, this.url); + this.switchLoadingIndicator(false); + }); + + this.webContents.addListener('did-fail-load', (e: Event, errorCode: number, errorDescription: string) => { + const hasConnectivityErr = SystemUtil.connectivityERR.includes(errorDescription); + if (hasConnectivityErr) { + console.error('error', errorDescription); + this.sendAction('network-error'); + } }); this.webContents.addListener('did-finish-load', () => { diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index da10f75d5..b08016baa 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -405,10 +405,7 @@ class ServerManagerView { const $altIcon = document.createElement('div'); const $parent = $img.parentElement; - const $container = $parent.parentElement; - const webviewId = $container.dataset.tabId; - const $webview = document.querySelector(`webview[data-tab-id="${webviewId}"]`); - const realmName = $webview.getAttribute('name'); + const realmName = this.tabs[index].props.name; if (realmName === null) { $img.src = '/img/icon.png'; @@ -911,6 +908,10 @@ class ServerManagerView { ipcRenderer.on('handle-link', (e: Event, index: number, url: string) => { handleExternalLink(index, url); }); + + ipcRenderer.on('network-error', () => { + this.openNetworkTroubleshooting(); + }); } } From c49d2d9bcb1cc900d61a00f6f9295dcb7f8e0097 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Wed, 31 Jul 2019 03:46:45 +0530 Subject: [PATCH 16/28] BrowserView: Add logic for custom CSS. --- app/main/view.ts | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/app/main/view.ts b/app/main/view.ts index 7adb912bb..47246c8c3 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -1,7 +1,9 @@ 'use strict'; -import { BrowserView, BrowserWindow, app } from 'electron'; +import { BrowserView, BrowserWindow, app, dialog } from 'electron'; +import path = require('path'); +import fs = require('fs'); import ConfigUtil = require('../renderer/js/utils/config-util'); import SystemUtil = require('../renderer/js/utils/system-util'); const shouldSilentWebview = ConfigUtil.getConfigItem('silent'); @@ -18,7 +20,7 @@ export class View extends BrowserView { index: number; url: string; zoomFactor: number; - customCSS: boolean; + customCSS: string | null; constructor(public props: ViewProps) { super({ @@ -62,6 +64,7 @@ export class View extends BrowserView { this.webContents.addListener('dom-ready', () => { this.switchLoadingIndicator(false); + this.handleCSS(); }); this.webContents.addListener('did-fail-load', (e: Event, errorCode: number, errorDescription: string) => { @@ -104,6 +107,25 @@ export class View extends BrowserView { }); } + handleCSS(): void { + // Injecting preload css in view to override some css rules + this.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '../renderer/css/preload.css'), 'utf8')); + + // get customCSS again from config util to avoid warning user again + this.customCSS = ConfigUtil.getConfigItem('customCSS'); + if (this.customCSS) { + if (!fs.existsSync(this.customCSS)) { + this.customCSS = null; + ConfigUtil.setConfigItem('customCSS', null); + const errMsg = 'The custom css previously set is deleted!'; + dialog.showErrorBox('custom css file deleted!', errMsg); + return; + } + + this.webContents.insertCSS(fs.readFileSync(path.resolve(__dirname, this.customCSS), 'utf8')); + } + } + setUserAgent(): void { let userAgent = SystemUtil.getUserAgent(); if (!userAgent) { From d3383dce1d237a69a7e387b62547dcb9face47ed Mon Sep 17 00:00:00 2001 From: vsvipul Date: Wed, 31 Jul 2019 20:35:52 +0530 Subject: [PATCH 17/28] BrowserView: Call fixBounds before setting view. --- app/main/viewmanager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index e8a8971bd..778e9f1a5 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -76,9 +76,9 @@ class ViewManager { const { url } = view; view.webContents.loadURL(url); } + this.fixBounds(); mainWindow.setBrowserView(view); view.webContents.focus(); - this.fixBounds(); } fixBounds(): void { @@ -87,7 +87,6 @@ class ViewManager { const view = this.views[this.selectedIndex]; const showSidebar = ConfigUtil.getConfigItem('showSidebar', true); if (!view || view.isDestroyed()) { - console.log('Attempt to fix bounds for a view that does not exist.'); return; } const mainWindow = BrowserWindow.getAllWindows()[0]; From 1bd3fa8db685218e8aca15260d315fd8e5a48571 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Thu, 1 Aug 2019 02:17:59 +0530 Subject: [PATCH 18/28] BrowserView: Update deps. --- app/main/index.ts | 2 +- app/package-lock.json | 310 +++++----- app/package.json | 4 +- app/renderer/js/preload.ts | 3 +- package-lock.json | 1167 ++++++++++++++++++++---------------- package.json | 4 +- 6 files changed, 798 insertions(+), 692 deletions(-) diff --git a/app/main/index.ts b/app/main/index.ts index 9f91c8313..010132134 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -82,7 +82,7 @@ function createMainWindow(): Electron.BrowserWindow { webPreferences: { plugins: true, nodeIntegration: true, - partition: 'persist:webviewsession' + partition: 'persist:viewsession' }, show: false }); diff --git a/app/package-lock.json b/app/package-lock.json index d99796edf..f16c24e97 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1,9 +1,29 @@ { "name": "zulip", - "version": "3.1.0-beta", + "version": "4.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { + "@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=" + } + } + }, "@electron-elements/send-feedback": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@electron-elements/send-feedback/-/send-feedback-1.0.8.tgz", @@ -17,23 +37,12 @@ "resolved": "https://registry.npmjs.org/@electron-elements/utils/-/utils-1.0.3.tgz", "integrity": "sha1-23sB2Zzaay/sNM+XuJcJCWnznII=" }, - "@paulcbetts/cld": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/@paulcbetts/cld/-/cld-2.4.6.tgz", - "integrity": "sha1-qZL2vEPKshKsLESIpnHPMC+LYuc=", - "requires": { - "glob": "^5.0.10", - "nan": "^2.0.5", - "rimraf": "^2.4.0", - "underscore": "^1.6.0" - } - }, - "@paulcbetts/spellchecker": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@paulcbetts/spellchecker/-/spellchecker-4.0.6.tgz", - "integrity": "sha1-ee8fnBnFoxVpIcyqn/3D77vuR+M=", + "@felixrieseberg/spellchecker": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@felixrieseberg/spellchecker/-/spellchecker-4.0.10.tgz", + "integrity": "sha512-b+BlHcBXjx+W7yGNAtoVpAv8dvmAQ8Tp2YhNjqxIgocb6Wq1nKLl4jfu9DG60UWC0hTNvvQ74ny9ojiUFNqGSA==", "requires": { - "nan": "^2.0.0" + "nan": "^2.13.2" } }, "@sentry/browser": { @@ -131,6 +140,11 @@ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" }, + "@types/semver": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.0.1.tgz", + "integrity": "sha512-ffCdcrEE5h8DqVxinQjo+2d1q+FV5z7iNtPofw3JsrltSoSVlOGaW0rY8XxtO9XukdTn8TaCGWmk2VFGhI70mg==" + }, "@types/stack-trace": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.29.tgz", @@ -281,19 +295,6 @@ "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==", "optional": true }, - "bluebird": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" - }, - "bluebird-lst": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.6.tgz", - "integrity": "sha512-CBWFoPuUPpcvMUxfyr8DKdI5d4kjxFl1h39+VbKxP3KJWJHEsLtuT4pPLkjpxCGU6Ask21tvbnftWXdqIxYldQ==", - "requires": { - "bluebird": "^3.5.2" - } - }, "boom": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", @@ -305,25 +306,18 @@ "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, "builder-util-runtime": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.1.0.tgz", - "integrity": "sha512-s1mlJ28mv+56Iebh6c9aXjVe11O3Z0cDTwAGeB0PCcUzHA37fDxGgS8ZGoYNMZP+rBHj21d/od1wuYofTVLaQg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.3.0.tgz", + "integrity": "sha512-CSOdsYqf4RXIHh1HANPbrZHlZ9JQJXSuDDloblZPcWQVN62inyYoTQuSmY3KrgefME2Sv3Kn2MxHvbGQHRf8Iw==", "requires": { - "bluebird-lst": "^1.0.6", - "debug": "^4.1.0", - "fs-extra-p": "^7.0.0", + "debug": "^4.1.1", "sax": "^1.2.4" }, "dependencies": { @@ -336,9 +330,9 @@ } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -378,6 +372,17 @@ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" }, + "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" + } + }, "clean-stack": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", @@ -564,58 +569,59 @@ "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-2.2.14.tgz", "integrity": "sha512-Rj+XyK4nShe/nv9v1Uks4KEfjtQ6N+eSnx5CLpAjG6rlyUdAflyFHoybcHSLoq9l9pGavclULWS5IXgk8umc2g==" }, - "electron-remote": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/electron-remote/-/electron-remote-1.2.0.tgz", - "integrity": "sha1-DwDB04A852URF/b7bydNJnge+b0=", - "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" - } - }, "electron-spellchecker": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/electron-spellchecker/-/electron-spellchecker-1.1.2.tgz", - "integrity": "sha1-X74eZdJGt35udDPuI4fZ0mAQ96g=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/electron-spellchecker/-/electron-spellchecker-2.2.0.tgz", + "integrity": "sha512-QkOVgjmjx6bDkqNshRTfVzEz9ctjiKVPZw77YLS0sQReP320QNtTXAKyo+01TORWk58RFT/LdxPZ/aejLdPmOA==", "requires": { - "@paulcbetts/cld": "^2.4.6", - "@paulcbetts/spellchecker": "^4.0.6", + "@aabuhijleh/electron-remote": "^1.4.0", + "@felixrieseberg/spellchecker": "^4.0.10", "bcp47": "^1.1.2", - "debug": "^2.6.3", - "electron-remote": "^1.1.1", - "keyboard-layout": "^2.0.7", - "lru-cache": "^4.0.2", + "cld": "^2.5.1", + "debug": "^4.1.1", + "keyboard-layout": "^2.0.16", + "lru-cache": "^5.1.1", "mkdirp": "^0.5.1", - "pify": "^2.3.0", + "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-updater": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.0.6.tgz", - "integrity": "sha512-JPGLME6fxJcHG8hX7HWFl6Aew6iVm0DkcrENreKa5SUJCHG+uUaAhxDGDt+YGcNkyx1uJ6eBGMvFxDTLUv67pg==", - "requires": { - "bluebird-lst": "^1.0.6", - "builder-util-runtime": "~8.1.0", - "fs-extra-p": "^7.0.0", - "js-yaml": "^3.12.0", - "lazy-val": "^1.0.3", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.1.2.tgz", + "integrity": "sha512-4Sk8IW0LfOilDz+WAB/gEDmX7+FUFRbKHGN1zGjehPilnd6H9cmjgBHK6Xzq/FLq/uOHGJ6GX/9tsF+jr7CvnA==", + "requires": { + "@types/semver": "^6.0.1", + "builder-util-runtime": "8.3.0", + "fs-extra": "^8.1.0", + "js-yaml": "^3.13.1", + "lazy-val": "^1.0.4", "lodash.isequal": "^4.5.0", - "pako": "^1.0.7", - "semver": "^5.6.0", - "source-map-support": "^0.5.9" + "pako": "^1.0.10", + "semver": "^6.2.0" }, "dependencies": { "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -693,9 +699,9 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "event-kit": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.4.0.tgz", - "integrity": "sha1-cYqvIt92ZwAkrWaSJIPhu6BUTzM=" + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.3.tgz", + "integrity": "sha512-b7Qi1JNzY4BfAYfnIRanLk0DOD1gdkWHT4GISIn8Q2tAf3LpU8SP2CMwWaq40imYoKWbtN4ZhbSRxvsnikooZQ==" }, "event-target-shim": { "version": "1.1.1", @@ -778,22 +784,20 @@ } }, "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "requires": { - "graceful-fs": "^4.1.2", + "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" - } - }, - "fs-extra-p": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-7.0.0.tgz", - "integrity": "sha512-5tg5jBOd0xIXjwj4PDnafOXL5TyPVzjxLby4DPKev53wurEXp7IsojBaD4Lj5M5w7jxw0pbkEU0fFEPmcKoMnA==", - "requires": { - "bluebird-lst": "^1.0.6", - "fs-extra": "^7.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz", + "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==" + } } }, "fs.realpath": { @@ -895,9 +899,9 @@ } }, "hashids": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/hashids/-/hashids-1.1.4.tgz", - "integrity": "sha512-U/fnTE3edW0AV92ZI/BfEluMZuVcu3MDOopsN7jS+HqDYcarQo8rXQiWlsBlm0uX48/taYSdxRsfzh2HRg5Z6w==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/hashids/-/hashids-1.2.2.tgz", + "integrity": "sha512-dEHCG2LraR6PNvSGxosZHIRgxF5sNLOIBFEHbj8lfP9WWmu/PWPMzsip1drdVSOFi51N2pU7gZavrgn7sbGFuw==" }, "hawk": { "version": "6.0.2", @@ -1103,9 +1107,9 @@ } }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -1157,12 +1161,12 @@ } }, "keyboard-layout": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/keyboard-layout/-/keyboard-layout-2.0.13.tgz", - "integrity": "sha1-W09cJYNeXSIae52ol2YxANiXSH0=", + "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.0.0" + "nan": "^2.13.2" } }, "keyv": { @@ -1174,9 +1178,9 @@ } }, "lazy-val": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.3.tgz", - "integrity": "sha512-pjCf3BYk+uv3ZcPzEVM0BFvO9Uw58TmlrU0oG5tTrr9Kcid3+kdKxapH8CjdYmVa2nO5wOoZn2rdvZx2PKj/xg==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz", + "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==" }, "lodash.assign": { "version": "4.2.0", @@ -1196,15 +1200,14 @@ "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=" + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" }, "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "yallist": "^3.0.2" } }, "lsmod": { @@ -1293,7 +1296,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { "brace-expansion": "^1.1.7" } @@ -1322,9 +1325,9 @@ "integrity": "sha512-jFI/4UVRsRYdUbuDTKT7KzfOp7FiD5WzYmmwNwXyUVypC0xjoTL78Fqc0jHUPIvvGD+6DQSPHIt1NE7D1ArsqA==" }, "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha1-ltDNYQ69WNS03pzAxoKM2pnHVI8=" + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, "node-json-db": { "version": "0.9.2", @@ -1442,9 +1445,9 @@ } }, "pako": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.7.tgz", - "integrity": "sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ==" + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" }, "path-is-absolute": { "version": "1.0.1", @@ -1457,9 +1460,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" }, "prepend-http": { "version": "1.0.4", @@ -1471,11 +1474,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, "public-ip": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/public-ip/-/public-ip-2.4.0.tgz", @@ -1618,17 +1616,17 @@ } }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" }, "dependencies": { "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1641,9 +1639,9 @@ } }, "rxjs": { - "version": "5.5.8", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.8.tgz", - "integrity": "sha1-srCAmldhStYlTAPXRG3qDYPKN5E=", + "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" } @@ -1710,20 +1708,6 @@ "is-plain-obj": "^1.0.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", - "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "spawn-rx": { "version": "2.0.12", "resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-2.0.12.tgz", @@ -1829,9 +1813,9 @@ "integrity": "sha1-0cIJOlT/ihn1jP+HfuqlTyJC04M=" }, "underscore": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.0.tgz", - "integrity": "sha512-4IV1DSSxC1QK48j9ONFK1MoIAKKkbE8i7u55w2R6IqBqbT7A/iG7aZBCR2Bi8piF0Uz+i/MG1aeqLwl/5vqF+A==" + "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==" }, "universalify": { "version": "0.1.2", @@ -1932,9 +1916,9 @@ "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=" }, "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" } } } diff --git a/app/package.json b/app/package.json index 7a63af0e1..1aeb713fe 100644 --- a/app/package.json +++ b/app/package.json @@ -34,8 +34,8 @@ "dotenv": "8.0.0", "electron-is-dev": "0.3.0", "electron-log": "2.2.14", - "electron-spellchecker": "1.1.2", - "electron-updater": "4.0.6", + "electron-spellchecker": "2.2.0", + "electron-updater": "4.1.2", "electron-window-state": "5.0.3", "escape-html": "1.0.3", "i18n": "0.8.3", diff --git a/app/renderer/js/preload.ts b/app/renderer/js/preload.ts index 968d80807..0a867c831 100644 --- a/app/renderer/js/preload.ts +++ b/app/renderer/js/preload.ts @@ -104,7 +104,8 @@ window.addEventListener('beforeunload', (): void => { // electron's globalShortcut can cause unexpected results // so adding the reload shortcut in the old-school way -// Zoom from numpad keys is not supported by electron, so adding it through listeners. +// electron does not support adding multiple accelerators for a menu item +// so adding numpad shortcuts here document.addEventListener('keydown', event => { const cmdOrCtrl = event.ctrlKey || event.metaKey; if (event.code === 'F5') { diff --git a/package-lock.json b/package-lock.json index 776656ca8..1d44a3674 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,13 @@ { "name": "zulip", - "version": "3.1.0-beta", + "version": "4.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "7zip-bin": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-4.1.0.tgz", - "integrity": "sha512-AsnBZN3a8/JcNt+KPkGGODaA4c7l3W5+WpeKgGSbstSLxqWtTXqd1ieJGBQ8IFCtRg8DmmKUcSkIkUc0A4p3YA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.0.3.tgz", + "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==", "dev": true }, "@babel/code-frame": { @@ -238,6 +238,42 @@ } } }, + "@develar/schema-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.1.0.tgz", + "integrity": "sha512-qjCqB4ctMig9Gz5bd6lkdFr3bO6arOdQqptdBSpF1ZpCnjofieCciEzkoS9ujY9cMGyllYSCSmBJ3x9OKHXzoA==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -254,6 +290,21 @@ "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, "@types/adm-zip": { "version": "0.4.32", "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.32.tgz", @@ -263,6 +314,12 @@ "@types/node": "*" } }, + "@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "dev": true + }, "@types/dotenv": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz", @@ -545,9 +602,9 @@ } }, "ajv-keywords": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", - "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", "dev": true }, "ansi-align": { @@ -648,41 +705,39 @@ } }, "app-builder-bin": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-2.6.6.tgz", - "integrity": "sha512-G0Ee6xkbxV+fvM/7xXWIgSDjWAD4E/d/aNbxerq/TVsCyBIau/0VPmrEqBMyZv0NbTwLDW5aF/yHG+0ZEY77kA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.4.3.tgz", + "integrity": "sha512-qMhayIwi3juerQEVJMQ76trObEbfQT0nhUdxZz9a26/3NLT3pE6awmQ8S1cEnrGugaaM5gYqR8OElcDezfmEsg==", "dev": true }, "app-builder-lib": { - "version": "20.40.2", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-20.40.2.tgz", - "integrity": "sha512-SAbfua8+L3pFbQp3QFpKV0PzHJPJqepROeX/FPrfdL02zxlw+BVOe6KfC3+UV6XUombWvVPG+SwG956vfIx/Cw==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-21.2.0.tgz", + "integrity": "sha512-aOX/nv77/Bti6NymJDg7p9T067xD8m1ipIEJR7B4Mm1GsJWpMm9PZdXtCRiMNRjHtQS5KIljT0g17781y6qn5A==", "dev": true, "requires": { - "7zip-bin": "~4.1.0", - "app-builder-bin": "2.6.6", + "7zip-bin": "~5.0.3", + "@develar/schema-utils": "~2.1.0", "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.7", - "builder-util": "9.7.1", - "builder-util-runtime": "8.2.1", + "bluebird-lst": "^1.0.9", + "builder-util": "21.2.0", + "builder-util-runtime": "8.3.0", "chromium-pickle-js": "^0.2.0", "debug": "^4.1.1", - "ejs": "^2.6.1", - "electron-osx-sign": "0.4.11", - "electron-publish": "20.40.0", - "fs-extra-p": "^7.0.1", + "ejs": "^2.6.2", + "electron-publish": "21.2.0", + "fs-extra": "^8.1.0", "hosted-git-info": "^2.7.1", "is-ci": "^2.0.0", - "isbinaryfile": "^4.0.0", - "js-yaml": "^3.13.0", + "isbinaryfile": "^4.0.2", + "js-yaml": "^3.13.1", "lazy-val": "^1.0.4", "minimatch": "^3.0.4", "normalize-package-data": "^2.5.0", - "plist": "^3.0.1", - "read-config-file": "3.2.2", - "sanitize-filename": "^1.6.1", - "semver": "^6.0.0", - "temp-file": "^3.3.2" + "read-config-file": "5.0.0", + "sanitize-filename": "^1.6.2", + "semver": "^6.3.0", + "temp-file": "^3.3.4" }, "dependencies": { "debug": { @@ -695,10 +750,13 @@ } }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.2.tgz", + "integrity": "sha512-CyjlXII6LMsPMyUzxpTt8fzh5QwzGqPmQXgY/Jyf4Zfp27t/FvfhwoE/8laaMUcMy816CkWF20I7NeQhwwY88w==", + "dev": true, + "requires": { + "lru-cache": "^5.1.1" + } }, "is-ci": { "version": "2.0.0", @@ -709,20 +767,19 @@ "ci-info": "^2.0.0" } }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "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==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "yallist": "^3.0.2" } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "normalize-package-data": { @@ -752,18 +809,24 @@ "dev": true }, "resolve": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", - "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", "dev": true, "requires": { "path-parse": "^1.0.6" } }, "semver": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", - "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "dev": true } } @@ -1347,18 +1410,18 @@ } }, "bluebird": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", - "integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==", + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", "dev": true }, "bluebird-lst": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.8.tgz", - "integrity": "sha512-InUDOaBaIjIobOa3O4YRAbFgff907uTJZXW0m0rhk3zhVZ4GvsmdCLEAKC1CTWTtUWCM8iWTTfFX9N/xQR/etw==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", + "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", "dev": true, "requires": { - "bluebird": "^3.5.4" + "bluebird": "^3.5.5" } }, "boom": { @@ -1531,23 +1594,24 @@ "dev": true }, "builder-util": { - "version": "9.7.1", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-9.7.1.tgz", - "integrity": "sha512-txpzYIeuHFjrOQWPTJDvhJYisIVGJdSG9ppccE+y7agT0YNhBlVHGnd8+HgFTajYE34xzB5zf1/zxiiDqSKSpA==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-21.2.0.tgz", + "integrity": "sha512-Nd6CUb6YgDY8EXAXEIegx+1kzKqyFQ5ZM5BoYkeunAlwz/zDJoH1UCyULjoS5wQe5czNClFQy07zz2bzYD0Z4A==", "dev": true, "requires": { - "7zip-bin": "~4.1.0", - "app-builder-bin": "2.6.6", - "bluebird-lst": "^1.0.7", - "builder-util-runtime": "^8.2.1", + "7zip-bin": "~5.0.3", + "@types/debug": "^4.1.4", + "app-builder-bin": "3.4.3", + "bluebird-lst": "^1.0.9", + "builder-util-runtime": "8.3.0", "chalk": "^2.4.2", "debug": "^4.1.1", - "fs-extra-p": "^7.0.1", + "fs-extra": "^8.1.0", "is-ci": "^2.0.0", - "js-yaml": "^3.13.0", - "source-map-support": "^0.5.11", + "js-yaml": "^3.13.1", + "source-map-support": "^0.5.13", "stat-mode": "^0.3.0", - "temp-file": "^3.3.2" + "temp-file": "^3.3.4" }, "dependencies": { "chalk": { @@ -1579,33 +1643,21 @@ "ci-info": "^2.0.0" } }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "builder-util-runtime": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.2.1.tgz", - "integrity": "sha512-2TkeTcI9bDlK5azRZSJJNxhAgW1DK+JY3jHK0UWPxgJcan4GZSVDNNO3sXntNxrp+JAdPHMF14rzNd/G53lvqw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.3.0.tgz", + "integrity": "sha512-CSOdsYqf4RXIHh1HANPbrZHlZ9JQJXSuDDloblZPcWQVN62inyYoTQuSmY3KrgefME2Sv3Kn2MxHvbGQHRf8Iw==", "dev": true, "requires": { - "bluebird-lst": "^1.0.7", "debug": "^4.1.1", - "fs-extra-p": "^7.0.1", "sax": "^1.2.4" }, "dependencies": { @@ -1619,9 +1671,9 @@ } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } @@ -1649,6 +1701,48 @@ "unset-value": "^1.0.0" } }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", @@ -1712,7 +1806,8 @@ "capture-stack-trace": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" + "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", + "dev": true }, "caseless": { "version": "0.12.0", @@ -1952,6 +2047,15 @@ "is-supported-regexp-flag": "^1.0.0" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, "clone-stats": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", @@ -2102,12 +2206,6 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, - "compare-version": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", - "integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=", - "dev": true - }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", @@ -2401,6 +2499,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, "requires": { "capture-stack-trace": "^1.0.0" } @@ -2581,6 +2680,15 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, "deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", @@ -2637,6 +2745,12 @@ "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", "dev": true }, + "defer-to-connect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.0.2.tgz", + "integrity": "sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw==", + "dev": true + }, "define-properties": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", @@ -2758,29 +2872,27 @@ } }, "dmg-builder": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-6.6.1.tgz", - "integrity": "sha512-aIbpQG3es+gHTFtsBQE4fmSYVM60yewxJZsN6FhkAmAmNaoO45bEQNJZsRX0YE49+imiSC92mJmFAEP6iKE0Tg==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-21.2.0.tgz", + "integrity": "sha512-9cJEclnGy7EyKFCoHDYDf54pub/t92CQapyiUxU0w9Bj2vUvfoDagP1PMiX4XD5rPp96141h9A+QN0OB4VgvQg==", "dev": true, "requires": { - "app-builder-lib": "~20.40.0", - "bluebird-lst": "^1.0.7", - "builder-util": "~9.7.1", - "fs-extra-p": "^7.0.1", - "iconv-lite": "^0.4.24", - "js-yaml": "^3.13.0", - "parse-color": "^1.0.0", - "sanitize-filename": "^1.6.1" + "app-builder-lib": "~21.2.0", + "bluebird-lst": "^1.0.9", + "builder-util": "~21.2.0", + "fs-extra": "^8.1.0", + "iconv-lite": "^0.5.0", + "js-yaml": "^3.13.1", + "sanitize-filename": "^1.6.2" }, "dependencies": { - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "iconv-lite": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz", + "integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "safer-buffer": ">= 2.1.2 < 3" } } } @@ -2847,15 +2959,15 @@ } }, "dotenv": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", - "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.0.0.tgz", + "integrity": "sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg==", "dev": true }, "dotenv-expand": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz", - "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true }, "duplexer": { @@ -2876,7 +2988,8 @@ "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true }, "duplexify": { "version": "3.6.0", @@ -2951,51 +3064,88 @@ } }, "ejs": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", - "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.2.tgz", + "integrity": "sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q==", "dev": true }, "electron": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/electron/-/electron-3.1.10.tgz", - "integrity": "sha512-IORdmdD5gWHmp3ffa+ZRD9kESJwdmQz8carDTeza6+W76dG447AUn7GmKk4cun31bLYTKb56D8pPhxa9S7kOZQ==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/electron/-/electron-5.0.8.tgz", + "integrity": "sha512-wkUVE2GaYCsqQTsISSHWkIkcdpwLwZ1jhzAXSFFoSzsTgugmzhX60rJjIccotUmZ0iPzw+u4ahfcaJ0eslrPNQ==", "dev": true, "requires": { - "@types/node": "^8.0.24", + "@types/node": "^10.12.18", "electron-download": "^4.1.0", "extract-zip": "^1.0.3" }, "dependencies": { "@types/node": { - "version": "8.10.49", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.49.tgz", - "integrity": "sha512-YX30JVx0PvSmJ3Eqr74fYLGeBxD+C7vIL20ek+GGGLJeUbVYRUW3EzyAXpIRA0K8c8o0UWqR/GwEFYiFoz1T8w==", + "version": "10.14.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.15.tgz", + "integrity": "sha512-CBR5avlLcu0YCILJiDIXeU2pTw7UK/NIxfC63m7d7CVamho1qDEzXKkOtEauQRPMy6MI8mLozth+JJkas7HY6g==", "dev": true } } }, "electron-builder": { - "version": "20.40.2", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-20.40.2.tgz", - "integrity": "sha512-hnnBzyLXna+WpmT4MIoWVdRli43q09yqKOgzPJj0KrOoJZ7TIoY1aYSPvSg8VL5rSuTgdAWGL4rYd9zcq3YXMQ==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-21.2.0.tgz", + "integrity": "sha512-x8EXrqFbAb2L3N22YlGar3dGh8vwptbB3ovo3OF6K7NTpcsmM2zEoJv7GhFyX73rNzSG2HaWpXwGAtOp2JWiEw==", "dev": true, "requires": { - "app-builder-lib": "20.40.2", - "bluebird-lst": "^1.0.7", - "builder-util": "9.7.1", - "builder-util-runtime": "8.2.1", + "app-builder-lib": "21.2.0", + "bluebird-lst": "^1.0.9", + "builder-util": "21.2.0", + "builder-util-runtime": "8.3.0", "chalk": "^2.4.2", - "dmg-builder": "6.6.1", - "fs-extra-p": "^7.0.1", + "dmg-builder": "21.2.0", + "fs-extra": "^8.1.0", "is-ci": "^2.0.0", "lazy-val": "^1.0.4", - "read-config-file": "3.2.2", - "sanitize-filename": "^1.6.1", - "update-notifier": "^2.5.0", - "yargs": "^13.2.2" + "read-config-file": "5.0.0", + "sanitize-filename": "^1.6.2", + "update-notifier": "^3.0.1", + "yargs": "^13.3.0" }, "dependencies": { + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "boxen": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", + "integrity": "sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^2.4.2", + "cli-boxes": "^2.2.0", + "string-width": "^3.0.0", + "term-size": "^1.2.0", + "type-fest": "^0.3.0", + "widest-line": "^2.0.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -3007,6 +3157,60 @@ "supports-color": "^5.3.0" } }, + "cli-boxes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", + "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", + "dev": true + }, + "configstore": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", + "integrity": "sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -3015,6 +3219,129 @@ "requires": { "ci-info": "^2.0.0" } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-npm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", + "integrity": "sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA==", + "dev": true + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + } + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "registry-auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", + "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", + "dev": true, + "requires": { + "rc": "^1.2.8", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "update-notifier": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz", + "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==", + "dev": true, + "requires": { + "boxen": "^3.0.0", + "chalk": "^2.0.1", + "configstore": "^4.0.0", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.1.0", + "is-npm": "^3.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } } } }, @@ -3125,44 +3452,19 @@ "keyboardevents-areequal": "^0.2.1" } }, - "electron-osx-sign": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.11.tgz", - "integrity": "sha512-VVd40nrnVqymvFrY9ZkOYgHJOvexHHYTR3di/SN+mjJ0OWhR1I8BRVj3U+Yamw6hnkZZNKZp52rqL5EFAAPFkQ==", - "dev": true, - "requires": { - "bluebird": "^3.5.0", - "compare-version": "^0.1.2", - "debug": "^2.6.8", - "isbinaryfile": "^3.0.2", - "minimist": "^1.2.0", - "plist": "^3.0.1" - }, - "dependencies": { - "isbinaryfile": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", - "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", - "dev": true, - "requires": { - "buffer-alloc": "^1.2.0" - } - } - } - }, "electron-publish": { - "version": "20.40.0", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-20.40.0.tgz", - "integrity": "sha512-mkjtsIgftRszuT/8do8TszmddokDnu254OyTeL8nE780o/A8t68oXHZzvlTJ4AQ8uBOYrA87JDO/BFCWjnVArA==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-21.2.0.tgz", + "integrity": "sha512-mWavuoWJe87iaeKd0I24dNWIaR+0yRzshjNVqGyK019H766fsPWl3caQJnVKFaEyrZRP397v4JZVG0e7s16AxA==", "dev": true, "requires": { - "bluebird-lst": "^1.0.7", - "builder-util": "~9.7.1", - "builder-util-runtime": "^8.2.1", + "bluebird-lst": "^1.0.9", + "builder-util": "~21.2.0", + "builder-util-runtime": "8.3.0", "chalk": "^2.4.2", - "fs-extra-p": "^7.0.1", + "fs-extra": "^8.1.0", "lazy-val": "^1.0.4", - "mime": "^2.4.1" + "mime": "^2.4.4" }, "dependencies": { "chalk": { @@ -3662,7 +3964,7 @@ "eslint-import-resolver-node": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha1-WPFfuDm40FdsqYBBNHaqskcttmo=", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", "dev": true, "requires": { "debug": "^2.6.9", @@ -4034,7 +4336,7 @@ "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { "estraverse": "^4.0.0" @@ -4089,7 +4391,8 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true + "dev": true, + "optional": true }, "expand-brackets": { "version": "2.1.4", @@ -4648,29 +4951,6 @@ } } }, - "fs-extra-p": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-7.0.1.tgz", - "integrity": "sha512-yhd2OV0HnHt2oitlp+X9hl2ReX4X/7kQeL7/72qzPHTZj5eUPGzAKOvEglU02Fa1OeG2rSy/aKB4WGVaLiF8tw==", - "dev": true, - "requires": { - "bluebird-lst": "^1.0.7", - "fs-extra": "^7.0.1" - }, - "dependencies": { - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, "fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", @@ -4763,7 +5043,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -4787,13 +5068,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4810,19 +5093,22 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4953,7 +5239,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4967,6 +5254,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4983,6 +5271,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4991,13 +5280,15 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5018,6 +5309,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5106,7 +5398,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5120,6 +5413,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5215,7 +5509,8 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -5257,6 +5552,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5278,6 +5574,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5326,13 +5623,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true + "dev": true, + "optional": true } } }, @@ -5378,7 +5677,8 @@ "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true }, "get-value": { "version": "2.0.6", @@ -5649,79 +5949,11 @@ } } }, - "google-translate-api": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/google-translate-api/-/google-translate-api-2.3.0.tgz", - "integrity": "sha1-YmcwoSPaDVevNzXdcHzacc7pGcc=", - "dev": true, - "requires": { - "configstore": "^2.0.0", - "got": "^6.3.0", - "safe-eval": "^0.3.0" - }, - "dependencies": { - "configstore": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz", - "integrity": "sha1-c3o6cDbpiGECqmCZ5HuzOrGroaE=", - "requires": { - "dot-prop": "^3.0.0", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "object-assign": "^4.0.1", - "os-tmpdir": "^1.0.0", - "osenv": "^0.1.0", - "uuid": "^2.0.1", - "write-file-atomic": "^1.1.2", - "xdg-basedir": "^2.0.0" - } - }, - "dot-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", - "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", - "requires": { - "is-obj": "^1.0.0" - } - }, - "google-translate-token": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/google-translate-token/-/google-translate-token-1.0.0.tgz", - "integrity": "sha1-vpQ0RXhvAMN2Xewx9JDawhIo0/g=", - "requires": { - "configstore": "^2.0.0", - "got": "^6.3.0" - } - }, - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" - }, - "write-file-atomic": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - }, - "xdg-basedir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz", - "integrity": "sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=", - "requires": { - "os-homedir": "^1.0.0" - } - } - } - }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, "requires": { "create-error-class": "^3.0.0", "duplexer3": "^0.1.4", @@ -5739,7 +5971,8 @@ "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true }, "grapheme-splitter": { "version": "1.0.4", @@ -6433,6 +6666,12 @@ "readable-stream": "1.1" } }, + "http-cache-semantics": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==", + "dev": true + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -6519,7 +6758,8 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, "indent-string": { "version": "2.1.0", @@ -6914,7 +7154,8 @@ "is-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true }, "is-obj-prop": { "version": "1.0.0", @@ -6986,7 +7227,8 @@ "is-redirect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true }, "is-regex": { "version": "1.0.4", @@ -7015,12 +7257,14 @@ "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true }, "is-supported-regexp-flag": { "version": "1.0.1", @@ -7088,6 +7332,12 @@ "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", "dev": true }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -7095,9 +7345,9 @@ "dev": true }, "isbinaryfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.0.tgz", - "integrity": "sha512-RBtmso6l2mCaEsUvXngMTIjg3oheXo0MgYzzfT6sk44RYggPnm9fT+cQJAmzRnJIxPHXg9FZglqDJGW28dvcqA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.2.tgz", + "integrity": "sha512-C3FSxJdNrEr2F4z6uFtNzECDM5hXk+46fxaa+cwBe5/XrWSmzdG8DDgyjfX6/NRdBB21q2JXuRAzPCUs+fclnQ==", "dev": true }, "isexe": { @@ -7187,6 +7437,12 @@ } } }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -7280,6 +7536,15 @@ "integrity": "sha1-iBkexzjOn3WRwl6QVt6Si0AncZQ=", "dev": true }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -7666,7 +7931,8 @@ "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=" + "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", + "dev": true }, "lru-cache": { "version": "4.1.3", @@ -7696,15 +7962,6 @@ "kind-of": "^6.0.2" } }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -7765,25 +8022,6 @@ "unist-util-visit": "^1.1.0" } }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - } - } - }, "meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", @@ -7830,9 +8068,9 @@ } }, "mime": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.3.tgz", - "integrity": "sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", "dev": true }, "mime-db": { @@ -7856,6 +8094,12 @@ "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", "dev": true }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -7906,6 +8150,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "dev": true, "requires": { "minimist": "0.0.8" }, @@ -7913,7 +8158,8 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true } } }, @@ -8103,6 +8349,12 @@ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", "dev": true }, + "normalize-url": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.3.0.tgz", + "integrity": "sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ==", + "dev": true + }, "now-and-later": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz", @@ -8169,7 +8421,8 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-copy": { "version": "0.1.0", @@ -8412,82 +8665,8 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true }, "os-shim": { "version": "0.1.3", @@ -8498,21 +8677,23 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true }, "osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha1-hc36+uso6Gd/QW4odZK18/SepBA=", + "dev": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" } }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true }, "p-finally": { @@ -8521,12 +8702,6 @@ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, "p-limit": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", @@ -8580,23 +8755,6 @@ } } }, - "parse-color": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz", - "integrity": "sha1-e3SLlag/A/FqlPU15S1/PZRlhhk=", - "dev": true, - "requires": { - "color-convert": "~0.5.0" - }, - "dependencies": { - "color-convert": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", - "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=", - "dev": true - } - } - }, "parse-entities": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", @@ -8874,17 +9032,6 @@ } } }, - "plist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", - "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", - "dev": true, - "requires": { - "base64-js": "^1.2.3", - "xmlbuilder": "^9.0.7", - "xmldom": "0.1.x" - } - }, "plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", @@ -9157,7 +9304,8 @@ "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true }, "prettier": { "version": "1.18.2", @@ -9314,56 +9462,17 @@ } }, "read-config-file": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-3.2.2.tgz", - "integrity": "sha512-PuFpMgZF01VB0ydH1dfitAxCP/fh+qnfbA9cYNIPoxPbz0SMngsrafCtaHDWfER7MwlDz4fmrNBhPkakxxFpTg==", - "dev": true, - "requires": { - "ajv": "^6.9.2", - "ajv-keywords": "^3.4.0", - "bluebird-lst": "^1.0.7", - "dotenv": "^6.2.0", - "dotenv-expand": "^4.2.0", - "fs-extra-p": "^7.0.1", - "js-yaml": "^3.12.1", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-5.0.0.tgz", + "integrity": "sha512-jIKUu+C84bfnKxyJ5j30CxCqgXWYjZLXuVE/NYlMEpeni+dhESgAeZOZd0JZbg1xTkMmnCdxksDoarkOyfEsOg==", + "dev": true, + "requires": { + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^8.1.0", + "js-yaml": "^3.13.1", "json5": "^2.1.0", "lazy-val": "^1.0.4" - }, - "dependencies": { - "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - } } }, "read-pkg": { @@ -9814,6 +9923,15 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -9906,7 +10024,8 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "safe-regex": { "version": "1.1.0", @@ -9924,9 +10043,9 @@ "dev": true }, "sanitize-filename": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz", - "integrity": "sha1-YS2hyWRz+gLczaktzVtKsWSmdyo=", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.2.tgz", + "integrity": "sha512-cmTzND7RMxUB+f7gI+4+KAVHWEg0lfXvQJdko+FXDP5bNbGIdx4KMP5pX6lv5jfT9jSf6OBbjyxjFtZQwYA/ig==", "dev": true, "requires": { "truncate-utf8-bytes": "^1.0.0" @@ -10055,7 +10174,8 @@ "slide": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true }, "snapdragon": { "version": "0.8.2", @@ -10208,9 +10328,9 @@ } }, "source-map-support": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", - "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -11347,14 +11467,13 @@ } }, "temp-file": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.2.tgz", - "integrity": "sha512-FGKccAW0Mux9hC/2bdUIe4bJRv4OyVo4RpVcuplFird1V/YoplIFbnPZjfzbJSf/qNvRZIRB9/4n/RkI0GziuQ==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.4.tgz", + "integrity": "sha512-qSZ5W5q54iyGnP8cNl49RE0jTJc5CrzNocux5APD5yIxcgonoMuMSbsZfaZy8rTGCYo0Xz6ySVv3adagZ8gffg==", "dev": true, "requires": { "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.6", - "fs-extra-p": "^7.0.0" + "fs-extra": "^8.1.0" } }, "term-size": { @@ -11473,7 +11592,8 @@ "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true }, "tmp": { "version": "0.0.33", @@ -11526,6 +11646,12 @@ } } }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", @@ -11714,6 +11840,12 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -11967,7 +12099,8 @@ "unzip-response": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true }, "upath": { "version": "1.0.5", @@ -12038,6 +12171,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, "requires": { "prepend-http": "^1.0.1" } @@ -12581,18 +12715,6 @@ "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", "dev": true }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "dev": true - }, - "xmldom": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", - "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", - "dev": true - }, "xo": { "version": "0.24.0", "resolved": "https://registry.npmjs.org/xo/-/xo-0.24.0.tgz", @@ -12940,22 +13062,21 @@ "dev": true }, "yargs": { - "version": "13.2.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", - "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", "dev": true, "requires": { "cliui": "^5.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.0" + "yargs-parser": "^13.1.1" }, "dependencies": { "ansi-regex": { @@ -13060,9 +13181,9 @@ } }, "yargs-parser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.0.tgz", - "integrity": "sha512-Yq+32PrijHRri0vVKQEm+ys8mbqWjLiwQkMFNXEENutzLPP0bE4Lcd4iA3OQY5HF+GD3xXxf0MEHb8E4/SA3AA==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { "camelcase": "^5.0.0", diff --git a/package.json b/package.json index 4693b72e3..f87ef3751 100644 --- a/package.json +++ b/package.json @@ -147,8 +147,8 @@ "assert": "1.4.1", "cp-file": "5.0.0", "devtron": "1.4.0", - "electron": "3.1.10", - "electron-builder": "20.40.2", + "electron": "5.0.8", + "electron-builder": "21.2.0", "electron-connect": "0.6.2", "electron-debug": "1.4.0", "eslint-config-xo-typescript": "0.14.0", From decf47e5127423cec52548d03f5cd89c4b48ebf1 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Sun, 4 Aug 2019 14:40:47 +0530 Subject: [PATCH 19/28] gitignore: Add .vscode to gitignore. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 8f2ecac37..d18775a6b 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ config.gypi # Ignore all the typescript compiled files app/**/*.js + +# text editor files +.vscode/ \ No newline at end of file From 10a20507021beb608007b2b80ad9e7ad8e04b055 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Sun, 4 Aug 2019 16:00:11 +0530 Subject: [PATCH 20/28] BrowserView: Show views only when dom content loaded. Adds a refresh function which refreshes view every 200 ms, and shows it only if the view DOM content is loaded. Also, gets rid of buggy browser view switching which we were facing earlier. --- app/main/index.ts | 2 +- app/main/view.ts | 3 +++ app/main/viewmanager.ts | 40 +++++++++++++++++++++++++++++++--------- app/renderer/js/main.ts | 5 +++++ 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/app/main/index.ts b/app/main/index.ts index 010132134..2e3a4674d 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -264,7 +264,7 @@ app.on('ready', () => { }); ipcMain.on('fix-bounds', () => { - ViewManager.fixBounds(); + ViewManager.fixBounds(mainWindow); }); ipcMain.on('update-badge', (_event: Electron.IpcMessageEvent, messageCount: number) => { diff --git a/app/main/view.ts b/app/main/view.ts index 47246c8c3..03be0b29d 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -21,6 +21,7 @@ export class View extends BrowserView { url: string; zoomFactor: number; customCSS: string | null; + loading: boolean; constructor(public props: ViewProps) { super({ @@ -34,6 +35,7 @@ export class View extends BrowserView { this.index = props.index; this.url = props.url; this.zoomFactor = 1.0; + this.loading = false; this.customCSS = ConfigUtil.getConfigItem('customCSS'); this.registerListeners(); this.setUserAgent(); @@ -157,6 +159,7 @@ export class View extends BrowserView { } switchLoadingIndicator(state: boolean): void { + this.loading = state; const isSettingsPage = this.url.includes('renderer/preference.html'); if (!isSettingsPage) { this.sendAction('switch-loading', state, this.url); diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index 778e9f1a5..e98f70ff9 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -5,13 +5,15 @@ import { View, ViewProps } from './view'; import ConfigUtil = require('../renderer/js/utils/config-util'); +let refreshViews: any = null; + class ViewManager { views: { [key: number]: View }; selectedIndex: number; constructor() { this.views = {}; - this.selectedIndex = 0; + this.selectedIndex = -1; this.registerIpcs(); } @@ -51,6 +53,30 @@ class ViewManager { // So, using a workaround here. (this.views[index] as any)[name as keyof View](...params); }); + + ipcMain.on('server-load-complete', () => { + let viewIsNull = true; + let viewIndex = -1; + const mainWindow = BrowserWindow.getAllWindows()[0]; + refreshViews = setInterval(() => { + const view = this.views[this.selectedIndex]; + if (!view || view.isDestroyed()) { + return; + } + if (view.loading === false) { + if ((viewIsNull) || (viewIndex !== view.index)) { + viewIsNull = false; + viewIndex = view.index; + mainWindow.setBrowserView(view); + this.fixBounds(mainWindow); + } + } else if (viewIsNull === false) { + viewIsNull = true; + viewIndex = -1; + mainWindow.setBrowserView(null); + } + }, 200); + }); } create(props: ViewProps): void { @@ -63,25 +89,19 @@ class ViewManager { } select(index: number): void { - const mainWindow = BrowserWindow.getAllWindows()[0]; const view = this.views[index]; if (!view || view.isDestroyed()) { console.log('Attempt to select a view that does not exist.'); return; } this.selectedIndex = index; - // Unset old view before setting new view - mainWindow.setBrowserView(null); if (!view.webContents.getURL()) { const { url } = view; view.webContents.loadURL(url); } - this.fixBounds(); - mainWindow.setBrowserView(view); - view.webContents.focus(); } - fixBounds(): void { + fixBounds(mainWindow: Electron.BrowserWindow): void { // Any updates to the sidebar width should reflect both here and in css const SIDEBAR_WIDTH = 54; const view = this.views[this.selectedIndex]; @@ -89,7 +109,6 @@ class ViewManager { if (!view || view.isDestroyed()) { return; } - const mainWindow = BrowserWindow.getAllWindows()[0]; const { width, height } = mainWindow.getContentBounds(); view.setBounds({ @@ -121,6 +140,9 @@ class ViewManager { for (const id in this.views) { this.destroy(this.views[id].index); } + if (refreshViews) { + clearInterval(refreshViews); + } } forwardMessageAll(name: string, ...args: any[]): void { diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index b08016baa..c3a23fadf 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -318,6 +318,7 @@ class ServerManagerView { } else { this.showLoading(true); } + this.initTabsComplete(); } initServer(server: any, index: number): void { @@ -387,6 +388,10 @@ class ServerManagerView { this.toggleDNDButton(dnd); } + initTabsComplete(): void { + ipcRenderer.send('server-load-complete'); + } + getTabIndex(): number { const currentIndex = this.tabIndex; this.tabIndex++; From 2d0153dc97494d1ebbcb95805c7e4a5a59bd606c Mon Sep 17 00:00:00 2001 From: vsvipul Date: Thu, 8 Aug 2019 01:50:06 +0530 Subject: [PATCH 21/28] BrowserView: Rename webview instances to view and handle tray toggle. --- app/main/index.ts | 4 +- app/main/view.ts | 8 +- app/main/viewmanager.ts | 21 +- app/renderer/css/main.css | 8 +- .../js/components/handle-external-link.ts | 6 +- app/renderer/js/components/webview.ts | 287 ------------------ app/renderer/js/main.ts | 58 +--- app/renderer/js/notification/helpers.ts | 5 +- app/renderer/js/tray.ts | 7 +- app/renderer/main.html | 2 +- 10 files changed, 55 insertions(+), 351 deletions(-) delete mode 100644 app/renderer/js/components/webview.ts diff --git a/app/main/index.ts b/app/main/index.ts index 2e3a4674d..1534dc759 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -223,7 +223,7 @@ app.on('ready', () => { // height: mainWindowState.height - paddingHeight, // webPreferences: { // plugins: true, - // partition: 'persist:webviewsession' + // partition: 'persist:viewsession' // } // }); // pdfWindow.loadURL(url); @@ -232,7 +232,7 @@ app.on('ready', () => { // pdfWindow.setMenu(null); // }); - // Reload full app not just webview, useful in debugging + // Reload full app not just view, useful in debugging ipcMain.on('reload-full-app', () => { ViewManager.destroyAll(); mainWindow.reload(); diff --git a/app/main/view.ts b/app/main/view.ts index 03be0b29d..b9da210e1 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -6,7 +6,7 @@ import path = require('path'); import fs = require('fs'); import ConfigUtil = require('../renderer/js/utils/config-util'); import SystemUtil = require('../renderer/js/utils/system-util'); -const shouldSilentWebview = ConfigUtil.getConfigItem('silent'); +const shouldSilentView = ConfigUtil.getConfigItem('silent'); export interface ViewProps { index: number; @@ -42,7 +42,7 @@ export class View extends BrowserView { } registerListeners(): void { - if (shouldSilentWebview) { + if (shouldSilentView) { this.webContents.addListener('dom-ready', () => { this.webContents.setAudioMuted(true); }); @@ -153,6 +153,10 @@ export class View extends BrowserView { this.webContents.setZoomFactor(this.zoomFactor); } + focus(): void { + this.webContents.focus(); + } + reload(): void { this.switchLoadingIndicator(true); this.webContents.reload(); diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index e98f70ff9..71287b42d 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -1,6 +1,6 @@ 'use strict'; -import { BrowserWindow, ipcMain } from 'electron'; +import { BrowserWindow, ipcMain, BrowserView } from 'electron'; import { View, ViewProps } from './view'; import ConfigUtil = require('../renderer/js/utils/config-util'); @@ -54,6 +54,25 @@ class ViewManager { (this.views[index] as any)[name as keyof View](...params); }); + ipcMain.on('toggle-silent', (e: Event, state: boolean) => { + for (const id in this.views) { + const view = this.views[id]; + try { + view.webContents.setAudioMuted(state); + } catch (err) { + // view is not ready yet + view.addListener('dom-ready', () => { + view.webContents.setAudioMuted(state); + }); + } + } + }); + + ipcMain.on('focus-view-with-contents', (e: Event, contents: Electron.webContents) => { + const view = BrowserView.fromWebContents(contents); + view.webContents.focus(); + }); + ipcMain.on('server-load-complete', () => { let viewIsNull = true; let viewIndex = -1; diff --git a/app/renderer/css/main.css b/app/renderer/css/main.css index ed63111db..fc47ad518 100644 --- a/app/renderer/css/main.css +++ b/app/renderer/css/main.css @@ -281,17 +281,17 @@ body { } /******************* - * Webview Area * + * View Area * *******************/ -#webviews-container { +#views-container { display: flex; height: 100%; width: 100%; } /* Pseudo element for loading indicator */ -#webviews-container::before { +#views-container::before { content: ""; position: absolute; z-index: 1; @@ -303,7 +303,7 @@ body { } /* When the active webview is loaded */ -#webviews-container.loaded::before { +#views-container.loaded::before { opacity: 0; z-index: -1; visibility: hidden; diff --git a/app/renderer/js/components/handle-external-link.ts b/app/renderer/js/components/handle-external-link.ts index 49f28b811..47586cd09 100644 --- a/app/renderer/js/components/handle-external-link.ts +++ b/app/renderer/js/components/handle-external-link.ts @@ -29,7 +29,7 @@ function handleExternalLink(index: number, url: string): void { // download txt, mp3, mp4 etc.. by using downloadURL in the // main process which allows the user to save the files to their desktop - // and not trigger webview reload while image in webview will + // and not trigger view reload while image in view will // do nothing and will not save it // Code to show pdf in a new BrowserWindow (currently commented out due to bug-upstream) @@ -61,14 +61,14 @@ function handleExternalLink(index: number, url: string): void { ipcRenderer.once('downloadFileFailed', () => { // Automatic download failed, so show save dialog prompt and download - // through webview + // through view ipcRenderer.send('call-specific-view-function', index, 'downloadUrl', url); ipcRenderer.removeAllListeners('downloadFileCompleted'); }); return; } - // open internal urls inside the current webview. + // open internal urls inside the current view. ipcRenderer.send('call-specific-view-function', index, 'loadUrl', url); } else { shell.openExternal(url); diff --git a/app/renderer/js/components/webview.ts b/app/renderer/js/components/webview.ts deleted file mode 100644 index b95cbe4da..000000000 --- a/app/renderer/js/components/webview.ts +++ /dev/null @@ -1,287 +0,0 @@ -'use strict'; -import { remote } from 'electron'; - -import path = require('path'); -import fs = require('fs'); -import ConfigUtil = require('../utils/config-util'); -import SystemUtil = require('../utils/system-util'); -import BaseComponent = require('../components/base'); -// import handleExternalLink = require('../components/handle-external-link'); - -const { app, dialog } = remote; - -const shouldSilentWebview = ConfigUtil.getConfigItem('silent'); - -// TODO: TypeScript - Type annotate WebViewProps. -interface WebViewProps { - [key: string]: any; -} - -class WebView extends BaseComponent { - props: any; - zoomFactor: number; - badgeCount: number; - loading: boolean; - customCSS: string; - $webviewsContainer: DOMTokenList; - $el: Electron.WebviewTag; - - // This is required because in main.js we access WebView.method as - // webview[method]. - [key: string]: any; - - constructor(props: WebViewProps) { - super(); - - this.props = props; - this.zoomFactor = 1.0; - this.loading = true; - this.badgeCount = 0; - this.customCSS = ConfigUtil.getConfigItem('customCSS'); - this.$webviewsContainer = document.querySelector('#webviews-container').classList; - } - - template(): string { - return ` - `; - } - - init(): void { - this.$el = this.generateNodeFromTemplate(this.template()) as Electron.WebviewTag; - this.props.$root.append(this.$el); - - this.registerListeners(); - } - - registerListeners(): void { - this.$el.addEventListener('new-window', event => { - // handleExternalLink.call(this, event); - }); - - if (shouldSilentWebview) { - this.$el.addEventListener('dom-ready', () => { - this.$el.setAudioMuted(true); - }); - } - - this.$el.addEventListener('page-title-updated', event => { - const { title } = event; - this.badgeCount = this.getBadgeCount(title); - this.props.onTitleChange(); - }); - - this.$el.addEventListener('did-navigate-in-page', event => { - const isSettingPage = event.url.includes('renderer/preference.html'); - if (isSettingPage) { - return; - } - this.canGoBackButton(); - }); - - this.$el.addEventListener('did-navigate', () => { - this.canGoBackButton(); - }); - - this.$el.addEventListener('page-favicon-updated', event => { - const { favicons } = event; - - // This returns a string of favicons URL. If there is a PM counts in unread messages then the URL would be like - // https://chat.zulip.org/static/images/favicon/favicon-pms.png - if (favicons[0].indexOf('favicon-pms') > 0 && process.platform === 'darwin') { - // This api is only supported on macOS - app.dock.setBadge('●'); - // bounce the dock - if (ConfigUtil.getConfigItem('dockBouncing')) { - app.dock.bounce(); - } - } - }); - - this.$el.addEventListener('dom-ready', () => { - if (this.props.role === 'server') { - this.$el.classList.add('onload'); - } - this.loading = false; - this.props.switchLoading(false, this.props.url); - this.show(); - - // Refocus text boxes after reload - // Remove when upstream issue https://github.com/electron/electron/issues/14474 is fixed - this.$el.blur(); - this.$el.focus(); - }); - - this.$el.addEventListener('did-fail-load', event => { - const { errorDescription } = event; - const hasConnectivityErr = SystemUtil.connectivityERR.includes(errorDescription); - if (hasConnectivityErr) { - console.error('error', errorDescription); - this.props.onNetworkError(); - } - }); - - this.$el.addEventListener('did-start-loading', () => { - const isSettingPage = this.props.url.includes('renderer/preference.html'); - if (!isSettingPage) { - this.props.switchLoading(true, this.props.url); - } - let userAgent = SystemUtil.getUserAgent(); - if (!userAgent) { - SystemUtil.setUserAgent(this.$el.getUserAgent()); - userAgent = SystemUtil.getUserAgent(); - } - this.$el.setUserAgent(userAgent); - }); - - this.$el.addEventListener('did-stop-loading', () => { - this.props.switchLoading(false, this.props.url); - }); - } - - getBadgeCount(title: string): number { - const messageCountInTitle = (/\((\d+)\)/).exec(title); - return messageCountInTitle ? Number(messageCountInTitle[1]) : 0; - } - - show(): void { - // Do not show WebView if another tab was selected and this tab should be in background. - if (!this.props.isActive()) { - return; - } - - // To show or hide the loading indicator in the the active tab - if (this.loading) { - this.$webviewsContainer.remove('loaded'); - } else { - this.$webviewsContainer.add('loaded'); - } - - this.$el.classList.remove('disabled'); - this.$el.classList.add('active'); - setTimeout(() => { - if (this.props.role === 'server') { - this.$el.classList.remove('onload'); - } - }, 1000); - this.focus(); - this.props.onTitleChange(); - // Injecting preload css in webview to override some css rules - this.$el.insertCSS(fs.readFileSync(path.join(__dirname, '/../../css/preload.css'), 'utf8')); - - // get customCSS again from config util to avoid warning user again - this.customCSS = ConfigUtil.getConfigItem('customCSS'); - if (this.customCSS) { - if (!fs.existsSync(this.customCSS)) { - this.customCSS = null; - ConfigUtil.setConfigItem('customCSS', null); - - const errMsg = 'The custom css previously set is deleted!'; - dialog.showErrorBox('custom css file deleted!', errMsg); - return; - } - - this.$el.insertCSS(fs.readFileSync(path.resolve(__dirname, this.customCSS), 'utf8')); - } - } - - focus(): void { - // focus Webview and it's contents when Window regain focus. - const webContents = this.$el.getWebContents(); - // HACK: webContents.isFocused() seems to be true even without the element - // being in focus. So, we check against `document.activeElement`. - if (webContents && this.$el !== document.activeElement) { - // HACK: Looks like blur needs to be called on the previously focused - // element to transfer focus correctly, in Electron v3.0.10 - // See https://github.com/electron/electron/issues/15718 - (document.activeElement as HTMLElement).blur(); - this.$el.focus(); - webContents.focus(); - } - } - - hide(): void { - this.$el.classList.add('disabled'); - this.$el.classList.remove('active'); - } - - load(): void { - if (this.$el) { - this.show(); - } else { - this.init(); - } - } - - zoomIn(): void { - this.zoomFactor += 0.1; - this.$el.setZoomFactor(this.zoomFactor); - } - - zoomOut(): void { - this.zoomFactor -= 0.1; - this.$el.setZoomFactor(this.zoomFactor); - } - - zoomActualSize(): void { - this.zoomFactor = 1.0; - this.$el.setZoomFactor(this.zoomFactor); - } - - logOut(): void { - this.$el.executeJavaScript('logout()'); - } - - showShortcut(): void { - this.$el.executeJavaScript('shortcut()'); - } - - openDevTools(): void { - this.$el.openDevTools(); - } - - back(): void { - if (this.$el.canGoBack()) { - this.$el.goBack(); - this.focus(); - } - } - - canGoBackButton(): void { - const $backButton = document.querySelector('#actions-container #back-action'); - if (this.$el.canGoBack()) { - $backButton.classList.remove('disable'); - } else { - $backButton.classList.add('disable'); - } - } - - forward(): void { - if (this.$el.canGoForward()) { - this.$el.goForward(); - } - } - - reload(): void { - this.hide(); - // Shows the loading indicator till the webview is reloaded - this.$webviewsContainer.remove('loaded'); - this.loading = true; - this.props.switchLoading(true, this.props.url); - this.$el.reload(); - } - - send(channel: string, ...param: any[]): void { - this.$el.send(channel, ...param); - } -} - -export = WebView; diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index c3a23fadf..d041948a9 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -77,7 +77,7 @@ class ServerManagerView { $reloadButton: HTMLButtonElement; $loadingIndicator: HTMLButtonElement; $settingsButton: HTMLButtonElement; - $webviewsContainer: Element; + $viewsContainer: Element; $backButton: HTMLButtonElement; $dndButton: HTMLButtonElement; $sidebar: Element; @@ -98,7 +98,7 @@ class ServerManagerView { this.$reloadButton = $actionsContainer.querySelector('#reload-action'); this.$loadingIndicator = $actionsContainer.querySelector('#loading-action'); this.$settingsButton = $actionsContainer.querySelector('#settings-action'); - this.$webviewsContainer = document.querySelector('#webviews-container'); + this.$viewsContainer = document.querySelector('#views-container'); this.$backButton = $actionsContainer.querySelector('#back-action'); this.$dndButton = $actionsContainer.querySelector('#dnd-action'); @@ -403,11 +403,6 @@ class ServerManagerView { } displayInitialCharLogo($img: HTMLImageElement, index: number): void { - /* - index parameter needed because webview[data-tab-id] can increment - beyond size of sidebar org array and throw error - */ - const $altIcon = document.createElement('div'); const $parent = $img.parentElement; const realmName = this.tabs[index].props.name; @@ -458,8 +453,8 @@ class ServerManagerView { }; ipcRenderer.send('create-view', props); // To show loading indicator the first time a functional tab is opened, indicator is - // closed when the functional tab DOM is ready, handled in webview.js - this.$webviewsContainer.classList.remove('loaded'); + // overlapped by the view when the functional tab DOM is ready + this.$viewsContainer.classList.remove('loaded'); this.activateTab(this.functionalTabs[tabProps.name]); } @@ -499,8 +494,7 @@ class ServerManagerView { // returns this.tabs in an way that does // not crash app when this.tabs is passed into - // ipcRenderer. Something about webview, and props.webview - // properties in ServerTab causes the app to crash. + // ipcRenderer. get tabsForIpc(): ServerOrFunctionalTab[] { const tabs: ServerOrFunctionalTab[] = []; this.tabs.forEach((tab: ServerOrFunctionalTab) => { @@ -568,7 +562,7 @@ class ServerManagerView { destroyView(): void { // Show loading indicator - this.$webviewsContainer.classList.remove('loaded'); + this.$viewsContainer.classList.remove('loaded'); ipcRenderer.send('destroy-all-views'); @@ -579,7 +573,7 @@ class ServerManagerView { // Clear DOM elements this.$tabsContainer.innerHTML = ''; - this.$webviewsContainer.innerHTML = ''; + this.$viewsContainer.innerHTML = ''; } reloadView(): void { @@ -674,10 +668,10 @@ class ServerManagerView { } registerIpcs(): void { - const webviewListeners: AnyObject = { - // 'webview-reload': 'reload', + const viewListeners: AnyObject = { + 'view-reload': 'reload', back: 'back', - // focus: 'focus', + focus: 'focus', forward: 'forward', zoomIn: 'zoomIn', zoomOut: 'zoomOut', @@ -687,9 +681,9 @@ class ServerManagerView { 'tab-devtools': 'toggleDevTools' }; - for (const key in webviewListeners) { + for (const key in viewListeners) { ipcRenderer.on(key, () => { - ipcRenderer.send('call-view-function', webviewListeners[key]); + ipcRenderer.send('call-view-function', viewListeners[key]); }); } @@ -742,20 +736,6 @@ class ServerManagerView { this.updateGeneralSettings('toggle-sidebar-setting', show); }); - ipcRenderer.on('toggle-silent', (event: Event, state: boolean) => { - const webviews: NodeListOf = document.querySelectorAll('webview'); - webviews.forEach(webview => { - try { - webview.setAudioMuted(state); - } catch (err) { - // webview is not ready yet - webview.addEventListener('dom-ready', () => { - webview.setAudioMuted(state); - }); - } - }); - }); - ipcRenderer.on('toggle-autohide-menubar', (event: Event, autoHideMenubar: boolean, updateMenu: boolean) => { if (updateMenu) { ipcRenderer.send('update-menu', { @@ -771,7 +751,7 @@ class ServerManagerView { ipcRenderer.on('toggle-dnd', (event: Event, state: boolean, newSettings: SettingsOptions) => { this.toggleDNDButton(state); - ipcRenderer.send('forward-message', 'toggle-silent', newSettings.silent); + ipcRenderer.send('toggle-silent', newSettings.silent); ipcRenderer.send('forward-view-message', 'toggle-dnd', state, newSettings); }); @@ -822,16 +802,8 @@ class ServerManagerView { this.$fullscreenPopup.classList.remove('show'); }); - ipcRenderer.on('focus-webview-with-id', (event: Event, webviewId: number) => { - const webviews: NodeListOf = document.querySelectorAll('webview'); - webviews.forEach(webview => { - const currentId = webview.getWebContents().id; - const tabId = webview.getAttribute('data-tab-id'); - const concurrentTab: HTMLButtonElement = document.querySelector(`div[data-tab-id="${tabId}"]`); - if (currentId === webviewId) { - concurrentTab.click(); - } - }); + ipcRenderer.on('focus-view-with-contents', (event: Event, contents: Electron.webContents) => { + ipcRenderer.send('focus-view-with-contents', contents); }); ipcRenderer.on('render-taskbar-icon', (event: Event, messageCount: number) => { diff --git a/app/renderer/js/notification/helpers.ts b/app/renderer/js/notification/helpers.ts index db7400c41..5a56d40a8 100644 --- a/app/renderer/js/notification/helpers.ts +++ b/app/renderer/js/notification/helpers.ts @@ -74,15 +74,14 @@ export function customReply(reply: string): void { } const currentWindow = remote.getCurrentWindow(); -const webContents = remote.getCurrentWebContents(); -const webContentsId = webContents.id; +const contents = remote.getCurrentWebContents(); // this function will focus the server that sent // the notification. Main function implemented in main.js export function focusCurrentServer(): void { // TODO: TypeScript: currentWindow of type BrowserWindow doesn't // have a .send() property per typescript. - (currentWindow as any).send('focus-webview-with-id', webContentsId); + (currentWindow as any).send('focus-view-with-contents', contents); } // this function parses the reply from to notification // making it easier to reply from notification eg diff --git a/app/renderer/js/tray.ts b/app/renderer/js/tray.ts index 0c64af033..1795454e5 100644 --- a/app/renderer/js/tray.ts +++ b/app/renderer/js/tray.ts @@ -1,5 +1,5 @@ 'use strict'; -import { ipcRenderer, remote, WebviewTag, NativeImage } from 'electron'; +import { ipcRenderer, remote, NativeImage } from 'electron'; import path = require('path'); import ConfigUtil = require('./utils/config-util.js'); @@ -207,10 +207,7 @@ function toggleTray(): void { } ConfigUtil.setConfigItem('trayIcon', true); } - const selector = 'webview:not([class*=disabled])'; - const webview: WebviewTag = document.querySelector(selector); - const webContents = webview.getWebContents(); - webContents.send('toggletray', state); + ipcRenderer.send('forward-view-message', 'toggletray', state); } ipcRenderer.on('toggletray', toggleTray); diff --git a/app/renderer/main.html b/app/renderer/main.html index b5746a761..2e1f2e783 100644 --- a/app/renderer/main.html +++ b/app/renderer/main.html @@ -41,7 +41,7 @@
-
+
From ad6ceae5a0851a3afaec07adba57ddb4082cd44e Mon Sep 17 00:00:00 2001 From: vsvipul Date: Mon, 12 Aug 2019 02:04:52 +0530 Subject: [PATCH 22/28] BrowserView: Add decoded server name when pushing to tabs. --- app/renderer/js/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index d041948a9..dd4498066 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -326,7 +326,7 @@ class ServerManagerView { this.tabs.push(new ServerTab({ role: 'server', icon: server.icon, - name: server.alias, + name: CommonUtil.decodeString(server.alias), $root: this.$tabsContainer, onClick: this.activateLastTab.bind(this, index), index, From 6feda14c523ad797761a821b4a0a24fcfa743dbc Mon Sep 17 00:00:00 2001 From: vsvipul Date: Mon, 12 Aug 2019 03:03:42 +0530 Subject: [PATCH 23/28] BrowserView: Make separate callViewFunction. --- app/main/viewmanager.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index 71287b42d..f70182ea8 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -43,15 +43,11 @@ class ViewManager { }); ipcMain.on('call-view-function', (e: Event, name: string, ...params: any[]) => { - // Type checking requires spread elements to match up with a rest parameter. - // So, using a workaround here. - (this.views[this.selectedIndex] as any)[name as keyof View](...params); + this.callViewFunction(this.selectedIndex, name, ...params); }); ipcMain.on('call-specific-view-function', (e: Event, index: number, name: string, ...params: any[]) => { - // Type checking requires spread elements to match up with a rest parameter. - // So, using a workaround here. - (this.views[index] as any)[name as keyof View](...params); + this.callViewFunction(index, name, ...params); }); ipcMain.on('toggle-silent', (e: Event, state: boolean) => { @@ -70,7 +66,9 @@ class ViewManager { ipcMain.on('focus-view-with-contents', (e: Event, contents: Electron.webContents) => { const view = BrowserView.fromWebContents(contents); - view.webContents.focus(); + if (view.webContents) { + view.webContents.focus(); + } }); ipcMain.on('server-load-complete', () => { @@ -164,6 +162,14 @@ class ViewManager { } } + callViewFunction(index: number, name: string, ...params: any[]): void { + const view = this.views[index]; + if (!view || view.isDestroyed()) { + return; + } + (view as any)[name as keyof View](...params); + } + forwardMessageAll(name: string, ...args: any[]): void { for (const id in this.views) { this.views[id].webContents.send(name, ...args); From 181ac443492ab75433d1ccb2c77a25205f0b005d Mon Sep 17 00:00:00 2001 From: vsvipul Date: Mon, 12 Aug 2019 22:42:12 +0530 Subject: [PATCH 24/28] BrowserView: Fix focus switching. --- app/main/viewmanager.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index f70182ea8..3d6aaa0d5 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -72,23 +72,18 @@ class ViewManager { }); ipcMain.on('server-load-complete', () => { - let viewIsNull = true; let viewIndex = -1; const mainWindow = BrowserWindow.getAllWindows()[0]; refreshViews = setInterval(() => { const view = this.views[this.selectedIndex]; - if (!view || view.isDestroyed()) { - return; - } - if (view.loading === false) { - if ((viewIsNull) || (viewIndex !== view.index)) { - viewIsNull = false; + if (view && view.loading === false) { + if (viewIndex !== view.index) { viewIndex = view.index; mainWindow.setBrowserView(view); this.fixBounds(mainWindow); + view.webContents.focus(); } - } else if (viewIsNull === false) { - viewIsNull = true; + } else if (viewIndex !== -1) { viewIndex = -1; mainWindow.setBrowserView(null); } From b1ca530e7343d3d1db94ac9f44beb720f22aa886 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Thu, 15 Aug 2019 17:50:28 +0530 Subject: [PATCH 25/28] Remove unnecessary translation-util.js file. --- app/translations/en-GB.json | 86 +++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 app/translations/en-GB.json diff --git a/app/translations/en-GB.json b/app/translations/en-GB.json new file mode 100644 index 000000000..e919d8ee0 --- /dev/null +++ b/app/translations/en-GB.json @@ -0,0 +1,86 @@ +{ + "File": "File", + "Add Organization": "Add Organization", + "Toggle Do Not Disturb": "Toggle Do Not Disturb", + "Desktop Settings": "Desktop Settings", + "Keyboard Shortcuts": "Keyboard Shortcuts", + "Copy Zulip URL": "Copy Zulip URL", + "Log Out of Organization": "Log Out of Organization", + "Minimize": "Minimize", + "Close": "Close", + "Quit": "Quit", + "Edit": "Edit", + "Undo": "Undo", + "Redo": "Redo", + "Cut": "Cut", + "Copy": "Copy", + "Paste": "Paste", + "Paste and Match Style": "Paste and Match Style", + "Select All": "Select All", + "View": "View", + "Reload": "Reload", + "Hard Reload": "Hard Reload", + "Toggle Full Screen": "Toggle Full Screen", + "Zoom In": "Zoom In", + "Zoom Out": "Zoom Out", + "Actual Size": "Actual Size", + "Toggle Tray Icon": "Toggle Tray Icon", + "Toggle Sidebar": "Toggle Sidebar", + "Auto hide Menu bar": "Auto hide Menu bar", + "History": "History", + "Back": "Back", + "Forward": "Forward", + "Window": "Window", + "Tools": "Tools", + "Check for Updates": "Check for Updates", + "Release Notes": "Release Notes", + "Factory Reset": "Factory Reset", + "Download App Logs": "Download App Logs", + "Toggle DevTools for Zulip App": "Toggle DevTools for Zulip App", + "Toggle DevTools for Active Tab": "Toggle DevTools for Active Tab", + "Help": "Help", + "About Zulip": "About Zulip", + "Help Center": "Help Center", + "Report an Issue": "Report an Issue", + "Switch to Next Organization": "Switch to Next Organization", + "Switch to Previous Organization": "Switch to Previous Organization", + "General": "General", + "Network": "Network", + "AddServer": "AddServer", + "Organizations": "Organizations", + "Shortcuts": "Shortcuts", + "Settings": "Settings", + "Appearance": "Appearance", + "Show app icon in system tray": "Show app icon in system tray", + "Auto hide menu bar (Press Alt key to display)": "Auto hide menu bar (Press Alt key to display)", + "Show sidebar": "Show sidebar", + "Show app unread badge": "Show app unread badge", + "Bounce dock on new private message": "Bounce dock on new private message", + "Flash taskbar on new message": "Flash taskbar on new message", + "Desktop Notifications": "Desktop Notifications", + "Show desktop notifications": "Show desktop notifications", + "Mute all sounds from Zulip": "Mute all sounds from Zulip", + "App Updates": "App Updates", + "Enable auto updates": "Enable auto updates", + "Get beta updates": "Get beta updates", + "Functionality": "Functionality", + "Start app at login": "Start app at login", + "Always start minimized": "Always start minimized", + "Enable spellchecker (requires restart)": "Enable spellchecker (requires restart)", + "Advanced": "Advanced", + "Enable error reporting (requires restart)": "Enable error reporting (requires restart)", + "Show downloaded files in file manager": "Show downloaded files in file manager", + "Add custom CSS": "Add custom CSS", + "Upload": "Upload", + "Delete": "Delete", + "Default download location": "Default download location", + "Change": "Change", + "Reset Application Data": "Reset Application Data", + "This will delete all application data including all added accounts and preferences": "This will delete all application data including all added accounts and preferences", + "Reset App Data": "Reset App Data", + "Add a Zulip organization": "Add a Zulip organization", + "Organization URL": "Organization URL", + "Connect": "Connect", + "OR": "OR", + "Create a new organization": "Create a new organization" +} \ No newline at end of file From 9c4a3de835d0e7f20948e07982d980f03bb2dfc7 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Fri, 16 Aug 2019 02:36:26 +0530 Subject: [PATCH 26/28] BrowserView: Remove show dom content on load. Removes the heavy setInterval which we were using earlier to prevent heavy CPU Usage. The main reason we were using a setInterval earlier was because view switching was buggy. This commit fixes that. --- app/main/index.ts | 5 +++-- app/main/viewmanager.ts | 35 ++++++----------------------------- app/renderer/js/main.ts | 5 ----- 3 files changed, 9 insertions(+), 36 deletions(-) diff --git a/app/main/index.ts b/app/main/index.ts index 1534dc759..acba1bc72 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -29,7 +29,8 @@ if (isDev) { } // Prevent window being garbage collected -let mainWindow: Electron.BrowserWindow; +// eslint-disable-next-line import/no-mutable-exports +export let mainWindow: Electron.BrowserWindow; let badgeCount: number; let isQuitting = false; @@ -264,7 +265,7 @@ app.on('ready', () => { }); ipcMain.on('fix-bounds', () => { - ViewManager.fixBounds(mainWindow); + ViewManager.fixBounds(); }); ipcMain.on('update-badge', (_event: Electron.IpcMessageEvent, messageCount: number) => { diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index 3d6aaa0d5..adbb41318 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -1,12 +1,11 @@ 'use strict'; -import { BrowserWindow, ipcMain, BrowserView } from 'electron'; +import { ipcMain, BrowserView } from 'electron'; import { View, ViewProps } from './view'; +import { mainWindow } from '.'; import ConfigUtil = require('../renderer/js/utils/config-util'); -let refreshViews: any = null; - class ViewManager { views: { [key: number]: View }; selectedIndex: number; @@ -70,25 +69,6 @@ class ViewManager { view.webContents.focus(); } }); - - ipcMain.on('server-load-complete', () => { - let viewIndex = -1; - const mainWindow = BrowserWindow.getAllWindows()[0]; - refreshViews = setInterval(() => { - const view = this.views[this.selectedIndex]; - if (view && view.loading === false) { - if (viewIndex !== view.index) { - viewIndex = view.index; - mainWindow.setBrowserView(view); - this.fixBounds(mainWindow); - view.webContents.focus(); - } - } else if (viewIndex !== -1) { - viewIndex = -1; - mainWindow.setBrowserView(null); - } - }, 200); - }); } create(props: ViewProps): void { @@ -107,18 +87,20 @@ class ViewManager { return; } this.selectedIndex = index; + this.fixBounds(); + mainWindow.setBrowserView(view); if (!view.webContents.getURL()) { const { url } = view; view.webContents.loadURL(url); } } - fixBounds(mainWindow: Electron.BrowserWindow): void { + fixBounds(): void { // Any updates to the sidebar width should reflect both here and in css const SIDEBAR_WIDTH = 54; const view = this.views[this.selectedIndex]; const showSidebar = ConfigUtil.getConfigItem('showSidebar', true); - if (!view || view.isDestroyed()) { + if (!view) { return; } const { width, height } = mainWindow.getContentBounds(); @@ -133,7 +115,6 @@ class ViewManager { } destroy(index: number): void { - const mainWindow = BrowserWindow.getAllWindows()[0]; const view = this.views[index]; if (!view || view.isDestroyed()) { console.log('Attempt to delete a view that does not exist.'); @@ -147,14 +128,10 @@ class ViewManager { } destroyAll(): void { - const mainWindow = BrowserWindow.getAllWindows()[0]; mainWindow.setBrowserView(null); for (const id in this.views) { this.destroy(this.views[id].index); } - if (refreshViews) { - clearInterval(refreshViews); - } } callViewFunction(index: number, name: string, ...params: any[]): void { diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index dd4498066..01daee64a 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -318,7 +318,6 @@ class ServerManagerView { } else { this.showLoading(true); } - this.initTabsComplete(); } initServer(server: any, index: number): void { @@ -388,10 +387,6 @@ class ServerManagerView { this.toggleDNDButton(dnd); } - initTabsComplete(): void { - ipcRenderer.send('server-load-complete'); - } - getTabIndex(): number { const currentIndex = this.tabIndex; this.tabIndex++; From ca5b45f1106e726e8c245e67b305dd44724778fa Mon Sep 17 00:00:00 2001 From: vsvipul Date: Sat, 17 Aug 2019 00:45:16 +0530 Subject: [PATCH 27/28] BrowserView: Add documentation and fix fullScreen. --- app/main/index.ts | 2 ++ app/main/view.ts | 4 ++++ app/main/viewmanager.ts | 15 ++++++++++++++- app/renderer/js/components/tab.ts | 3 +++ app/renderer/js/main.ts | 3 ++- 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/main/index.ts b/app/main/index.ts index acba1bc72..dbb5df0bd 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -110,10 +110,12 @@ function createMainWindow(): Electron.BrowserWindow { win.setTitle('Zulip'); win.on('enter-full-screen', () => { + ViewManager.fixBounds(); win.webContents.send('enter-fullscreen'); }); win.on('leave-full-screen', () => { + ViewManager.fixBounds(); win.webContents.send('leave-fullscreen'); }); diff --git a/app/main/view.ts b/app/main/view.ts index b9da210e1..6ad3c6bc0 100644 --- a/app/main/view.ts +++ b/app/main/view.ts @@ -16,6 +16,8 @@ export interface ViewProps { preload: boolean; } +// Class View is a wrapper around electron's BrowserView +// Multiples views are handled by ViewManager export class View extends BrowserView { index: number; url: string; @@ -194,6 +196,7 @@ export class View extends BrowserView { this.webContents.toggleDevTools(); } + // If page can go back, enables back button, otherwise disables it. maybeEnableGoBackButton(): void { if (this.webContents.canGoBack()) { this.sendAction('switch-back', true); @@ -220,6 +223,7 @@ export class View extends BrowserView { this.sendAction('update-badge-count', badgeCount, this.url); } + // Send an action to renderer process. sendAction(action: any, ...params: any[]): void { const win = BrowserWindow.getAllWindows()[0]; diff --git a/app/main/viewmanager.ts b/app/main/viewmanager.ts index adbb41318..9785e2ee0 100644 --- a/app/main/viewmanager.ts +++ b/app/main/viewmanager.ts @@ -6,6 +6,7 @@ import { mainWindow } from '.'; import ConfigUtil = require('../renderer/js/utils/config-util'); +// ViewManager Class allows us to create, delete and manage several instances of View class class ViewManager { views: { [key: number]: View }; selectedIndex: number; @@ -33,18 +34,22 @@ class ViewManager { this.destroyAll(); }); + // Sends a message to the selected View's webContents. ipcMain.on('forward-view-message', (e: Event, name: string, ...params: any[]) => { this.views[this.selectedIndex].webContents.send(name, ...params); }); + // Sends a message to each View's webContents. ipcMain.on('forward-message-all', (e: Event, name: string, ...params: any[]) => { this.forwardMessageAll(name, ...params); }); + // Calls a function for the selected View. ipcMain.on('call-view-function', (e: Event, name: string, ...params: any[]) => { this.callViewFunction(this.selectedIndex, name, ...params); }); + // Calls a function for the View with the given index. ipcMain.on('call-specific-view-function', (e: Event, index: number, name: string, ...params: any[]) => { this.callViewFunction(index, name, ...params); }); @@ -71,6 +76,7 @@ class ViewManager { }); } + // Creates a new View and appends it to this.views. create(props: ViewProps): void { if (this.views[props.index]) { return; @@ -78,8 +84,10 @@ class ViewManager { const view = new View(props); this.views[props.index] = view; view.webContents.loadURL(props.url); + view.setAutoResize({ width: true, height: true }); } + // Selects a view with the specified index. select(index: number): void { const view = this.views[index]; if (!view || view.isDestroyed()) { @@ -95,6 +103,8 @@ class ViewManager { } } + // BrowserView is like a separate BrowserWindow displayed inside the mainWindow + // So, it requires its bounds to be set everytime it is selected. fixBounds(): void { // Any updates to the sidebar width should reflect both here and in css const SIDEBAR_WIDTH = 54; @@ -111,9 +121,9 @@ class ViewManager { width: showSidebar ? width - SIDEBAR_WIDTH : width, height }); - view.setAutoResize({ width: true, height: true }); } + // Destroys View with specified index. destroy(index: number): void { const view = this.views[index]; if (!view || view.isDestroyed()) { @@ -127,6 +137,7 @@ class ViewManager { delete this.views[index]; } + // Destroys all Views. destroyAll(): void { mainWindow.setBrowserView(null); for (const id in this.views) { @@ -134,6 +145,7 @@ class ViewManager { } } + // Calls a function in View class of a specified index. callViewFunction(index: number, name: string, ...params: any[]): void { const view = this.views[index]; if (!view || view.isDestroyed()) { @@ -142,6 +154,7 @@ class ViewManager { (view as any)[name as keyof View](...params); } + // Forwards a message to webContents of each view. forwardMessageAll(name: string, ...args: any[]): void { for (const id in this.views) { this.views[id].webContents.send(name, ...args); diff --git a/app/renderer/js/components/tab.ts b/app/renderer/js/components/tab.ts index d4131dba1..5c0dcc0b3 100644 --- a/app/renderer/js/components/tab.ts +++ b/app/renderer/js/components/tab.ts @@ -21,14 +21,17 @@ class Tab extends BaseComponent { this.$el.addEventListener('mouseout', this.props.onHoverOut); } + // Add active highlight to tab. activate(): void { this.$el.classList.add('active'); } + // Remove active highlight from tab. deactivate(): void { this.$el.classList.remove('active'); } + // Remove the tab from DOM when it is removed. destroy(): void { this.$el.parentNode.removeChild(this.$el); } diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 01daee64a..9f527ee3c 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -853,8 +853,9 @@ class ServerManagerView { const webviews: NodeListOf = document.querySelectorAll('webview'); webviews.forEach(webview => { webview.send('set-idle'); + }); }); - + ipcRenderer.on('switch-back', (e: Event, state: boolean) => { if (state === true) { this.$backButton.classList.remove('disable'); From 3b6c356616f01c933d80c0e47cd2840785ee8b98 Mon Sep 17 00:00:00 2001 From: vsvipul Date: Mon, 2 Sep 2019 21:46:08 +0530 Subject: [PATCH 28/28] Add integer check for messageCountAll --- app/renderer/js/main.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 9f527ee3c..12484df57 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -597,7 +597,9 @@ class ServerManagerView { tab.updateBadge(count); } } - ipcRenderer.send('update-badge', messageCountAll); + if (Number.isInteger(messageCountAll)) { + ipcRenderer.send('update-badge', messageCountAll); + } } updateGeneralSettings(setting: string, value: any): void {