2019-08-10 02:47:13 +00:00
|
|
|
/* eslint global-require: off */
|
2020-07-05 07:41:33 +00:00
|
|
|
require('dotenv').config();
|
2019-08-10 02:47:13 +00:00
|
|
|
/**
|
|
|
|
* This module executes inside of electron's main process. You can start
|
|
|
|
* electron renderer process from here and communicate with the other processes
|
|
|
|
* through IPC.
|
|
|
|
*
|
|
|
|
* When running `yarn build` or `yarn build-main`, this file is compiled to
|
|
|
|
* `./app/main.prod.js` using webpack. This gives us some performance wins.
|
|
|
|
*
|
|
|
|
* @flow
|
|
|
|
*/
|
2020-06-04 15:49:03 +00:00
|
|
|
import electron, {
|
|
|
|
app,
|
|
|
|
BrowserWindow,
|
|
|
|
BrowserView,
|
|
|
|
globalShortcut,
|
|
|
|
ipcMain,
|
2020-06-11 02:52:42 +00:00
|
|
|
nativeTheme,
|
2020-06-13 06:55:57 +00:00
|
|
|
webContents,
|
2020-07-05 08:23:42 +00:00
|
|
|
shell,
|
|
|
|
dialog,
|
2020-08-27 07:12:12 +00:00
|
|
|
session,
|
2020-06-04 15:49:03 +00:00
|
|
|
} from 'electron';
|
2019-09-02 16:23:13 +00:00
|
|
|
import settings from 'electron-settings';
|
2019-08-10 02:47:13 +00:00
|
|
|
import log from 'electron-log';
|
2019-09-05 17:29:33 +00:00
|
|
|
import * as Sentry from '@sentry/electron';
|
2020-05-24 09:56:24 +00:00
|
|
|
import installExtension, {
|
|
|
|
REACT_DEVELOPER_TOOLS,
|
|
|
|
REDUX_DEVTOOLS,
|
|
|
|
} from 'electron-devtools-installer';
|
2020-05-25 14:07:11 +00:00
|
|
|
import fs from 'fs';
|
2020-07-04 08:26:23 +00:00
|
|
|
import MenuBuilder from './menu';
|
2020-09-03 02:33:56 +00:00
|
|
|
import {USER_PREFERENCES, NETWORK_CONFIGURATION} from './constants/settingKeys';
|
2021-05-17 19:26:15 +00:00
|
|
|
import {STARTUP_PAGE} from './constants/values';
|
2020-05-30 13:00:34 +00:00
|
|
|
import {migrateDeviceSchema} from './settings/migration';
|
2020-06-09 13:25:05 +00:00
|
|
|
import {DEVTOOLS_MODES} from './constants/previewerLayouts';
|
2020-06-07 11:38:30 +00:00
|
|
|
import {initMainShortcutManager} from './shortcut-manager/main-shortcut-manager';
|
2020-06-10 20:05:31 +00:00
|
|
|
import {appUpdater} from './app-updater';
|
2020-07-05 07:41:33 +00:00
|
|
|
import trimStart from 'lodash/trimStart';
|
2020-07-04 18:46:33 +00:00
|
|
|
import isURL from 'validator/lib/isURL';
|
2021-05-19 14:06:12 +00:00
|
|
|
import {
|
|
|
|
confirmMove,
|
|
|
|
conflictHandler,
|
|
|
|
movingFailed,
|
|
|
|
} from './move-to-applications';
|
2020-07-20 15:22:54 +00:00
|
|
|
import {
|
|
|
|
initBrowserSync,
|
|
|
|
getBrowserSyncHost,
|
|
|
|
getBrowserSyncEmbedScriptURL,
|
2020-07-25 04:47:11 +00:00
|
|
|
closeBrowserSync,
|
2020-08-03 14:37:28 +00:00
|
|
|
stopWatchFiles,
|
|
|
|
watchFiles,
|
2020-07-20 15:22:54 +00:00
|
|
|
} from './utils/browserSync';
|
2021-05-12 19:18:30 +00:00
|
|
|
import {getHostFromURL, normalize} from './utils/urlUtils';
|
2020-08-27 13:10:59 +00:00
|
|
|
import {getPermissionSettingPreference} from './utils/permissionUtils';
|
2020-07-20 15:22:54 +00:00
|
|
|
import browserSync from 'browser-sync';
|
2020-08-11 14:20:55 +00:00
|
|
|
import {captureOnSentry} from './utils/logUtils';
|
2020-08-12 16:58:08 +00:00
|
|
|
import appMetadata from './services/db/appMetadata';
|
2020-09-03 02:33:56 +00:00
|
|
|
import {convertToProxyConfig} from './utils/proxyUtils';
|
2020-08-27 13:10:59 +00:00
|
|
|
import {PERMISSION_MANAGEMENT_OPTIONS} from './constants/permissionsManagement';
|
2020-08-29 10:49:34 +00:00
|
|
|
import {endSession, startSession} from './utils/analytics';
|
2021-05-17 19:26:15 +00:00
|
|
|
import {getStartupPage, getLastOpenedAddress} from './utils/navigatorUtils';
|
2019-09-05 17:29:33 +00:00
|
|
|
|
2020-03-14 08:01:12 +00:00
|
|
|
const path = require('path');
|
2020-07-05 09:20:36 +00:00
|
|
|
const URL = require('url').URL;
|
2019-10-22 02:52:14 +00:00
|
|
|
|
2021-05-12 19:18:30 +00:00
|
|
|
const HOME_PAGE = 'HOME_PAGE';
|
|
|
|
const LAST_OPENED_ADDRESS = 'LAST_OPENED_ADDRESS';
|
|
|
|
|
2020-05-30 13:00:34 +00:00
|
|
|
migrateDeviceSchema();
|
|
|
|
|
2019-09-05 18:03:05 +00:00
|
|
|
if (process.env.NODE_ENV !== 'development') {
|
2020-03-14 08:05:02 +00:00
|
|
|
Sentry.init({
|
|
|
|
dsn: 'https://f2cdbc6a88aa4a068a738d4e4cfd3e12@sentry.io/1553155',
|
2020-10-07 08:58:21 +00:00
|
|
|
environment: process.env.NODE_ENV,
|
|
|
|
beforeSend: (event, hint) => {
|
|
|
|
// Suppress address already in use error
|
|
|
|
if (
|
|
|
|
(event?.exception?.values?.[0]?.value || '').indexOf(
|
|
|
|
'listen EADDRINUSE: address already in use'
|
|
|
|
) > -1
|
|
|
|
) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
event.tags = {appVersion: app.getVersion()};
|
|
|
|
return event;
|
|
|
|
},
|
2020-03-14 08:05:02 +00:00
|
|
|
});
|
2019-09-05 18:03:05 +00:00
|
|
|
}
|
2019-08-10 02:47:13 +00:00
|
|
|
|
2020-05-28 13:30:40 +00:00
|
|
|
const protocol = 'responsively';
|
|
|
|
|
|
|
|
let hasActiveWindow = false;
|
|
|
|
|
2019-08-10 02:47:13 +00:00
|
|
|
let mainWindow = null;
|
2020-05-25 14:07:11 +00:00
|
|
|
let urlToOpen = null;
|
2020-06-07 10:03:44 +00:00
|
|
|
let devToolsView = null;
|
2020-07-26 14:48:23 +00:00
|
|
|
let fileToOpen = null;
|
2019-08-10 02:47:13 +00:00
|
|
|
|
2020-07-04 08:26:23 +00:00
|
|
|
const httpAuthCallbacks = {};
|
2020-08-27 07:12:12 +00:00
|
|
|
const permissionCallbacks = {};
|
2019-08-24 06:07:07 +00:00
|
|
|
|
2019-08-10 02:47:13 +00:00
|
|
|
if (process.env.NODE_ENV === 'production') {
|
2020-03-14 08:05:02 +00:00
|
|
|
const sourceMapSupport = require('source-map-support');
|
|
|
|
sourceMapSupport.install();
|
2019-08-10 02:47:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
2020-03-14 08:05:02 +00:00
|
|
|
process.env.NODE_ENV === 'development' ||
|
|
|
|
process.env.DEBUG_PROD === 'true'
|
2019-08-10 02:47:13 +00:00
|
|
|
) {
|
2020-05-08 16:36:49 +00:00
|
|
|
require('electron-debug')({isEnabled: true});
|
2019-08-10 02:47:13 +00:00
|
|
|
}
|
|
|
|
|
2020-07-26 14:48:23 +00:00
|
|
|
const openWithHandler = filePath => {
|
|
|
|
fileToOpen = null;
|
|
|
|
if (
|
|
|
|
filePath != null &&
|
2021-06-16 15:11:47 +00:00
|
|
|
!filePath.startsWith('http://') &&
|
|
|
|
!filePath.startsWith('https://') &&
|
2020-07-26 14:48:23 +00:00
|
|
|
(filePath.endsWith('.html') || filePath.endsWith('.htm'))
|
|
|
|
) {
|
2021-06-16 15:11:47 +00:00
|
|
|
if (filePath.startsWith('file://')) fileToOpen = filePath;
|
|
|
|
else fileToOpen = `file://${filePath}`;
|
2020-07-26 14:48:23 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2020-09-03 02:33:56 +00:00
|
|
|
const setProxyOnStart = () => {
|
|
|
|
const proxyConfig = (settings.get(NETWORK_CONFIGURATION) || {}).proxy;
|
|
|
|
if (proxyConfig != null && proxyConfig.active) {
|
|
|
|
session.defaultSession.setProxy(convertToProxyConfig(proxyConfig));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-08-10 02:47:13 +00:00
|
|
|
/**
|
|
|
|
* Add event listeners...
|
|
|
|
*/
|
2020-05-25 14:07:11 +00:00
|
|
|
app.on('will-finish-launching', () => {
|
2020-06-09 09:52:48 +00:00
|
|
|
if (process.platform === 'win32') {
|
|
|
|
urlToOpen = process.argv.filter(i => /^responsively/.test(i))[0];
|
|
|
|
}
|
2020-05-25 14:07:11 +00:00
|
|
|
if (['win32', 'darwin'].includes(process.platform)) {
|
|
|
|
if (process.argv.length >= 2) {
|
2020-07-26 14:48:23 +00:00
|
|
|
if (!openWithHandler(process.argv[1])) {
|
|
|
|
app.setAsDefaultProtocolClient(protocol, process.execPath, [
|
|
|
|
path.resolve(process.argv[1]),
|
|
|
|
]);
|
|
|
|
}
|
2020-05-25 14:07:11 +00:00
|
|
|
} else {
|
2020-05-28 13:30:40 +00:00
|
|
|
app.setAsDefaultProtocolClient(protocol);
|
2020-05-25 14:07:11 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-12 19:18:30 +00:00
|
|
|
if (
|
|
|
|
!fileToOpen &&
|
|
|
|
!urlToOpen &&
|
|
|
|
process.argv.length >= 2 &&
|
|
|
|
!openWithHandler(process.argv[1]) &&
|
2021-06-16 15:11:47 +00:00
|
|
|
isURL(process.argv[1], {
|
|
|
|
protocols: ['http', 'https', 'file'],
|
|
|
|
require_tld: false,
|
|
|
|
})
|
2021-05-12 19:18:30 +00:00
|
|
|
) {
|
|
|
|
urlToOpen = process.argv[1];
|
|
|
|
}
|
2020-05-25 14:07:11 +00:00
|
|
|
});
|
|
|
|
|
2020-07-26 14:48:23 +00:00
|
|
|
app.on('open-file', async (event, filePath) => {
|
|
|
|
event.preventDefault();
|
|
|
|
let htmlFile = filePath;
|
|
|
|
if (process.platform === 'win32' && process.argv.length >= 2) {
|
|
|
|
htmlFile = process.argv[1];
|
|
|
|
}
|
|
|
|
if (openWithHandler(htmlFile)) {
|
|
|
|
if (mainWindow) {
|
|
|
|
openFile(fileToOpen);
|
|
|
|
} else if (!hasActiveWindow) {
|
2020-08-13 14:59:13 +00:00
|
|
|
await createWindow();
|
2020-07-26 14:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-05-25 14:07:11 +00:00
|
|
|
app.on('open-url', async (event, url) => {
|
|
|
|
if (mainWindow) {
|
|
|
|
openUrl(url);
|
|
|
|
} else {
|
|
|
|
urlToOpen = url;
|
2020-05-28 13:30:40 +00:00
|
|
|
if (!hasActiveWindow) {
|
2020-08-13 14:59:13 +00:00
|
|
|
await createWindow();
|
2020-05-28 13:30:40 +00:00
|
|
|
}
|
2020-05-25 14:07:11 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-08-10 02:47:13 +00:00
|
|
|
app.on('window-all-closed', () => {
|
2020-08-29 10:49:34 +00:00
|
|
|
endSession();
|
2020-07-22 04:22:48 +00:00
|
|
|
hasActiveWindow = false;
|
|
|
|
ipcMain.removeAllListeners();
|
|
|
|
ipcMain.removeHandler('install-extension');
|
|
|
|
ipcMain.removeHandler('get-local-extension-path');
|
|
|
|
ipcMain.removeHandler('get-screen-shot-save-path');
|
|
|
|
ipcMain.removeHandler('request-browser-sync');
|
2020-07-25 05:06:56 +00:00
|
|
|
closeBrowserSync();
|
2020-03-14 08:05:02 +00:00
|
|
|
// Respect the OSX convention of having the application in memory even
|
|
|
|
// after all windows have been closed
|
|
|
|
if (process.platform !== 'darwin') {
|
|
|
|
app.quit();
|
|
|
|
}
|
2019-08-10 02:47:13 +00:00
|
|
|
});
|
|
|
|
|
2020-05-21 13:46:57 +00:00
|
|
|
app.on(
|
|
|
|
'certificate-error',
|
|
|
|
(event, webContents, url, error, certificate, callback) => {
|
2020-07-12 15:48:14 +00:00
|
|
|
if (
|
2020-07-20 15:22:54 +00:00
|
|
|
getHostFromURL(url) === getBrowserSyncHost() ||
|
2020-07-12 15:48:14 +00:00
|
|
|
(settings.get(USER_PREFERENCES) || {}).disableSSLValidation === true
|
|
|
|
) {
|
2020-05-21 13:46:57 +00:00
|
|
|
event.preventDefault();
|
|
|
|
callback(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2019-08-24 06:07:07 +00:00
|
|
|
app.on('login', (event, webContents, request, authInfo, callback) => {
|
2020-03-14 08:05:02 +00:00
|
|
|
event.preventDefault();
|
|
|
|
const {url} = request;
|
2020-09-03 02:33:56 +00:00
|
|
|
if (authInfo.isProxy) {
|
|
|
|
const proxyConfig = (settings.get(NETWORK_CONFIGURATION) || {}).proxy;
|
|
|
|
if (proxyConfig != null && proxyConfig.active) {
|
|
|
|
const schConfig =
|
|
|
|
proxyConfig[url.substr(0, url.indexOf(':')).toLowerCase()];
|
|
|
|
if (schConfig != null && !schConfig.useDefault) {
|
|
|
|
callback(schConfig.user, schConfig.password);
|
|
|
|
} else {
|
|
|
|
callback(proxyConfig.default.user, proxyConfig.default.password);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (httpAuthCallbacks[url]) {
|
|
|
|
return httpAuthCallbacks[url].push(callback);
|
|
|
|
}
|
|
|
|
httpAuthCallbacks[url] = [callback];
|
|
|
|
mainWindow.webContents.send('http-auth-prompt', {url});
|
2020-03-14 08:05:02 +00:00
|
|
|
}
|
2020-09-03 02:33:56 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
ipcMain.on('set-proxy-profile', async (_, proxyProfile) => {
|
|
|
|
if (proxyProfile == null || proxyProfile.length === 0) return;
|
|
|
|
await session.defaultSession.clearAuthCache();
|
|
|
|
await session.defaultSession.setProxy(proxyProfile);
|
2019-08-24 06:07:07 +00:00
|
|
|
});
|
|
|
|
|
2020-08-13 14:59:13 +00:00
|
|
|
app.on('activate', async (event, hasVisibleWindows) => {
|
2020-07-11 16:44:00 +00:00
|
|
|
if (hasVisibleWindows || hasActiveWindow) {
|
|
|
|
return;
|
|
|
|
}
|
2020-08-13 14:59:13 +00:00
|
|
|
await createWindow();
|
2020-07-11 16:44:00 +00:00
|
|
|
});
|
|
|
|
|
2020-08-13 14:59:13 +00:00
|
|
|
app.on('ready', async () => {
|
2020-07-11 16:44:00 +00:00
|
|
|
if (hasActiveWindow) {
|
|
|
|
return;
|
|
|
|
}
|
2021-05-19 18:20:24 +00:00
|
|
|
if (
|
|
|
|
process.platform === 'darwin' &&
|
|
|
|
!app.isInApplicationsFolder() &&
|
|
|
|
(await confirmMove(dialog))
|
|
|
|
) {
|
2021-05-19 14:06:12 +00:00
|
|
|
try {
|
|
|
|
app.moveToApplicationsFolder({
|
|
|
|
conflictHandler: conflictHandler.bind(this, dialog),
|
|
|
|
});
|
|
|
|
} catch (e) {
|
|
|
|
movingFailed(dialog);
|
|
|
|
}
|
|
|
|
}
|
2020-08-31 01:41:01 +00:00
|
|
|
// Set theme based on user preference
|
|
|
|
const themeSource = (settings.get(USER_PREFERENCES) || {}).theme;
|
|
|
|
if (themeSource) {
|
|
|
|
nativeTheme.themeSource = themeSource;
|
|
|
|
}
|
2020-08-13 14:59:13 +00:00
|
|
|
await createWindow();
|
2020-07-11 16:44:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
const chooseOpenWindowHandler = url => {
|
|
|
|
if (url == null || url.trim() === '' || url === 'about:blank#blocked')
|
|
|
|
return 'none';
|
|
|
|
|
|
|
|
if (url === 'about:blank') return 'useWindow';
|
|
|
|
|
2021-06-16 15:11:47 +00:00
|
|
|
if (isURL(url, {protocols: ['http', 'https'], require_tld: false}))
|
|
|
|
return 'useWindow';
|
2020-07-11 16:44:00 +00:00
|
|
|
|
|
|
|
let urlObj = null;
|
|
|
|
try {
|
|
|
|
urlObj = new URL(url);
|
|
|
|
} catch {}
|
|
|
|
|
|
|
|
if (
|
|
|
|
urlObj != null &&
|
|
|
|
urlObj.protocol === 'file:' &&
|
|
|
|
(urlObj.pathname.endsWith('.html') || urlObj.pathname.endsWith('.htm'))
|
|
|
|
)
|
|
|
|
return 'useWindow';
|
|
|
|
|
|
|
|
return 'useShell';
|
|
|
|
};
|
|
|
|
|
|
|
|
const installExtensions = async () => {
|
|
|
|
const extensions = [REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS];
|
|
|
|
try {
|
|
|
|
await installExtension(extensions);
|
|
|
|
} catch (err) {
|
|
|
|
console.log('Error installing extensions', err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const openUrl = url => {
|
|
|
|
mainWindow.webContents.send(
|
|
|
|
'address-change',
|
2021-05-12 19:18:30 +00:00
|
|
|
normalize(url.replace(`${protocol}://`, ''))
|
2020-07-11 16:44:00 +00:00
|
|
|
);
|
|
|
|
mainWindow.show();
|
|
|
|
};
|
|
|
|
|
2020-07-26 14:48:23 +00:00
|
|
|
const openFile = filePath => {
|
2021-05-12 19:18:30 +00:00
|
|
|
mainWindow.webContents.send('address-change', normalize(filePath));
|
2020-07-26 14:48:23 +00:00
|
|
|
mainWindow.show();
|
|
|
|
};
|
|
|
|
|
2021-05-12 19:18:30 +00:00
|
|
|
function getUserPreferences(): UserPreferenceType {
|
|
|
|
return settings.get(USER_PREFERENCES) || {};
|
|
|
|
}
|
|
|
|
|
2019-09-04 07:54:03 +00:00
|
|
|
const createWindow = async () => {
|
2020-08-12 16:58:08 +00:00
|
|
|
appMetadata.incrementOpenCount();
|
2020-05-28 13:30:40 +00:00
|
|
|
hasActiveWindow = true;
|
2020-09-03 02:33:56 +00:00
|
|
|
setProxyOnStart();
|
2020-07-12 05:24:47 +00:00
|
|
|
|
2020-07-01 07:31:02 +00:00
|
|
|
if (process.env.NODE_ENV === 'development') {
|
2020-03-14 08:05:02 +00:00
|
|
|
await installExtensions();
|
|
|
|
}
|
|
|
|
|
|
|
|
const {width, height} = electron.screen.getPrimaryDisplay().workAreaSize;
|
|
|
|
|
2020-07-04 08:26:23 +00:00
|
|
|
const iconPath = path.resolve(__dirname, '../resources/icons/64x64.png');
|
2020-03-14 08:05:02 +00:00
|
|
|
mainWindow = new BrowserWindow({
|
|
|
|
show: false,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
webPreferences: {
|
|
|
|
nodeIntegration: true,
|
|
|
|
nodeIntegrationInWorker: true,
|
|
|
|
webviewTag: true,
|
2020-05-24 09:56:24 +00:00
|
|
|
enableRemoteModule: true,
|
2021-05-19 14:06:12 +00:00
|
|
|
contextIsolation: false,
|
2020-03-14 08:05:02 +00:00
|
|
|
},
|
|
|
|
titleBarStyle: 'hidden',
|
|
|
|
icon: iconPath,
|
|
|
|
});
|
|
|
|
|
2020-08-05 16:52:39 +00:00
|
|
|
await initBrowserSync();
|
|
|
|
ipcMain.handle('request-browser-sync', (event, data) => {
|
|
|
|
const browserSyncOptions = {
|
|
|
|
url: getBrowserSyncEmbedScriptURL(),
|
|
|
|
};
|
|
|
|
return browserSyncOptions;
|
|
|
|
});
|
|
|
|
|
2020-03-14 08:05:02 +00:00
|
|
|
mainWindow.loadURL(`file://${__dirname}/app.html`);
|
|
|
|
|
2020-07-04 08:26:23 +00:00
|
|
|
mainWindow.webContents.on('did-finish-load', () => {
|
2020-08-29 10:49:34 +00:00
|
|
|
startSession();
|
2020-03-14 08:05:02 +00:00
|
|
|
if (process.platform === 'darwin') {
|
|
|
|
// Trick to make the transparent title bar draggable
|
2020-08-11 13:38:04 +00:00
|
|
|
mainWindow.webContents
|
|
|
|
.executeJavaScript(
|
|
|
|
`
|
|
|
|
var div = document.createElement("div");
|
|
|
|
div.style.position = "absolute";
|
|
|
|
div.style.top = 0;
|
|
|
|
div.style.height = "23px";
|
|
|
|
div.style.width = "100%";
|
|
|
|
div.style["-webkit-app-region"] = "drag";
|
|
|
|
div.style['-webkit-user-select'] = 'none';
|
|
|
|
document.body.appendChild(div);
|
|
|
|
true;
|
|
|
|
`
|
|
|
|
)
|
|
|
|
.catch(captureOnSentry);
|
2020-03-14 08:05:02 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-06-07 11:38:30 +00:00
|
|
|
initMainShortcutManager();
|
|
|
|
|
2020-06-15 17:53:30 +00:00
|
|
|
const onResize = () => {
|
2020-06-16 03:05:07 +00:00
|
|
|
const [width, height] = mainWindow.getContentSize();
|
2020-06-10 02:36:35 +00:00
|
|
|
mainWindow.webContents.send('window-resize', {height, width});
|
2020-06-15 17:53:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
mainWindow.on('resize', onResize);
|
2020-06-10 02:36:35 +00:00
|
|
|
|
2020-03-14 08:05:02 +00:00
|
|
|
mainWindow.once('ready-to-show', () => {
|
2020-05-25 14:07:11 +00:00
|
|
|
if (urlToOpen) {
|
|
|
|
openUrl(urlToOpen);
|
|
|
|
urlToOpen = null;
|
2020-07-26 14:48:23 +00:00
|
|
|
} else if (fileToOpen) {
|
|
|
|
openFile(fileToOpen);
|
|
|
|
fileToOpen = null;
|
2020-06-09 09:52:48 +00:00
|
|
|
} else {
|
2021-05-12 19:18:30 +00:00
|
|
|
openUrl(
|
|
|
|
getUserPreferences().reopenLastAddress
|
|
|
|
? getLastOpenedAddress()
|
2021-05-17 19:26:15 +00:00
|
|
|
: getStartupPage()
|
2021-05-12 19:18:30 +00:00
|
|
|
);
|
2020-06-09 09:52:48 +00:00
|
|
|
mainWindow.show();
|
2020-05-25 14:07:11 +00:00
|
|
|
}
|
2020-10-05 19:29:54 +00:00
|
|
|
mainWindow.maximize();
|
2020-06-15 17:53:30 +00:00
|
|
|
onResize();
|
2020-03-14 08:05:02 +00:00
|
|
|
});
|
|
|
|
|
2020-08-27 07:12:12 +00:00
|
|
|
session.defaultSession.setPermissionRequestHandler(
|
|
|
|
(webContents, permission, callback, details) => {
|
|
|
|
const preferences = getPermissionSettingPreference();
|
|
|
|
|
|
|
|
const reqUrl = webContents.getURL();
|
|
|
|
|
|
|
|
if (permissionCallbacks[reqUrl] == null) permissionCallbacks[reqUrl] = {};
|
|
|
|
|
|
|
|
if (permissionCallbacks[reqUrl][permission] == null) {
|
|
|
|
permissionCallbacks[reqUrl][permission] = {
|
|
|
|
called: false,
|
|
|
|
allowed: null,
|
|
|
|
callbacks: [],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const entry = permissionCallbacks[reqUrl][permission];
|
|
|
|
|
2020-08-27 13:10:59 +00:00
|
|
|
if (preferences === PERMISSION_MANAGEMENT_OPTIONS.ALLOW_ALWAYS) {
|
2020-08-27 07:12:12 +00:00
|
|
|
entry.callbacks.forEach(callback => callback(true));
|
|
|
|
entry.callbacks = [];
|
|
|
|
entry.allowed = true;
|
|
|
|
entry.called = true;
|
|
|
|
return callback(true);
|
|
|
|
}
|
2020-08-27 13:10:59 +00:00
|
|
|
if (preferences === PERMISSION_MANAGEMENT_OPTIONS.DENY_ALWAYS) {
|
2020-08-27 07:12:12 +00:00
|
|
|
entry.callbacks.forEach(callback => callback(false));
|
|
|
|
entry.callbacks = [];
|
|
|
|
entry.allowed = false;
|
|
|
|
entry.called = true;
|
|
|
|
return callback(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry.called) {
|
|
|
|
if (entry.allowed == null) return;
|
|
|
|
return callback(entry.allowed);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry.callbacks.length === 0) {
|
|
|
|
entry.callbacks.push(callback);
|
|
|
|
|
|
|
|
mainWindow.webContents.send('permission-prompt', {
|
|
|
|
url: reqUrl,
|
|
|
|
permission,
|
|
|
|
details,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
entry.callbacks.push(callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
session.defaultSession.setPermissionCheckHandler(
|
|
|
|
(webContents, permission) => {
|
|
|
|
const reqUrl = webContents.getURL();
|
|
|
|
|
|
|
|
let entry = permissionCallbacks[reqUrl];
|
|
|
|
if (entry != null) entry = entry[permission];
|
|
|
|
|
|
|
|
if (entry == null || !entry.called) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry.allowed;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
ipcMain.on('permission-response', (evnt, ...args) => {
|
|
|
|
if (args[0] == null) return;
|
|
|
|
const {url, permission, allowed} = args[0];
|
|
|
|
|
|
|
|
let entry = permissionCallbacks[url];
|
|
|
|
if (entry != null) entry = entry[permission];
|
|
|
|
|
|
|
|
if (entry != null && !entry.called) {
|
|
|
|
entry.called = true;
|
|
|
|
entry.allowed = allowed;
|
|
|
|
if (allowed != null)
|
|
|
|
entry.callbacks.forEach(callback => callback(allowed));
|
|
|
|
entry.callbacks = [];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
ipcMain.on('reset-ignored-permissions', evnt => {
|
|
|
|
Object.entries(permissionCallbacks).forEach(([_, permissions]) => {
|
|
|
|
Object.entries(permissions).forEach(([_, entry]) => {
|
|
|
|
if (entry.called && entry.allowed == null) entry.called = false;
|
|
|
|
entry.callbacks = [];
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-08-04 16:04:10 +00:00
|
|
|
ipcMain.on('start-watching-file', async (event, fileInfo) => {
|
2020-07-05 07:41:33 +00:00
|
|
|
let path = fileInfo.path.replace('file://', '');
|
|
|
|
if (process.platform === 'win32') {
|
|
|
|
path = trimStart(path, '/');
|
|
|
|
}
|
2020-07-26 14:48:23 +00:00
|
|
|
app.addRecentDocument(path);
|
2020-08-04 16:04:10 +00:00
|
|
|
await stopWatchFiles();
|
2020-08-04 15:53:12 +00:00
|
|
|
watchFiles(path);
|
2020-07-03 21:58:12 +00:00
|
|
|
});
|
|
|
|
|
2020-08-04 16:04:10 +00:00
|
|
|
ipcMain.on('stop-watcher', async () => {
|
|
|
|
await stopWatchFiles();
|
2020-07-03 21:58:12 +00:00
|
|
|
});
|
|
|
|
|
2020-07-04 18:46:33 +00:00
|
|
|
ipcMain.on('open-new-window', (event, data) => {
|
|
|
|
const handler = chooseOpenWindowHandler(data.url);
|
|
|
|
|
|
|
|
if (handler === 'useWindow') {
|
|
|
|
let win = new BrowserWindow({
|
|
|
|
width: 800,
|
|
|
|
height: 600,
|
|
|
|
webPreferences: {
|
|
|
|
devTools: false,
|
|
|
|
},
|
2020-07-05 09:20:36 +00:00
|
|
|
});
|
2020-07-04 18:46:33 +00:00
|
|
|
win.setMenu(null);
|
|
|
|
win.loadURL(data.url);
|
|
|
|
win.once('ready-to-show', () => {
|
|
|
|
win.show();
|
|
|
|
});
|
|
|
|
win.on('closed', () => {
|
|
|
|
win = null;
|
|
|
|
});
|
|
|
|
} else if (handler === 'useShell') {
|
|
|
|
shell.openExternal(data.url);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-03-14 08:05:02 +00:00
|
|
|
ipcMain.on('http-auth-promt-response', (event, ...args) => {
|
|
|
|
if (!args[0].url) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const {url, username, password} = args[0];
|
|
|
|
if (!httpAuthCallbacks[url]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
httpAuthCallbacks[url].forEach(cb => cb(username, password));
|
|
|
|
httpAuthCallbacks[url] = null;
|
|
|
|
});
|
|
|
|
|
2020-06-09 08:43:41 +00:00
|
|
|
ipcMain.on('prefers-color-scheme-select', (event, scheme) => {
|
2020-09-22 07:24:05 +00:00
|
|
|
if (!scheme) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nativeTheme.themeSource = scheme;
|
2020-06-09 08:43:41 +00:00
|
|
|
});
|
|
|
|
|
2020-07-03 11:09:40 +00:00
|
|
|
ipcMain.handle('install-extension', (event, extensionId) => {
|
2020-07-05 08:23:42 +00:00
|
|
|
let isLocalExtension;
|
|
|
|
|
|
|
|
try {
|
|
|
|
isLocalExtension = fs.statSync(extensionId).isDirectory();
|
|
|
|
} catch {
|
|
|
|
isLocalExtension = false;
|
|
|
|
}
|
2020-07-03 11:09:40 +00:00
|
|
|
|
|
|
|
if (isLocalExtension) {
|
|
|
|
return electron.BrowserWindow.addDevToolsExtension(extensionId);
|
|
|
|
}
|
2020-07-05 08:23:42 +00:00
|
|
|
|
2020-07-03 11:09:40 +00:00
|
|
|
const id = extensionId
|
|
|
|
.replace(/\/$/, '')
|
|
|
|
.split('/')
|
|
|
|
.pop();
|
|
|
|
|
2020-06-23 12:02:29 +00:00
|
|
|
return installExtension(id, true);
|
|
|
|
});
|
|
|
|
|
2020-07-04 08:26:23 +00:00
|
|
|
ipcMain.on('uninstall-extension', (event, name) =>
|
|
|
|
BrowserWindow.removeDevToolsExtension(name)
|
|
|
|
);
|
2020-06-23 12:02:29 +00:00
|
|
|
|
2020-07-05 08:23:42 +00:00
|
|
|
ipcMain.handle('get-local-extension-path', async event => {
|
|
|
|
try {
|
|
|
|
const {filePaths = []} = await dialog.showOpenDialog({
|
|
|
|
properties: ['openDirectory'],
|
|
|
|
});
|
|
|
|
|
|
|
|
const [localExtensionPath = ''] = filePaths;
|
|
|
|
return localExtensionPath;
|
|
|
|
} catch {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-07-12 12:53:31 +00:00
|
|
|
ipcMain.handle('get-screen-shot-save-path', async event => {
|
|
|
|
try {
|
|
|
|
const {filePaths = []} = await dialog.showOpenDialog({
|
|
|
|
properties: ['openDirectory'],
|
|
|
|
});
|
|
|
|
return filePaths[0];
|
|
|
|
} catch {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-06-06 07:48:37 +00:00
|
|
|
ipcMain.on('open-devtools', (event, ...args) => {
|
2020-06-09 13:25:05 +00:00
|
|
|
const {webViewId, bounds, mode} = args[0];
|
2020-06-04 15:49:03 +00:00
|
|
|
if (!webViewId) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-09 13:25:05 +00:00
|
|
|
const webView = webContents.fromId(webViewId);
|
|
|
|
|
|
|
|
if (mode === DEVTOOLS_MODES.UNDOCKED) {
|
|
|
|
return webView.openDevTools();
|
|
|
|
}
|
|
|
|
|
2020-06-07 10:03:44 +00:00
|
|
|
devToolsView = new BrowserView();
|
|
|
|
mainWindow.setBrowserView(devToolsView);
|
|
|
|
devToolsView.setBounds(bounds);
|
|
|
|
webView.setDevToolsWebContents(devToolsView.webContents);
|
2020-06-04 15:49:03 +00:00
|
|
|
webView.openDevTools();
|
2020-08-11 13:38:04 +00:00
|
|
|
devToolsView.webContents
|
|
|
|
.executeJavaScript(
|
|
|
|
`
|
|
|
|
(async function () {
|
|
|
|
const sleep = ms => (new Promise(resolve => setTimeout(resolve, ms)));
|
|
|
|
var retryCount = 0;
|
|
|
|
var done = false;
|
|
|
|
while(retryCount < 10 && !done) {
|
|
|
|
try {
|
|
|
|
retryCount++;
|
|
|
|
document.querySelectorAll('div[slot="insertion-point-main"]')[0].shadowRoot.querySelectorAll('.tabbed-pane-left-toolbar.toolbar')[0].style.display = 'none'
|
|
|
|
done = true
|
|
|
|
} catch(err){
|
|
|
|
await sleep(100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})()
|
|
|
|
`
|
|
|
|
)
|
|
|
|
.catch(captureOnSentry);
|
2020-06-04 15:49:03 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
ipcMain.on('close-devtools', (event, ...args) => {
|
2020-06-06 07:48:37 +00:00
|
|
|
const {webViewId} = args[0];
|
2020-06-12 04:44:31 +00:00
|
|
|
if (!webViewId) {
|
2020-06-04 15:49:03 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-07-06 11:31:05 +00:00
|
|
|
const _webContents = webContents.fromId(webViewId);
|
|
|
|
if (_webContents) {
|
|
|
|
_webContents.closeDevTools();
|
|
|
|
}
|
2020-06-12 04:44:31 +00:00
|
|
|
if (!devToolsView) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-07 10:03:44 +00:00
|
|
|
mainWindow.removeBrowserView(devToolsView);
|
2020-06-12 04:44:31 +00:00
|
|
|
devToolsView.destroy();
|
|
|
|
devToolsView = null;
|
2020-06-04 15:49:03 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
ipcMain.on('resize-devtools', (event, ...args) => {
|
2020-06-07 07:04:35 +00:00
|
|
|
const {bounds} = args[0];
|
2020-06-07 10:03:44 +00:00
|
|
|
if (!bounds || !devToolsView) {
|
2020-06-04 15:49:03 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-06-07 10:03:44 +00:00
|
|
|
devToolsView.setBounds(bounds);
|
2020-06-04 15:49:03 +00:00
|
|
|
});
|
|
|
|
|
2022-01-11 19:24:22 +00:00
|
|
|
ipcMain.on('download-preferences', (event, ...args) => {
|
|
|
|
session.defaultSession.downloadURL(args[0].url);
|
|
|
|
});
|
|
|
|
|
2020-03-14 08:05:02 +00:00
|
|
|
mainWindow.on('closed', () => {
|
|
|
|
mainWindow = null;
|
|
|
|
});
|
|
|
|
|
2020-08-08 09:03:15 +00:00
|
|
|
mainWindow.webContents.on(
|
|
|
|
'new-window',
|
|
|
|
(event, url, frameName, disposition, options) => {
|
|
|
|
if (url?.indexOf('headwayapp.co') !== -1) {
|
|
|
|
event.preventDefault();
|
|
|
|
shell.openExternal(url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-03-14 08:05:02 +00:00
|
|
|
const menuBuilder = new MenuBuilder(mainWindow);
|
|
|
|
menuBuilder.buildMenu();
|
|
|
|
|
2020-06-13 06:55:57 +00:00
|
|
|
appUpdater.on('status-changed', nextStatus => {
|
2020-06-10 20:05:31 +00:00
|
|
|
menuBuilder.buildMenu(true);
|
2020-06-22 16:48:06 +00:00
|
|
|
mainWindow.webContents.send('updater-status-changed', {nextStatus});
|
2020-06-10 20:05:31 +00:00
|
|
|
});
|
2020-03-14 08:05:02 +00:00
|
|
|
// Remove this if your app does not use auto updates
|
2020-08-05 05:38:05 +00:00
|
|
|
appUpdater
|
|
|
|
.checkForUpdatesAndNotify()
|
|
|
|
.catch(err => console.log('Error while updating app', err));
|
2019-09-04 07:54:03 +00:00
|
|
|
};
|