2016-02-25 07:56:32 +01:00
|
|
|
import fs from 'fs';
|
2016-01-29 15:04:41 +01:00
|
|
|
import path from 'path';
|
2017-04-29 16:52:12 +02:00
|
|
|
import { BrowserWindow, shell, ipcMain, dialog } from 'electron';
|
2016-01-29 15:04:41 +01:00
|
|
|
import windowStateKeeper from 'electron-window-state';
|
2018-05-27 23:18:59 +02:00
|
|
|
import mainWindowHelpers from './mainWindowHelpers';
|
2018-07-21 15:16:02 +02:00
|
|
|
import helpers from '../../helpers/helpers';
|
|
|
|
import createMenu from '../menu/menu';
|
|
|
|
import initContextMenu from '../contextMenu/contextMenu';
|
2016-01-25 08:56:33 +01:00
|
|
|
|
2017-11-14 14:05:01 +01:00
|
|
|
const {
|
2018-05-24 09:02:44 +02:00
|
|
|
isOSX,
|
|
|
|
linkIsInternal,
|
|
|
|
getCssToInject,
|
|
|
|
shouldInjectCss,
|
|
|
|
getAppIcon,
|
|
|
|
nativeTabsSupported,
|
2018-05-28 14:14:54 +02:00
|
|
|
getCounterValue,
|
2017-11-14 14:05:01 +01:00
|
|
|
} = helpers;
|
2016-01-29 15:04:41 +01:00
|
|
|
|
2018-05-27 23:18:59 +02:00
|
|
|
const { onNewWindowHelper } = mainWindowHelpers;
|
|
|
|
|
2016-01-23 03:09:47 +01:00
|
|
|
const ZOOM_INTERVAL = 0.1;
|
|
|
|
|
2017-10-06 01:32:48 +02:00
|
|
|
function maybeHideWindow(window, event, fastQuit, tray) {
|
2017-04-29 16:52:12 +02:00
|
|
|
if (isOSX() && !fastQuit) {
|
|
|
|
// this is called when exiting from clicking the cross button on the window
|
|
|
|
event.preventDefault();
|
|
|
|
window.hide();
|
2017-10-06 01:32:48 +02:00
|
|
|
} else if (!fastQuit && tray) {
|
|
|
|
event.preventDefault();
|
|
|
|
window.hide();
|
2017-04-29 16:52:12 +02:00
|
|
|
}
|
|
|
|
// will close the window on other platforms
|
|
|
|
}
|
|
|
|
|
|
|
|
function maybeInjectCss(browserWindow) {
|
|
|
|
if (!shouldInjectCss()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const cssToInject = getCssToInject();
|
|
|
|
|
|
|
|
const injectCss = () => {
|
|
|
|
browserWindow.webContents.insertCSS(cssToInject);
|
|
|
|
};
|
2018-12-01 03:14:20 +01:00
|
|
|
const onHeadersReceived = (details, callback) => {
|
|
|
|
injectCss();
|
|
|
|
callback({ cancel: false, responseHeaders: details.responseHeaders });
|
|
|
|
};
|
2017-04-29 16:52:12 +02:00
|
|
|
|
|
|
|
browserWindow.webContents.on('did-finish-load', () => {
|
|
|
|
// remove the injection of css the moment the page is loaded
|
2018-12-01 03:14:20 +01:00
|
|
|
browserWindow.webContents.session.webRequest.onHeadersReceived(null);
|
2017-04-29 16:52:12 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
// on every page navigation inject the css
|
|
|
|
browserWindow.webContents.on('did-navigate', () => {
|
2019-01-02 05:38:45 +01:00
|
|
|
// we have to inject the css in onHeadersReceived so they're early enough
|
|
|
|
// will run multiple times, so did-finish-load will remove this handler
|
2018-12-01 03:14:20 +01:00
|
|
|
browserWindow.webContents.session.webRequest.onHeadersReceived(
|
2019-08-28 13:28:18 +02:00
|
|
|
{ urls: [] }, // Pass an empty filter list; null will not match _any_ urls
|
2018-12-01 03:14:20 +01:00
|
|
|
onHeadersReceived,
|
|
|
|
);
|
2017-04-29 16:52:12 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-02-08 16:03:29 +01:00
|
|
|
function clearCache(browserWindow, targetUrl = null) {
|
|
|
|
const { session } = browserWindow.webContents;
|
|
|
|
session.clearStorageData(() => {
|
|
|
|
session.clearCache(() => {
|
|
|
|
if (targetUrl) {
|
|
|
|
browserWindow.loadURL(targetUrl);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-10-23 01:38:39 +02:00
|
|
|
function setProxyRules(browserWindow, proxyRules) {
|
|
|
|
browserWindow.webContents.session.setProxy(
|
|
|
|
{
|
|
|
|
proxyRules,
|
|
|
|
},
|
|
|
|
() => {},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-01-23 03:09:47 +01:00
|
|
|
/**
|
|
|
|
*
|
2017-04-29 16:52:12 +02:00
|
|
|
* @param {{}} inpOptions AppArgs from nativefier.json
|
2016-01-23 08:12:53 +01:00
|
|
|
* @param {function} onAppQuit
|
|
|
|
* @param {function} setDockBadge
|
2016-01-23 03:09:47 +01:00
|
|
|
* @returns {electron.BrowserWindow}
|
|
|
|
*/
|
2017-04-29 16:52:12 +02:00
|
|
|
function createMainWindow(inpOptions, onAppQuit, setDockBadge) {
|
|
|
|
const options = Object.assign({}, inpOptions);
|
|
|
|
const mainWindowState = windowStateKeeper({
|
|
|
|
defaultWidth: options.width || 1280,
|
|
|
|
defaultHeight: options.height || 800,
|
|
|
|
});
|
|
|
|
|
2018-05-01 03:36:45 +02:00
|
|
|
const DEFAULT_WINDOW_OPTIONS = {
|
2017-04-29 16:52:12 +02:00
|
|
|
// Convert dashes to spaces because on linux the app name is joined with dashes
|
|
|
|
title: options.name,
|
2018-05-02 01:24:35 +02:00
|
|
|
tabbingIdentifier: nativeTabsSupported() ? options.name : undefined,
|
2017-04-29 16:52:12 +02:00
|
|
|
webPreferences: {
|
|
|
|
javascript: true,
|
|
|
|
plugins: true,
|
|
|
|
// node globals causes problems with sites like messenger.com
|
|
|
|
nodeIntegration: false,
|
|
|
|
webSecurity: !options.insecure,
|
|
|
|
preload: path.join(__dirname, 'static', 'preload.js'),
|
|
|
|
zoomFactor: options.zoom,
|
|
|
|
},
|
2018-05-01 03:36:45 +02:00
|
|
|
};
|
|
|
|
|
2019-08-22 21:37:49 +02:00
|
|
|
const browserwindowOptions = Object.assign({}, options.browserwindowOptions);
|
|
|
|
|
2018-05-24 09:02:44 +02:00
|
|
|
const mainWindow = new BrowserWindow(
|
|
|
|
Object.assign(
|
|
|
|
{
|
|
|
|
frame: !options.hideWindowFrame,
|
|
|
|
width: mainWindowState.width,
|
|
|
|
height: mainWindowState.height,
|
|
|
|
minWidth: options.minWidth,
|
|
|
|
minHeight: options.minHeight,
|
|
|
|
maxWidth: options.maxWidth,
|
|
|
|
maxHeight: options.maxHeight,
|
|
|
|
x: options.x,
|
|
|
|
y: options.y,
|
|
|
|
autoHideMenuBar: !options.showMenuBar,
|
|
|
|
// after webpack path here should reference `resources/app/`
|
|
|
|
icon: getAppIcon(),
|
|
|
|
// set to undefined and not false because explicitly setting to false will disable full screen
|
|
|
|
fullscreen: options.fullScreen || undefined,
|
|
|
|
// Whether the window should always stay on top of other windows. Default is false.
|
|
|
|
alwaysOnTop: options.alwaysOnTop,
|
2018-05-31 14:05:12 +02:00
|
|
|
titleBarStyle: options.titleBarStyle,
|
2018-12-01 20:04:55 +01:00
|
|
|
show: options.tray !== 'start-in-tray',
|
2019-08-22 21:25:58 +02:00
|
|
|
backgroundColor: options.backgroundColor,
|
2018-05-24 09:02:44 +02:00
|
|
|
},
|
|
|
|
DEFAULT_WINDOW_OPTIONS,
|
2019-08-22 21:37:49 +02:00
|
|
|
browserwindowOptions,
|
2018-05-24 09:02:44 +02:00
|
|
|
),
|
|
|
|
);
|
2017-04-29 16:52:12 +02:00
|
|
|
|
|
|
|
mainWindowState.manage(mainWindow);
|
|
|
|
|
|
|
|
// after first run, no longer force maximize to be true
|
|
|
|
if (options.maximize) {
|
|
|
|
mainWindow.maximize();
|
|
|
|
options.maximize = undefined;
|
2019-10-23 01:36:40 +02:00
|
|
|
try {
|
|
|
|
fs.writeFileSync(
|
|
|
|
path.join(__dirname, '..', 'nativefier.json'),
|
|
|
|
JSON.stringify(options),
|
|
|
|
);
|
|
|
|
} catch (exception) {
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.log(`WARNING: Ignored nativefier.json rewrital (${exception})`);
|
|
|
|
}
|
2017-04-29 16:52:12 +02:00
|
|
|
}
|
|
|
|
|
2018-05-02 01:24:35 +02:00
|
|
|
const withFocusedWindow = (block) => {
|
|
|
|
const focusedWindow = BrowserWindow.getFocusedWindow();
|
2018-05-24 09:02:44 +02:00
|
|
|
if (focusedWindow) {
|
2018-06-14 14:06:30 +02:00
|
|
|
return block(focusedWindow);
|
2018-05-24 09:02:44 +02:00
|
|
|
}
|
2018-06-14 14:06:30 +02:00
|
|
|
return undefined;
|
2018-05-02 01:24:35 +02:00
|
|
|
};
|
|
|
|
|
2018-04-22 21:54:29 +02:00
|
|
|
const adjustWindowZoom = (window, adjustment) => {
|
|
|
|
window.webContents.getZoomFactor((zoomFactor) => {
|
|
|
|
window.webContents.setZoomFactor(zoomFactor + adjustment);
|
|
|
|
});
|
2017-04-29 16:52:12 +02:00
|
|
|
};
|
|
|
|
|
2018-05-02 01:24:35 +02:00
|
|
|
const onZoomIn = () => {
|
2018-05-24 09:02:44 +02:00
|
|
|
withFocusedWindow((focusedWindow) =>
|
|
|
|
adjustWindowZoom(focusedWindow, ZOOM_INTERVAL),
|
|
|
|
);
|
2018-05-02 01:24:35 +02:00
|
|
|
};
|
2018-04-22 21:54:29 +02:00
|
|
|
|
2018-05-02 01:24:35 +02:00
|
|
|
const onZoomOut = () => {
|
2018-05-24 09:02:44 +02:00
|
|
|
withFocusedWindow((focusedWindow) =>
|
|
|
|
adjustWindowZoom(focusedWindow, -ZOOM_INTERVAL),
|
|
|
|
);
|
2018-05-02 01:24:35 +02:00
|
|
|
};
|
2017-04-29 16:52:12 +02:00
|
|
|
|
|
|
|
const onZoomReset = () => {
|
2018-05-02 01:24:35 +02:00
|
|
|
withFocusedWindow((focusedWindow) => {
|
|
|
|
focusedWindow.webContents.setZoomFactor(options.zoom);
|
|
|
|
});
|
2017-04-29 16:52:12 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const clearAppData = () => {
|
2018-05-24 09:02:44 +02:00
|
|
|
dialog.showMessageBox(
|
|
|
|
mainWindow,
|
|
|
|
{
|
|
|
|
type: 'warning',
|
|
|
|
buttons: ['Yes', 'Cancel'],
|
|
|
|
defaultId: 1,
|
|
|
|
title: 'Clear cache confirmation',
|
|
|
|
message:
|
|
|
|
'This will clear all data (cookies, local storage etc) from this app. Are you sure you wish to proceed?',
|
|
|
|
},
|
|
|
|
(response) => {
|
|
|
|
if (response !== 0) {
|
|
|
|
return;
|
|
|
|
}
|
2019-02-08 16:03:29 +01:00
|
|
|
clearCache(mainWindow, options.targetUrl);
|
2018-05-24 09:02:44 +02:00
|
|
|
},
|
|
|
|
);
|
2017-04-29 16:52:12 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const onGoBack = () => {
|
2018-05-02 01:24:35 +02:00
|
|
|
withFocusedWindow((focusedWindow) => {
|
|
|
|
focusedWindow.webContents.goBack();
|
|
|
|
});
|
2017-04-29 16:52:12 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const onGoForward = () => {
|
2018-05-02 01:24:35 +02:00
|
|
|
withFocusedWindow((focusedWindow) => {
|
|
|
|
focusedWindow.webContents.goForward();
|
|
|
|
});
|
2017-04-29 16:52:12 +02:00
|
|
|
};
|
|
|
|
|
2018-06-14 14:06:30 +02:00
|
|
|
const getCurrentUrl = () =>
|
|
|
|
withFocusedWindow((focusedWindow) => focusedWindow.webContents.getURL());
|
2017-04-29 16:52:12 +02:00
|
|
|
|
2018-05-27 20:04:08 +02:00
|
|
|
const onWillNavigate = (event, urlToGo) => {
|
|
|
|
if (!linkIsInternal(options.targetUrl, urlToGo, options.internalUrls)) {
|
|
|
|
event.preventDefault();
|
|
|
|
shell.openExternal(urlToGo);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-05-01 03:36:45 +02:00
|
|
|
let createNewWindow;
|
|
|
|
|
2018-05-02 01:24:35 +02:00
|
|
|
const createNewTab = (url, foreground) => {
|
|
|
|
withFocusedWindow((focusedWindow) => {
|
|
|
|
const newTab = createNewWindow(url);
|
|
|
|
focusedWindow.addTabbedWindow(newTab);
|
|
|
|
if (!foreground) {
|
|
|
|
focusedWindow.focus();
|
|
|
|
}
|
|
|
|
return newTab;
|
|
|
|
});
|
|
|
|
return undefined;
|
|
|
|
};
|
2018-05-01 03:36:45 +02:00
|
|
|
|
2018-05-27 23:18:59 +02:00
|
|
|
const createAboutBlankWindow = () => {
|
|
|
|
const window = createNewWindow('about:blank');
|
|
|
|
window.hide();
|
|
|
|
window.webContents.once('did-stop-loading', () => {
|
|
|
|
if (window.webContents.getURL() === 'about:blank') {
|
|
|
|
window.close();
|
|
|
|
} else {
|
|
|
|
window.show();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return window;
|
|
|
|
};
|
|
|
|
|
2018-05-02 01:24:35 +02:00
|
|
|
const onNewWindow = (event, urlToGo, _, disposition) => {
|
2018-05-27 04:50:36 +02:00
|
|
|
const preventDefault = (newGuest) => {
|
|
|
|
event.preventDefault();
|
|
|
|
if (newGuest) {
|
|
|
|
// eslint-disable-next-line no-param-reassign
|
|
|
|
event.newGuest = newGuest;
|
|
|
|
}
|
|
|
|
};
|
2018-05-27 23:18:59 +02:00
|
|
|
onNewWindowHelper(
|
|
|
|
urlToGo,
|
|
|
|
disposition,
|
|
|
|
options.targetUrl,
|
|
|
|
options.internalUrls,
|
|
|
|
preventDefault,
|
|
|
|
shell.openExternal,
|
|
|
|
createAboutBlankWindow,
|
|
|
|
nativeTabsSupported,
|
|
|
|
createNewTab,
|
|
|
|
);
|
2018-05-01 03:36:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const sendParamsOnDidFinishLoad = (window) => {
|
|
|
|
window.webContents.on('did-finish-load', () => {
|
|
|
|
window.webContents.send('params', JSON.stringify(options));
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
createNewWindow = (url) => {
|
|
|
|
const window = new BrowserWindow(DEFAULT_WINDOW_OPTIONS);
|
|
|
|
if (options.userAgent) {
|
|
|
|
window.webContents.setUserAgent(options.userAgent);
|
|
|
|
}
|
2019-10-23 01:38:39 +02:00
|
|
|
|
|
|
|
if (options.proxyRules) {
|
|
|
|
setProxyRules(window, options.proxyRules);
|
|
|
|
}
|
|
|
|
|
2018-05-01 03:36:45 +02:00
|
|
|
maybeInjectCss(window);
|
|
|
|
sendParamsOnDidFinishLoad(window);
|
|
|
|
window.webContents.on('new-window', onNewWindow);
|
2018-05-27 20:04:08 +02:00
|
|
|
window.webContents.on('will-navigate', onWillNavigate);
|
2018-05-01 03:36:45 +02:00
|
|
|
window.loadURL(url);
|
|
|
|
return window;
|
|
|
|
};
|
|
|
|
|
2017-04-29 16:52:12 +02:00
|
|
|
const menuOptions = {
|
|
|
|
nativefierVersion: options.nativefierVersion,
|
|
|
|
appQuit: onAppQuit,
|
|
|
|
zoomIn: onZoomIn,
|
|
|
|
zoomOut: onZoomOut,
|
|
|
|
zoomReset: onZoomReset,
|
|
|
|
zoomBuildTimeValue: options.zoom,
|
|
|
|
goBack: onGoBack,
|
|
|
|
goForward: onGoForward,
|
|
|
|
getCurrentUrl,
|
|
|
|
clearAppData,
|
|
|
|
disableDevTools: options.disableDevTools,
|
|
|
|
};
|
|
|
|
|
|
|
|
createMenu(menuOptions);
|
|
|
|
if (!options.disableContextMenu) {
|
2018-05-24 09:02:44 +02:00
|
|
|
initContextMenu(
|
|
|
|
createNewWindow,
|
|
|
|
nativeTabsSupported() ? createNewTab : undefined,
|
|
|
|
);
|
2017-04-29 16:52:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (options.userAgent) {
|
|
|
|
mainWindow.webContents.setUserAgent(options.userAgent);
|
|
|
|
}
|
|
|
|
|
2019-10-23 01:38:39 +02:00
|
|
|
if (options.proxyRules) {
|
|
|
|
setProxyRules(mainWindow, options.proxyRules);
|
|
|
|
}
|
|
|
|
|
2017-04-29 16:52:12 +02:00
|
|
|
maybeInjectCss(mainWindow);
|
2018-05-01 03:36:45 +02:00
|
|
|
sendParamsOnDidFinishLoad(mainWindow);
|
2017-04-29 16:52:12 +02:00
|
|
|
|
|
|
|
if (options.counter) {
|
|
|
|
mainWindow.on('page-title-updated', (e, title) => {
|
2018-05-28 14:14:54 +02:00
|
|
|
const counterValue = getCounterValue(title);
|
|
|
|
if (counterValue) {
|
|
|
|
setDockBadge(counterValue, options.bounce);
|
2017-04-29 16:52:12 +02:00
|
|
|
} else {
|
|
|
|
setDockBadge('');
|
|
|
|
}
|
2016-01-29 15:04:41 +01:00
|
|
|
});
|
2017-04-29 16:52:12 +02:00
|
|
|
} else {
|
|
|
|
ipcMain.on('notification', () => {
|
|
|
|
if (!isOSX() || mainWindow.isFocused()) {
|
|
|
|
return;
|
|
|
|
}
|
2018-04-14 23:17:25 +02:00
|
|
|
setDockBadge('•', options.bounce);
|
2017-04-29 16:52:12 +02:00
|
|
|
});
|
|
|
|
mainWindow.on('focus', () => {
|
|
|
|
setDockBadge('');
|
|
|
|
});
|
|
|
|
}
|
2016-01-29 15:04:41 +01:00
|
|
|
|
2018-08-22 22:06:44 +02:00
|
|
|
ipcMain.on('notification-click', () => {
|
|
|
|
mainWindow.show();
|
|
|
|
});
|
|
|
|
|
2018-05-01 03:36:45 +02:00
|
|
|
mainWindow.webContents.on('new-window', onNewWindow);
|
2018-05-27 20:04:08 +02:00
|
|
|
mainWindow.webContents.on('will-navigate', onWillNavigate);
|
2018-05-02 01:24:35 +02:00
|
|
|
|
2019-02-08 16:03:29 +01:00
|
|
|
if (options.clearCache) {
|
|
|
|
clearCache(mainWindow);
|
|
|
|
}
|
|
|
|
|
2017-04-29 16:52:12 +02:00
|
|
|
mainWindow.loadURL(options.targetUrl);
|
2016-05-26 12:01:33 +02:00
|
|
|
|
2018-05-02 01:24:35 +02:00
|
|
|
mainWindow.on('new-tab', () => createNewTab(options.targetUrl, true));
|
|
|
|
|
2017-04-29 16:52:12 +02:00
|
|
|
mainWindow.on('close', (event) => {
|
|
|
|
if (mainWindow.isFullScreen()) {
|
2018-05-02 01:24:35 +02:00
|
|
|
if (nativeTabsSupported()) {
|
|
|
|
mainWindow.moveTabToNewWindow();
|
|
|
|
}
|
2017-04-29 16:52:12 +02:00
|
|
|
mainWindow.setFullScreen(false);
|
2018-05-24 09:02:44 +02:00
|
|
|
mainWindow.once(
|
|
|
|
'leave-full-screen',
|
|
|
|
maybeHideWindow.bind(this, mainWindow, event, options.fastQuit),
|
|
|
|
);
|
2016-01-23 03:09:47 +01:00
|
|
|
}
|
2017-10-06 01:32:48 +02:00
|
|
|
maybeHideWindow(mainWindow, event, options.fastQuit, options.tray);
|
2019-02-08 16:03:29 +01:00
|
|
|
|
|
|
|
if (options.clearCache) {
|
|
|
|
clearCache(mainWindow);
|
|
|
|
}
|
2017-04-29 16:52:12 +02:00
|
|
|
});
|
2016-01-23 03:09:47 +01:00
|
|
|
|
2017-04-29 16:52:12 +02:00
|
|
|
return mainWindow;
|
2016-01-23 03:09:47 +01:00
|
|
|
}
|
|
|
|
|
2016-01-29 15:04:41 +01:00
|
|
|
export default createMainWindow;
|