Nativefier/app/src/components/mainWindow/mainWindow.js

234 lines
6.5 KiB
JavaScript

import fs from 'fs';
import path from 'path';
import { BrowserWindow, shell, ipcMain, dialog } from 'electron';
import windowStateKeeper from 'electron-window-state';
import helpers from './../../helpers/helpers';
import createMenu from './../menu/menu';
import initContextMenu from './../contextMenu/contextMenu';
const {
isOSX, linkIsInternal, getCssToInject, shouldInjectCss,
} = helpers;
const ZOOM_INTERVAL = 0.1;
function maybeHideWindow(window, event, fastQuit, tray) {
if (isOSX() && !fastQuit) {
// this is called when exiting from clicking the cross button on the window
event.preventDefault();
window.hide();
} else if (!fastQuit && tray) {
event.preventDefault();
window.hide();
}
// will close the window on other platforms
}
function maybeInjectCss(browserWindow) {
if (!shouldInjectCss()) {
return;
}
const cssToInject = getCssToInject();
const injectCss = () => {
browserWindow.webContents.insertCSS(cssToInject);
};
browserWindow.webContents.on('did-finish-load', () => {
// remove the injection of css the moment the page is loaded
browserWindow.webContents.removeListener('did-get-response-details', injectCss);
});
// on every page navigation inject the css
browserWindow.webContents.on('did-navigate', () => {
// we have to inject the css in did-get-response-details to prevent the fouc
// will run multiple times
browserWindow.webContents.on('did-get-response-details', injectCss);
});
}
/**
*
* @param {{}} inpOptions AppArgs from nativefier.json
* @param {function} onAppQuit
* @param {function} setDockBadge
* @returns {electron.BrowserWindow}
*/
function createMainWindow(inpOptions, onAppQuit, setDockBadge) {
const options = Object.assign({}, inpOptions);
const mainWindowState = windowStateKeeper({
defaultWidth: options.width || 1280,
defaultHeight: options.height || 800,
});
const mainWindow = new BrowserWindow({
frame: !options.hideWindowFrame,
width: mainWindowState.width,
height: mainWindowState.height,
minWidth: options.minWidth,
minHeight: options.minHeight,
maxWidth: options.maxWidth,
maxHeight: options.maxHeight,
x: mainWindowState.x,
y: mainWindowState.y,
autoHideMenuBar: !options.showMenuBar,
// Convert dashes to spaces because on linux the app name is joined with dashes
title: options.name,
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,
},
// after webpack path here should reference `resources/app/`
icon: path.join(__dirname, '../', '/icon.png'),
// set to undefined and not false because explicitly setting to false will disable full screen
fullscreen: options.fullScreen || undefined,
});
mainWindowState.manage(mainWindow);
// after first run, no longer force maximize to be true
if (options.maximize) {
mainWindow.maximize();
options.maximize = undefined;
fs.writeFileSync(path.join(__dirname, '..', 'nativefier.json'), JSON.stringify(options));
}
let currentZoom = options.zoom;
const onZoomIn = () => {
currentZoom += ZOOM_INTERVAL;
mainWindow.webContents.send('change-zoom', currentZoom);
};
const onZoomOut = () => {
currentZoom -= ZOOM_INTERVAL;
mainWindow.webContents.send('change-zoom', currentZoom);
};
const onZoomReset = () => {
mainWindow.webContents.send('change-zoom', options.zoom);
};
const clearAppData = () => {
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;
}
const { session } = mainWindow.webContents;
session.clearStorageData(() => {
session.clearCache(() => {
mainWindow.loadURL(options.targetUrl);
});
});
});
};
const onGoBack = () => {
mainWindow.webContents.goBack();
};
const onGoForward = () => {
mainWindow.webContents.goForward();
};
const getCurrentUrl = () => mainWindow.webContents.getURL();
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) {
initContextMenu(mainWindow);
}
if (options.userAgent) {
mainWindow.webContents.setUserAgent(options.userAgent);
}
maybeInjectCss(mainWindow);
mainWindow.webContents.on('did-finish-load', () => {
mainWindow.webContents.send('params', JSON.stringify(options));
});
if (options.counter) {
mainWindow.on('page-title-updated', (e, title) => {
const itemCountRegex = /[([{](\d*?)\+?[}\])]/;
const match = itemCountRegex.exec(title);
if (match) {
setDockBadge(match[1]);
} else {
setDockBadge('');
}
});
} else {
ipcMain.on('notification', () => {
if (!isOSX() || mainWindow.isFocused()) {
return;
}
setDockBadge('•');
});
mainWindow.on('focus', () => {
setDockBadge('');
});
}
mainWindow.webContents.on('new-window', (event, urlToGo) => {
if (mainWindow.useDefaultWindowBehaviour) {
mainWindow.useDefaultWindowBehaviour = false;
return;
}
if (linkIsInternal(options.targetUrl, urlToGo, options.internalUrls)) {
return;
}
event.preventDefault();
shell.openExternal(urlToGo);
});
mainWindow.loadURL(options.targetUrl);
mainWindow.on('close', (event) => {
if (mainWindow.isFullScreen()) {
mainWindow.setFullScreen(false);
mainWindow.once('leave-full-screen', maybeHideWindow.bind(this, mainWindow, event, options.fastQuit));
}
maybeHideWindow(mainWindow, event, options.fastQuit, options.tray);
});
return mainWindow;
}
ipcMain.on('cancelNewWindowOverride', () => {
const allWindows = BrowserWindow.getAllWindows();
allWindows.forEach((window) => {
// eslint-disable-next-line no-param-reassign
window.useDefaultWindowBehaviour = false;
});
});
export default createMainWindow;