diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 015668b..0000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,49 +0,0 @@
-module.exports = {
- globals: {
- // mocha
- describe: false,
- it: false,
- before: false,
- beforeEach: false,
- after: false,
- afterEach: false
- },
- rules: {
- indent: [
- 2,
- 4,
- {SwitchCase: 1}
- ],
- quotes: [
- 2,
- 'single'
- ],
- 'linebreak-style': [
- 2,
- 'unix'
- ],
- semi: [
- 2,
- 'always'
- ],
- 'max-len': 0,
- 'require-jsdoc': 0,
- 'padded-blocks': 0,
- 'no-throw-literal': 0,
- camelcase: 0,
- 'valid-jsdoc': 0,
- 'no-path-concat': 1,
- 'quote-props': [2, 'as-needed'],
- 'no-warning-comments': 1,
- 'no-control-regex': 0
- },
- env: {
- es6: true,
- browser: true,
- node: true
- },
- ecmaFeatures: {
- modules: true
- },
- extends: 'google'
-};
diff --git a/.eslintrc.yml b/.eslintrc.yml
new file mode 100644
index 0000000..eeafada
--- /dev/null
+++ b/.eslintrc.yml
@@ -0,0 +1,8 @@
+extends: airbnb-base
+plugins:
+ - import
+rules:
+ # TODO: Remove this when we have shifted away from the async package
+ no-shadow: 'warn'
+ # Gulpfiles and tests use dev dependencies
+ import/no-extraneous-dependencies: ['error', { devDependencies: ['gulpfile.babel.js', 'gulp/**/**.js', 'test/**/**.js']}]
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 26bede8..1560c79 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -15,23 +15,19 @@ Please include the following in your new issue:
See [here](https://github.com/jiahaog/nativefier#development) for instructions on how to set up a development environment.
-Follow the current code style, and make sure tests and lints pass before submitting with the following commands:
+We follow the [Airbnb Style Guide](https://github.com/airbnb/javascript), please make sure tests and lints pass when you submit your pull request.
-Run the following command before submitting the pull request:
+The following commands might be helpful:
```bash
-# Run tests and linting
-$ npm run ci
-```
+# Run specs and lint
+npm run ci
-Or you can run them separately:
+# Run specs only
+npm run test
-```bash
-# Tests
-$ npm run test
-
-# Lint source files
-$ npm run lint
+# Run linter only
+npm run lint
```
Thank you so much for your contribution!
diff --git a/app/.eslintrc.yml b/app/.eslintrc.yml
new file mode 100644
index 0000000..d4c13bf
--- /dev/null
+++ b/app/.eslintrc.yml
@@ -0,0 +1,2 @@
+settings:
+ import/core-modules: [ electron ]
diff --git a/app/src/components/contextMenu/contextMenu.js b/app/src/components/contextMenu/contextMenu.js
index d731277..2538e63 100644
--- a/app/src/components/contextMenu/contextMenu.js
+++ b/app/src/components/contextMenu/contextMenu.js
@@ -1,47 +1,48 @@
-import {Menu, ipcMain, shell, clipboard, BrowserWindow} from 'electron';
+// Because we are changing the properties of `mainWindow` in initContextMenu()
+/* eslint-disable no-param-reassign */
+import { Menu, ipcMain, shell, clipboard, BrowserWindow } from 'electron';
function initContextMenu(mainWindow) {
- ipcMain.on('contextMenuOpened', (event, targetHref) => {
- const contextMenuTemplate = [
- {
- label: 'Open with default browser',
- click: () => {
- if (targetHref) {
- shell.openExternal(targetHref);
- return;
- }
- }
- },
- {
- label: 'Open in new window',
- click: () => {
- if (targetHref) {
- new BrowserWindow().loadURL(targetHref);
- return;
- }
+ ipcMain.on('contextMenuOpened', (event, targetHref) => {
+ const contextMenuTemplate = [
+ {
+ label: 'Open with default browser',
+ click: () => {
+ if (targetHref) {
+ shell.openExternal(targetHref);
+ }
+ },
+ },
+ {
+ label: 'Open in new window',
+ click: () => {
+ if (targetHref) {
+ new BrowserWindow().loadURL(targetHref);
+ return;
+ }
- mainWindow.useDefaultWindowBehaviour = true;
- mainWindow.webContents.send('contextMenuClosed');
- }
- },
- {
- label: 'Copy link location',
- click: () => {
- if (targetHref) {
- clipboard.writeText(targetHref);
- return;
- }
+ mainWindow.useDefaultWindowBehaviour = true;
+ mainWindow.webContents.send('contextMenuClosed');
+ },
+ },
+ {
+ label: 'Copy link location',
+ click: () => {
+ if (targetHref) {
+ clipboard.writeText(targetHref);
+ return;
+ }
- mainWindow.useDefaultWindowBehaviour = true;
- mainWindow.webContents.send('contextMenuClosed');
- }
- }
- ];
+ mainWindow.useDefaultWindowBehaviour = true;
+ mainWindow.webContents.send('contextMenuClosed');
+ },
+ },
+ ];
- const contextMenu = Menu.buildFromTemplate(contextMenuTemplate);
- contextMenu.popup(mainWindow);
- mainWindow.contextMenuOpen = true;
- });
+ const contextMenu = Menu.buildFromTemplate(contextMenuTemplate);
+ contextMenu.popup(mainWindow);
+ mainWindow.contextMenuOpen = true;
+ });
}
export default initContextMenu;
diff --git a/app/src/components/login/loginWindow.js b/app/src/components/login/loginWindow.js
index 3427b01..12f7e1f 100644
--- a/app/src/components/login/loginWindow.js
+++ b/app/src/components/login/loginWindow.js
@@ -1,20 +1,20 @@
-import {BrowserWindow, ipcMain} from 'electron';
+import { BrowserWindow, ipcMain } from 'electron';
import path from 'path';
function createLoginWindow(loginCallback) {
- var loginWindow = new BrowserWindow({
- width: 300,
- height: 400,
- frame: false,
- resizable: false
- });
- loginWindow.loadURL('file://' + path.join(__dirname, '/static/login/login.html'));
+ const loginWindow = new BrowserWindow({
+ width: 300,
+ height: 400,
+ frame: false,
+ resizable: false,
+ });
+ loginWindow.loadURL(`file://${path.join(__dirname, '/static/login/login.html')}`);
- ipcMain.once('login-message', function(event, usernameAndPassword) {
- loginCallback(usernameAndPassword[0], usernameAndPassword[1]);
- loginWindow.close();
- });
- return loginWindow;
+ ipcMain.once('login-message', (event, usernameAndPassword) => {
+ loginCallback(usernameAndPassword[0], usernameAndPassword[1]);
+ loginWindow.close();
+ });
+ return loginWindow;
}
export default createLoginWindow;
diff --git a/app/src/components/mainWindow/mainWindow.js b/app/src/components/mainWindow/mainWindow.js
index 95e4678..62b9508 100644
--- a/app/src/components/mainWindow/mainWindow.js
+++ b/app/src/components/mainWindow/mainWindow.js
@@ -1,232 +1,234 @@
import fs from 'fs';
import path from 'path';
-import {BrowserWindow, shell, ipcMain, dialog} from 'electron';
+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 { isOSX, linkIsInternal, getCssToInject, shouldInjectCss } = helpers;
const ZOOM_INTERVAL = 0.1;
+function maybeHideWindow(window, event, fastQuit) {
+ if (isOSX() && !fastQuit) {
+ // this is called when exiting from clicking the cross button on the window
+ 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 {{}} options AppArgs from nativefier.json
+ * @param {{}} inpOptions AppArgs from nativefier.json
* @param {function} onAppQuit
* @param {function} setDockBadge
* @returns {electron.BrowserWindow}
*/
-function createMainWindow(options, onAppQuit, setDockBadge) {
- const mainWindowState = windowStateKeeper({
- defaultWidth: options.width || 1280,
- defaultHeight: options.height || 800
- });
+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
- });
+ 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);
+ mainWindowState.manage(mainWindow);
- // after first run, no longer force full screen to be true
- if (options.fullScreen) {
- options.fullScreen = undefined;
- fs.writeFileSync(path.join(__dirname, '..', 'nativefier.json'), JSON.stringify(options));
- }
+ // after first run, no longer force full screen to be true
+ if (options.fullScreen) {
+ options.fullScreen = undefined;
+ fs.writeFileSync(path.join(__dirname, '..', 'nativefier.json'), JSON.stringify(options));
+ }
- // 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));
- }
+ // 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;
+ let currentZoom = options.zoom;
- const onZoomIn = () => {
- currentZoom += ZOOM_INTERVAL;
- mainWindow.webContents.send('change-zoom', currentZoom);
- };
+ const onZoomIn = () => {
+ currentZoom += ZOOM_INTERVAL;
+ mainWindow.webContents.send('change-zoom', currentZoom);
+ };
- const onZoomOut = () => {
- 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 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) {
- const session = mainWindow.webContents.session;
- session.clearStorageData(() => {
- session.clearCache(() => {
- mainWindow.loadURL(options.targetUrl);
- });
- });
- }
+ 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;
+ session.clearStorageData(() => {
+ session.clearCache(() => {
+ mainWindow.loadURL(options.targetUrl);
});
- };
+ });
+ });
+ };
- const onGoBack = () => {
- mainWindow.webContents.goBack();
- };
+ const onGoBack = () => {
+ mainWindow.webContents.goBack();
+ };
- const onGoForward = () => {
- mainWindow.webContents.goForward();
- };
+ const onGoForward = () => {
+ mainWindow.webContents.goForward();
+ };
- const getCurrentUrl = () => {
- return mainWindow.webContents.getURL();
- };
+ 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: getCurrentUrl,
- clearAppData: clearAppData,
- disableDevTools: options.disableDevTools
- };
+ 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);
+ 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 (options.userAgent) {
- mainWindow.webContents.setUserAgent(options.userAgent);
+ if (linkIsInternal(options.targetUrl, urlToGo, options.internalUrls)) {
+ return;
}
+ event.preventDefault();
+ shell.openExternal(urlToGo);
+ });
- maybeInjectCss(mainWindow);
- mainWindow.webContents.on('did-finish-load', () => {
- mainWindow.webContents.send('params', JSON.stringify(options));
- });
+ mainWindow.loadURL(options.targetUrl);
- 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.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);
+ });
- 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);
- });
-
- return mainWindow;
+ return mainWindow;
}
ipcMain.on('cancelNewWindowOverride', () => {
- const allWindows = BrowserWindow.getAllWindows();
- allWindows.forEach(window => {
- window.useDefaultWindowBehaviour = false;
- });
+ const allWindows = BrowserWindow.getAllWindows();
+ allWindows.forEach((window) => {
+ // eslint-disable-next-line no-param-reassign
+ window.useDefaultWindowBehaviour = false;
+ });
});
-function maybeHideWindow(window, event, fastQuit) {
- if (isOSX() && !fastQuit) {
- // this is called when exiting from clicking the cross button on the window
- 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);
- });
-}
-
export default createMainWindow;
diff --git a/app/src/components/menu/menu.js b/app/src/components/menu/menu.js
index fd964c3..c6bcfa0 100644
--- a/app/src/components/menu/menu.js
+++ b/app/src/components/menu/menu.js
@@ -1,4 +1,4 @@
-import {Menu, shell, clipboard} from 'electron';
+import { Menu, shell, clipboard } from 'electron';
/**
* @param nativefierVersion
@@ -13,255 +13,265 @@ import {Menu, shell, clipboard} from 'electron';
* @param clearAppData
* @param disableDevTools
*/
-function createMenu({nativefierVersion, appQuit, zoomIn, zoomOut, zoomReset, zoomBuildTimeValue, goBack, goForward, getCurrentUrl, clearAppData, disableDevTools}) {
- if (Menu.getApplicationMenu()) {
- return;
- }
- const zoomResetLabel = (zoomBuildTimeValue === 1.0) ?
+function createMenu({ nativefierVersion,
+ appQuit,
+ zoomIn,
+ zoomOut,
+ zoomReset,
+ zoomBuildTimeValue,
+ goBack,
+ goForward,
+ getCurrentUrl,
+ clearAppData,
+ disableDevTools }) {
+ if (Menu.getApplicationMenu()) {
+ return;
+ }
+ const zoomResetLabel = (zoomBuildTimeValue === 1.0) ?
'Reset Zoom' :
`Reset Zoom (to ${zoomBuildTimeValue * 100}%, set at build time)`;
- const template = [
+ const template = [
+ {
+ label: 'Edit',
+ submenu: [
{
- label: 'Edit',
- submenu: [
- {
- label: 'Undo',
- accelerator: 'CmdOrCtrl+Z',
- role: 'undo'
- },
- {
- label: 'Redo',
- accelerator: 'Shift+CmdOrCtrl+Z',
- role: 'redo'
- },
- {
- type: 'separator'
- },
- {
- label: 'Cut',
- accelerator: 'CmdOrCtrl+X',
- role: 'cut'
- },
- {
- label: 'Copy',
- accelerator: 'CmdOrCtrl+C',
- role: 'copy'
- },
- {
- label: 'Copy Current URL',
- accelerator: 'CmdOrCtrl+L',
- click: () => {
- const currentURL = getCurrentUrl();
- clipboard.writeText(currentURL);
- }
- },
- {
- label: 'Paste',
- accelerator: 'CmdOrCtrl+V',
- role: 'paste'
- },
- {
- label: 'Select All',
- accelerator: 'CmdOrCtrl+A',
- role: 'selectall'
- },
- {
- label: 'Clear App Data',
- click: () => {
- clearAppData();
- }
- }
- ]
+ label: 'Undo',
+ accelerator: 'CmdOrCtrl+Z',
+ role: 'undo',
},
{
- label: 'View',
- submenu: [
- {
- label: 'Back',
- accelerator: 'CmdOrCtrl+[',
- click: () => {
- goBack();
- }
- },
- {
- label: 'Forward',
- accelerator: 'CmdOrCtrl+]',
- click: () => {
- goForward();
- }
- },
- {
- label: 'Reload',
- accelerator: 'CmdOrCtrl+R',
- click: (item, focusedWindow) => {
- if (focusedWindow) {
- focusedWindow.reload();
- }
- }
- },
- {
- type: 'separator'
- },
- {
- label: 'Toggle Full Screen',
- accelerator: (() => {
- if (process.platform === 'darwin') {
- return 'Ctrl+Command+F';
- }
- return 'F11';
- })(),
- click: (item, focusedWindow) => {
- if (focusedWindow) {
- focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
- }
- }
- },
- {
- label: 'Zoom In',
- accelerator: (() => {
- if (process.platform === 'darwin') {
- return 'Command+=';
- }
- return 'Ctrl+=';
- })(),
- click: () => {
- zoomIn();
- }
- },
- {
- label: 'Zoom Out',
- accelerator: (() => {
- if (process.platform === 'darwin') {
- return 'Command+-';
- }
- return 'Ctrl+-';
- })(),
- click: () => {
- zoomOut();
- }
- },
- {
- label: zoomResetLabel,
- accelerator: (() => {
- if (process.platform === 'darwin') {
- return 'Command+0';
- }
- return 'Ctrl+0';
- })(),
- click: () => {
- zoomReset();
- }
- },
- {
- label: 'Toggle Developer Tools',
- accelerator: (() => {
- if (process.platform === 'darwin') {
- return 'Alt+Command+I';
- }
- return 'Ctrl+Shift+I';
- })(),
- click: (item, focusedWindow) => {
- if (focusedWindow) {
- focusedWindow.toggleDevTools();
- }
- }
- }
- ]
+ label: 'Redo',
+ accelerator: 'Shift+CmdOrCtrl+Z',
+ role: 'redo',
},
{
- label: 'Window',
- role: 'window',
- submenu: [
- {
- label: 'Minimize',
- accelerator: 'CmdOrCtrl+M',
- role: 'minimize'
- },
- {
- label: 'Close',
- accelerator: 'CmdOrCtrl+W',
- role: 'close'
- }
- ]
+ type: 'separator',
},
{
- label: 'Help',
- role: 'help',
- submenu: [
- {
- label: `Built with Nativefier v${nativefierVersion}`,
- click: () => {
- shell.openExternal('https://github.com/jiahaog/nativefier');
- }
- },
- {
- label: 'Report an Issue',
- click: () => {
- shell.openExternal('https://github.com/jiahaog/nativefier/issues');
- }
- }
- ]
- }
- ];
-
- if (disableDevTools) {
- // remove last item (dev tools) from menu > view
- const submenu = template[1].submenu;
- submenu.splice(submenu.length - 1, 1);
- }
-
- if (process.platform === 'darwin') {
- template.unshift({
- label: 'Electron',
- submenu: [
- {
- label: 'Services',
- role: 'services',
- submenu: []
- },
- {
- type: 'separator'
- },
- {
- label: 'Hide App',
- accelerator: 'Command+H',
- role: 'hide'
- },
- {
- label: 'Hide Others',
- accelerator: 'Command+Shift+H',
- role: 'hideothers'
- },
- {
- label: 'Show All',
- role: 'unhide'
- },
- {
- type: 'separator'
- },
- {
- label: 'Quit',
- accelerator: 'Command+Q',
- click: () => {
- appQuit();
- }
- }
- ]
- });
- template[3].submenu.push(
- {
- type: 'separator'
- },
- {
- label: 'Bring All to Front',
- role: 'front'
+ label: 'Cut',
+ accelerator: 'CmdOrCtrl+X',
+ role: 'cut',
+ },
+ {
+ label: 'Copy',
+ accelerator: 'CmdOrCtrl+C',
+ role: 'copy',
+ },
+ {
+ label: 'Copy Current URL',
+ accelerator: 'CmdOrCtrl+L',
+ click: () => {
+ const currentURL = getCurrentUrl();
+ clipboard.writeText(currentURL);
+ },
+ },
+ {
+ label: 'Paste',
+ accelerator: 'CmdOrCtrl+V',
+ role: 'paste',
+ },
+ {
+ label: 'Select All',
+ accelerator: 'CmdOrCtrl+A',
+ role: 'selectall',
+ },
+ {
+ label: 'Clear App Data',
+ click: () => {
+ clearAppData();
+ },
+ },
+ ],
+ },
+ {
+ label: 'View',
+ submenu: [
+ {
+ label: 'Back',
+ accelerator: 'CmdOrCtrl+[',
+ click: () => {
+ goBack();
+ },
+ },
+ {
+ label: 'Forward',
+ accelerator: 'CmdOrCtrl+]',
+ click: () => {
+ goForward();
+ },
+ },
+ {
+ label: 'Reload',
+ accelerator: 'CmdOrCtrl+R',
+ click: (item, focusedWindow) => {
+ if (focusedWindow) {
+ focusedWindow.reload();
}
- );
- }
+ },
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: 'Toggle Full Screen',
+ accelerator: (() => {
+ if (process.platform === 'darwin') {
+ return 'Ctrl+Command+F';
+ }
+ return 'F11';
+ })(),
+ click: (item, focusedWindow) => {
+ if (focusedWindow) {
+ focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
+ }
+ },
+ },
+ {
+ label: 'Zoom In',
+ accelerator: (() => {
+ if (process.platform === 'darwin') {
+ return 'Command+=';
+ }
+ return 'Ctrl+=';
+ })(),
+ click: () => {
+ zoomIn();
+ },
+ },
+ {
+ label: 'Zoom Out',
+ accelerator: (() => {
+ if (process.platform === 'darwin') {
+ return 'Command+-';
+ }
+ return 'Ctrl+-';
+ })(),
+ click: () => {
+ zoomOut();
+ },
+ },
+ {
+ label: zoomResetLabel,
+ accelerator: (() => {
+ if (process.platform === 'darwin') {
+ return 'Command+0';
+ }
+ return 'Ctrl+0';
+ })(),
+ click: () => {
+ zoomReset();
+ },
+ },
+ {
+ label: 'Toggle Developer Tools',
+ accelerator: (() => {
+ if (process.platform === 'darwin') {
+ return 'Alt+Command+I';
+ }
+ return 'Ctrl+Shift+I';
+ })(),
+ click: (item, focusedWindow) => {
+ if (focusedWindow) {
+ focusedWindow.toggleDevTools();
+ }
+ },
+ },
+ ],
+ },
+ {
+ label: 'Window',
+ role: 'window',
+ submenu: [
+ {
+ label: 'Minimize',
+ accelerator: 'CmdOrCtrl+M',
+ role: 'minimize',
+ },
+ {
+ label: 'Close',
+ accelerator: 'CmdOrCtrl+W',
+ role: 'close',
+ },
+ ],
+ },
+ {
+ label: 'Help',
+ role: 'help',
+ submenu: [
+ {
+ label: `Built with Nativefier v${nativefierVersion}`,
+ click: () => {
+ shell.openExternal('https://github.com/jiahaog/nativefier');
+ },
+ },
+ {
+ label: 'Report an Issue',
+ click: () => {
+ shell.openExternal('https://github.com/jiahaog/nativefier/issues');
+ },
+ },
+ ],
+ },
+ ];
- const menu = Menu.buildFromTemplate(template);
- Menu.setApplicationMenu(menu);
+ if (disableDevTools) {
+ // remove last item (dev tools) from menu > view
+ const submenu = template[1].submenu;
+ submenu.splice(submenu.length - 1, 1);
+ }
+
+ if (process.platform === 'darwin') {
+ template.unshift({
+ label: 'Electron',
+ submenu: [
+ {
+ label: 'Services',
+ role: 'services',
+ submenu: [],
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: 'Hide App',
+ accelerator: 'Command+H',
+ role: 'hide',
+ },
+ {
+ label: 'Hide Others',
+ accelerator: 'Command+Shift+H',
+ role: 'hideothers',
+ },
+ {
+ label: 'Show All',
+ role: 'unhide',
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: 'Quit',
+ accelerator: 'Command+Q',
+ click: () => {
+ appQuit();
+ },
+ },
+ ],
+ });
+ template[3].submenu.push(
+ {
+ type: 'separator',
+ },
+ {
+ label: 'Bring All to Front',
+ role: 'front',
+ },
+ );
+ }
+
+ const menu = Menu.buildFromTemplate(template);
+ Menu.setApplicationMenu(menu);
}
export default createMenu;
diff --git a/app/src/helpers/helpers.js b/app/src/helpers/helpers.js
index aed6acf..c908a01 100644
--- a/app/src/helpers/helpers.js
+++ b/app/src/helpers/helpers.js
@@ -6,39 +6,39 @@ import path from 'path';
const INJECT_CSS_PATH = path.join(__dirname, '..', 'inject/inject.css');
function isOSX() {
- return os.platform() === 'darwin';
+ return os.platform() === 'darwin';
}
function isLinux() {
- return os.platform() === 'linux';
+ return os.platform() === 'linux';
}
function isWindows() {
- return os.platform() === 'win32';
+ return os.platform() === 'win32';
}
function linkIsInternal(currentUrl, newUrl, internalUrlRegex) {
- if (internalUrlRegex) {
- var regex = RegExp(internalUrlRegex);
- return regex.test(newUrl);
- }
+ if (internalUrlRegex) {
+ const regex = RegExp(internalUrlRegex);
+ return regex.test(newUrl);
+ }
- var currentDomain = wurl('domain', currentUrl);
- var newDomain = wurl('domain', newUrl);
- return currentDomain === newDomain;
+ const currentDomain = wurl('domain', currentUrl);
+ const newDomain = wurl('domain', newUrl);
+ return currentDomain === newDomain;
}
function shouldInjectCss() {
- try {
- fs.accessSync(INJECT_CSS_PATH, fs.F_OK);
- return true;
- } catch (e) {
- return false;
- }
+ try {
+ fs.accessSync(INJECT_CSS_PATH, fs.F_OK);
+ return true;
+ } catch (e) {
+ return false;
+ }
}
function getCssToInject() {
- return fs.readFileSync(INJECT_CSS_PATH).toString();
+ return fs.readFileSync(INJECT_CSS_PATH).toString();
}
/**
@@ -47,19 +47,20 @@ function getCssToInject() {
* @param message
*/
function debugLog(browserWindow, message) {
- // need the timeout as it takes time for the preload javascript to be loaded in the window
- setTimeout(() => {
- browserWindow.webContents.send('debug', message);
- }, 3000);
- console.log(message);
+ // need the timeout as it takes time for the preload javascript to be loaded in the window
+ setTimeout(() => {
+ browserWindow.webContents.send('debug', message);
+ }, 3000);
+ // eslint-disable-next-line no-console
+ console.log(message);
}
export default {
- isOSX,
- isLinux,
- isWindows,
- linkIsInternal,
- getCssToInject,
- debugLog,
- shouldInjectCss
+ isOSX,
+ isLinux,
+ isWindows,
+ linkIsInternal,
+ getCssToInject,
+ debugLog,
+ shouldInjectCss,
};
diff --git a/app/src/helpers/inferFlash.js b/app/src/helpers/inferFlash.js
index 5c13360..8b555f5 100644
--- a/app/src/helpers/inferFlash.js
+++ b/app/src/helpers/inferFlash.js
@@ -2,23 +2,7 @@ import fs from 'fs';
import path from 'path';
import helpers from './helpers';
-const {isOSX, isWindows, isLinux} = helpers;
-
-function inferFlash() {
- if (isOSX()) {
- return darwinMatch();
- }
-
- if (isWindows()) {
- return windowsMatch();
- }
-
- if (isLinux()) {
- return linuxMatch();
- }
-
- console.warn('Unable to determine OS to infer flash player');
-}
+const { isOSX, isWindows, isLinux } = helpers;
/**
* Synchronously find a file or directory
@@ -27,56 +11,72 @@ function inferFlash() {
* @param {boolean} [findDir] if true, search results will be limited to only directories
* @returns {Array}
*/
-function findSync(pattern, base, findDir) {
- const matches = [];
+function findSync(pattern, basePath, findDir) {
+ const matches = [];
- (function findSyncRecurse(base) {
- let children;
- try {
- children = fs.readdirSync(base);
- } catch (exception) {
- if (exception.code === 'ENOENT') {
- return;
- }
- throw exception;
+ (function findSyncRecurse(base) {
+ let children;
+ try {
+ children = fs.readdirSync(base);
+ } catch (exception) {
+ if (exception.code === 'ENOENT') {
+ return;
+ }
+ throw exception;
+ }
+
+ children.forEach((child) => {
+ const childPath = path.join(base, child);
+ const childIsDirectory = fs.lstatSync(childPath).isDirectory();
+ const patternMatches = pattern.test(childPath);
+
+ if (!patternMatches) {
+ if (!childIsDirectory) {
+ return;
}
+ findSyncRecurse(childPath);
+ return;
+ }
- children.forEach(child => {
- const childPath = path.join(base, child);
- const childIsDirectory = fs.lstatSync(childPath).isDirectory();
- const patternMatches = pattern.test(childPath);
+ if (!findDir) {
+ matches.push(childPath);
+ return;
+ }
- if (!patternMatches) {
- if (!childIsDirectory) {
- return;
- }
- findSyncRecurse(childPath);
- return;
- }
-
- if (!findDir) {
- matches.push(childPath);
- return;
- }
-
- if (childIsDirectory) {
- matches.push(childPath);
- }
- });
- })(base);
- return matches;
+ if (childIsDirectory) {
+ matches.push(childPath);
+ }
+ });
+ }(basePath));
+ return matches;
}
function linuxMatch() {
- return findSync(/libpepflashplayer\.so/, '/opt/google/chrome')[0];
+ return findSync(/libpepflashplayer\.so/, '/opt/google/chrome')[0];
}
function windowsMatch() {
- return findSync(/pepflashplayer\.dll/, 'C:\\Program Files (x86)\\Google\\Chrome')[0];
+ return findSync(/pepflashplayer\.dll/, 'C:\\Program Files (x86)\\Google\\Chrome')[0];
}
function darwinMatch() {
- return findSync(/PepperFlashPlayer.plugin/, '/Applications/Google Chrome.app/', true)[0];
+ return findSync(/PepperFlashPlayer.plugin/, '/Applications/Google Chrome.app/', true)[0];
}
+function inferFlash() {
+ if (isOSX()) {
+ return darwinMatch();
+ }
+
+ if (isWindows()) {
+ return windowsMatch();
+ }
+
+ if (isLinux()) {
+ return linuxMatch();
+ }
+
+ console.warn('Unable to determine OS to infer flash player');
+ return null;
+}
export default inferFlash;
diff --git a/app/src/main.js b/app/src/main.js
index 1deb91d..1189069 100644
--- a/app/src/main.js
+++ b/app/src/main.js
@@ -1,14 +1,15 @@
import 'source-map-support/register';
import fs from 'fs';
import path from 'path';
-import {app, crashReporter} from 'electron';
+import { app, crashReporter } from 'electron';
+import electronDownload from 'electron-dl';
+
import createLoginWindow from './components/login/loginWindow';
import createMainWindow from './components/mainWindow/mainWindow';
import helpers from './helpers/helpers';
import inferFlash from './helpers/inferFlash';
-import electronDownload from 'electron-dl';
-const {isOSX} = helpers;
+const { isOSX } = helpers;
electronDownload();
@@ -18,83 +19,82 @@ const appArgs = JSON.parse(fs.readFileSync(APP_ARGS_FILE_PATH, 'utf8'));
let mainWindow;
if (typeof appArgs.flashPluginDir === 'string') {
- app.commandLine.appendSwitch('ppapi-flash-path', appArgs.flashPluginDir);
+ app.commandLine.appendSwitch('ppapi-flash-path', appArgs.flashPluginDir);
} else if (appArgs.flashPluginDir) {
- const flashPath = inferFlash();
- app.commandLine.appendSwitch('ppapi-flash-path', flashPath);
+ const flashPath = inferFlash();
+ app.commandLine.appendSwitch('ppapi-flash-path', flashPath);
}
if (appArgs.ignoreCertificate) {
- app.commandLine.appendSwitch('ignore-certificate-errors');
+ app.commandLine.appendSwitch('ignore-certificate-errors');
}
// do nothing for setDockBadge if not OSX
let setDockBadge = () => {};
if (isOSX()) {
- setDockBadge = app.dock.setBadge;
+ setDockBadge = app.dock.setBadge;
}
app.on('window-all-closed', () => {
- if (!isOSX() || appArgs.fastQuit) {
- app.quit();
- }
+ if (!isOSX() || appArgs.fastQuit) {
+ app.quit();
+ }
});
app.on('activate', (event, hasVisibleWindows) => {
- if (isOSX()) {
+ if (isOSX()) {
// this is called when the dock is clicked
- if (!hasVisibleWindows) {
- mainWindow.show();
- }
+ if (!hasVisibleWindows) {
+ mainWindow.show();
}
+ }
});
app.on('before-quit', () => {
- // not fired when the close button on the window is clicked
- if (isOSX()) {
- // need to force a quit as a workaround here to simulate the osx app hiding behaviour
- // Somehow sokution at https://github.com/atom/electron/issues/444#issuecomment-76492576 does not work,
- // e.prevent default appears to persist
+ // not fired when the close button on the window is clicked
+ if (isOSX()) {
+ // need to force a quit as a workaround here to simulate the osx app hiding behaviour
+ // Somehow sokution at https://github.com/atom/electron/issues/444#issuecomment-76492576 does not work,
+ // e.prevent default appears to persist
- // might cause issues in the future as before-quit and will-quit events are not called
- app.exit(0);
- }
+ // might cause issues in the future as before-quit and will-quit events are not called
+ app.exit(0);
+ }
});
if (appArgs.crashReporter) {
- app.on('will-finish-launching', () => {
- crashReporter.start({
- productName: appArgs.name,
- submitURL: appArgs.crashReporter,
- autoSubmit: true
- });
+ app.on('will-finish-launching', () => {
+ crashReporter.start({
+ productName: appArgs.name,
+ submitURL: appArgs.crashReporter,
+ autoSubmit: true,
});
+ });
}
app.on('ready', () => {
- mainWindow = createMainWindow(appArgs, app.quit, setDockBadge);
+ mainWindow = createMainWindow(appArgs, app.quit, setDockBadge);
});
app.on('login', (event, webContents, request, authInfo, callback) => {
// for http authentication
- event.preventDefault();
- createLoginWindow(callback);
+ event.preventDefault();
+ createLoginWindow(callback);
});
if (appArgs.singleInstance) {
- const shouldQuit = app.makeSingleInstance(() => {
- // Someone tried to run a second instance, we should focus our window.
- if (mainWindow) {
- if (mainWindow.isMinimized()) {
- mainWindow.restore();
- }
- mainWindow.focus();
-
- }
- });
-
- if (shouldQuit) {
- app.quit();
+ const shouldQuit = app.makeSingleInstance(() => {
+ // Someone tried to run a second instance, we should focus our window.
+ if (mainWindow) {
+ if (mainWindow.isMinimized()) {
+ mainWindow.restore();
+ }
+ mainWindow.focus();
}
+ });
+
+ if (shouldQuit) {
+ app.quit();
+ }
}
diff --git a/app/src/static/.eslintrc.yml b/app/src/static/.eslintrc.yml
new file mode 100644
index 0000000..5c9fc4c
--- /dev/null
+++ b/app/src/static/.eslintrc.yml
@@ -0,0 +1,2 @@
+env:
+ browser: true
diff --git a/app/src/static/login/login.js b/app/src/static/login/login.js
index 78fbb67..2e35dfc 100644
--- a/app/src/static/login/login.js
+++ b/app/src/static/login/login.js
@@ -1,11 +1,12 @@
import electron from 'electron';
-const {ipcRenderer} = electron;
+
+const { ipcRenderer } = electron;
const form = document.getElementById('login-form');
-form.addEventListener('submit', event => {
- event.preventDefault();
- const username = document.getElementById('username-input').value;
- const password = document.getElementById('password-input').value;
- ipcRenderer.send('login-message', [username, password]);
+form.addEventListener('submit', (event) => {
+ event.preventDefault();
+ const username = document.getElementById('username-input').value;
+ const password = document.getElementById('password-input').value;
+ ipcRenderer.send('login-message', [username, password]);
});
diff --git a/app/src/static/preload.js b/app/src/static/preload.js
index a7d5ea5..09db72e 100644
--- a/app/src/static/preload.js
+++ b/app/src/static/preload.js
@@ -1,86 +1,85 @@
/**
Preload file that will be executed in the renderer process
*/
-import {ipcRenderer, webFrame} from 'electron';
+import { ipcRenderer, webFrame } from 'electron';
import path from 'path';
import fs from 'fs';
const INJECT_JS_PATH = path.join(__dirname, '../../', 'inject/inject.js');
-setNotificationCallback((title, opt) => {
- ipcRenderer.send('notification', title, opt);
-});
-
-document.addEventListener('DOMContentLoaded', () => {
- // do things
-
- window.addEventListener('contextmenu', event => {
- event.preventDefault();
- let targetElement = event.srcElement;
-
- // the clicked element is the deepest in the DOM, and may not be the bearing the href
- // for example, Google
- while (!targetElement.href && targetElement.parentElement) {
- targetElement = targetElement.parentElement;
- }
- const targetHref = targetElement.href;
-
- if (!targetHref) {
- ipcRenderer.once('contextMenuClosed', () => {
- clickSelector(event.target);
- ipcRenderer.send('cancelNewWindowOverride');
- });
- }
-
- ipcRenderer.send('contextMenuOpened', targetHref);
- }, false);
-
- injectScripts();
-});
-
-ipcRenderer.on('params', (event, message) => {
- const appArgs = JSON.parse(message);
- console.log('nativefier.json', appArgs);
-});
-
-ipcRenderer.on('debug', (event, message) => {
- console.log('debug:', message);
-});
-
-ipcRenderer.on('change-zoom', (event, message) => {
- webFrame.setZoomFactor(message);
-});
-
/**
* Patches window.Notification to set a callback on a new Notification
* @param callback
*/
function setNotificationCallback(callback) {
+ const OldNotify = window.Notification;
+ const newNotify = (title, opt) => {
+ callback(title, opt);
+ return new OldNotify(title, opt);
+ };
+ newNotify.requestPermission = OldNotify.requestPermission.bind(OldNotify);
+ Object.defineProperty(newNotify, 'permission', {
+ get: () => OldNotify.permission,
+ });
- const OldNotify = window.Notification;
- const newNotify = (title, opt) => {
- callback(title, opt);
- return new OldNotify(title, opt);
- };
- newNotify.requestPermission = OldNotify.requestPermission.bind(OldNotify);
- Object.defineProperty(newNotify, 'permission', {
- get: () => {
- return OldNotify.permission;
- }
- });
-
- window.Notification = newNotify;
+ window.Notification = newNotify;
}
function clickSelector(element) {
- const mouseEvent = new MouseEvent('click');
- element.dispatchEvent(mouseEvent);
+ const mouseEvent = new MouseEvent('click');
+ element.dispatchEvent(mouseEvent);
}
function injectScripts() {
- const needToInject = fs.existsSync(INJECT_JS_PATH);
- if (!needToInject) {
- return;
- }
- require(INJECT_JS_PATH);
+ const needToInject = fs.existsSync(INJECT_JS_PATH);
+ if (!needToInject) {
+ return;
+ }
+ // Dynamically require scripts
+ // eslint-disable-next-line global-require, import/no-dynamic-require
+ require(INJECT_JS_PATH);
}
+
+setNotificationCallback((title, opt) => {
+ ipcRenderer.send('notification', title, opt);
+});
+
+document.addEventListener('DOMContentLoaded', () => {
+ window.addEventListener('contextmenu', (event) => {
+ event.preventDefault();
+ let targetElement = event.srcElement;
+
+ // the clicked element is the deepest in the DOM, and may not be the bearing the href
+ // for example, Google
+ while (!targetElement.href && targetElement.parentElement) {
+ targetElement = targetElement.parentElement;
+ }
+ const targetHref = targetElement.href;
+
+ if (!targetHref) {
+ ipcRenderer.once('contextMenuClosed', () => {
+ clickSelector(event.target);
+ ipcRenderer.send('cancelNewWindowOverride');
+ });
+ }
+
+ ipcRenderer.send('contextMenuOpened', targetHref);
+ }, false);
+
+ injectScripts();
+});
+
+ipcRenderer.on('params', (event, message) => {
+ const appArgs = JSON.parse(message);
+ console.log('nativefier.json', appArgs);
+});
+
+ipcRenderer.on('debug', (event, message) => {
+ // eslint-disable-next-line no-console
+ console.log('debug:', message);
+});
+
+ipcRenderer.on('change-zoom', (event, message) => {
+ webFrame.setZoomFactor(message);
+});
+
diff --git a/gulp/build.js b/gulp/build.js
index 5bbcef3..7b832fb 100644
--- a/gulp/build.js
+++ b/gulp/build.js
@@ -1,19 +1,18 @@
import gulp from 'gulp';
-import PATHS from './helpers/src-paths';
-
import del from 'del';
import runSequence from 'run-sequence';
+import PATHS from './helpers/src-paths';
-gulp.task('build', callback => {
- runSequence('clean', ['build-cli', 'build-app', 'build-tests'], callback);
+gulp.task('build', (callback) => {
+ runSequence('clean', ['build-cli', 'build-app', 'build-tests'], callback);
});
-gulp.task('clean', callback => {
- del(PATHS.CLI_DEST).then(() => {
- del(PATHS.APP_DEST).then(() => {
- del(PATHS.TEST_DEST).then(() => {
- callback();
- });
- });
+gulp.task('clean', (callback) => {
+ del(PATHS.CLI_DEST).then(() => {
+ del(PATHS.APP_DEST).then(() => {
+ del(PATHS.TEST_DEST).then(() => {
+ callback();
+ });
});
+ });
});
diff --git a/gulp/build/build-app.js b/gulp/build/build-app.js
index 8ba2083..ab0b3e1 100644
--- a/gulp/build/build-app.js
+++ b/gulp/build/build-app.js
@@ -1,10 +1,9 @@
import gulp from 'gulp';
+import webpack from 'webpack-stream';
import PATHS from './../helpers/src-paths';
-import webpack from 'webpack-stream';
+const webpackConfig = require('./../../webpack.config.js');
-gulp.task('build-app', ['build-static'], () => {
- return gulp.src(PATHS.APP_MAIN_JS)
- .pipe(webpack(require('./../../webpack.config.js')))
- .pipe(gulp.dest(PATHS.APP_DEST));
-});
+gulp.task('build-app', ['build-static'], () => gulp.src(PATHS.APP_MAIN_JS)
+ .pipe(webpack(webpackConfig))
+ .pipe(gulp.dest(PATHS.APP_DEST)));
diff --git a/gulp/build/build-cli.js b/gulp/build/build-cli.js
index 0b91f6e..a3b54c5 100644
--- a/gulp/build/build-cli.js
+++ b/gulp/build/build-cli.js
@@ -2,8 +2,6 @@ import gulp from 'gulp';
import PATHS from './../helpers/src-paths';
import helpers from './../helpers/gulp-helpers';
-const {buildES6} = helpers;
+const { buildES6 } = helpers;
-gulp.task('build-cli', done => {
- return buildES6(PATHS.CLI_SRC_JS, PATHS.CLI_DEST, done);
-});
+gulp.task('build-cli', done => buildES6(PATHS.CLI_SRC_JS, PATHS.CLI_DEST, done));
diff --git a/gulp/build/build-static.js b/gulp/build/build-static.js
index 3cba6b2..543b4a4 100644
--- a/gulp/build/build-static.js
+++ b/gulp/build/build-static.js
@@ -2,15 +2,11 @@ import gulp from 'gulp';
import PATHS from './../helpers/src-paths';
import helpers from './../helpers/gulp-helpers';
-const {buildES6} = helpers;
+const { buildES6 } = helpers;
-gulp.task('build-static-not-js', () => {
- return gulp.src([PATHS.APP_STATIC_ALL, '!**/*.js'])
- .pipe(gulp.dest(PATHS.APP_STATIC_DEST));
-});
+gulp.task('build-static-not-js', () => gulp.src([PATHS.APP_STATIC_ALL, '!**/*.js'])
+ .pipe(gulp.dest(PATHS.APP_STATIC_DEST)));
-gulp.task('build-static-js', done => {
- return buildES6(PATHS.APP_STATIC_JS, PATHS.APP_STATIC_DEST, done);
-});
+gulp.task('build-static-js', done => buildES6(PATHS.APP_STATIC_JS, PATHS.APP_STATIC_DEST, done));
gulp.task('build-static', ['build-static-js', 'build-static-not-js']);
diff --git a/gulp/helpers/gulp-helpers.js b/gulp/helpers/gulp-helpers.js
index 36bd3e1..432a5ba 100644
--- a/gulp/helpers/gulp-helpers.js
+++ b/gulp/helpers/gulp-helpers.js
@@ -4,17 +4,17 @@ import sourcemaps from 'gulp-sourcemaps';
import babel from 'gulp-babel';
function shellExec(cmd, silent, callback) {
- shellJs.exec(cmd, {silent: silent}, (code, stdout, stderr) => {
- if (code) {
- callback(JSON.stringify({code, stdout, stderr}));
- return;
- }
- callback();
- });
+ shellJs.exec(cmd, { silent }, (code, stdout, stderr) => {
+ if (code) {
+ callback(JSON.stringify({ code, stdout, stderr }));
+ return;
+ }
+ callback();
+ });
}
function buildES6(src, dest, callback) {
- return gulp.src(src)
+ return gulp.src(src)
.pipe(sourcemaps.init())
.pipe(babel())
.on('error', callback)
@@ -23,6 +23,6 @@ function buildES6(src, dest, callback) {
}
export default {
- shellExec,
- buildES6
+ shellExec,
+ buildES6,
};
diff --git a/gulp/helpers/src-paths.js b/gulp/helpers/src-paths.js
index 933716b..512f64f 100644
--- a/gulp/helpers/src-paths.js
+++ b/gulp/helpers/src-paths.js
@@ -1,22 +1,22 @@
import path from 'path';
const paths = {
- APP_SRC: 'app/src',
- APP_DEST: 'app/lib',
- CLI_SRC: 'src',
- CLI_DEST: 'lib',
- TEST_SRC: 'test',
- TEST_DEST: 'built-tests'
+ APP_SRC: 'app/src',
+ APP_DEST: 'app/lib',
+ CLI_SRC: 'src',
+ CLI_DEST: 'lib',
+ TEST_SRC: 'test',
+ TEST_DEST: 'built-tests',
};
paths.APP_MAIN_JS = path.join(paths.APP_SRC, '/main.js');
-paths.APP_ALL = paths.APP_SRC + '/**/*';
-paths.APP_STATIC_ALL = path.join(paths.APP_SRC, 'static') + '/**/*';
-paths.APP_STATIC_JS = path.join(paths.APP_SRC, 'static') + '/**/*.js';
+paths.APP_ALL = `${paths.APP_SRC}/**/*`;
+paths.APP_STATIC_ALL = `${path.join(paths.APP_SRC, 'static')}/**/*`;
+paths.APP_STATIC_JS = `${path.join(paths.APP_SRC, 'static')}/**/*.js`;
paths.APP_STATIC_DEST = path.join(paths.APP_DEST, 'static');
-paths.CLI_SRC_JS = paths.CLI_SRC + '/**/*.js';
-paths.CLI_DEST_JS = paths.CLI_DEST + '/**/*.js';
-paths.TEST_SRC_JS = paths.TEST_SRC + '/**/*.js';
-paths.TEST_DEST_JS = paths.TEST_DEST + '/**/*.js';
+paths.CLI_SRC_JS = `${paths.CLI_SRC}/**/*.js`;
+paths.CLI_DEST_JS = `${paths.CLI_DEST}/**/*.js`;
+paths.TEST_SRC_JS = `${paths.TEST_SRC}/**/*.js`;
+paths.TEST_DEST_JS = `${paths.TEST_DEST}/**/*.js`;
export default paths;
diff --git a/gulp/release.js b/gulp/release.js
index 3d0e386..4e7dd98 100644
--- a/gulp/release.js
+++ b/gulp/release.js
@@ -2,12 +2,10 @@ import gulp from 'gulp';
import runSequence from 'run-sequence';
import helpers from './helpers/gulp-helpers';
-const {shellExec} = helpers;
+const { shellExec } = helpers;
-gulp.task('publish', done => {
- shellExec('npm publish', false, done);
+gulp.task('publish', (done) => {
+ shellExec('npm publish', false, done);
});
-gulp.task('release', callback => {
- return runSequence('build', 'publish', callback);
-});
+gulp.task('release', callback => runSequence('build', 'publish', callback));
diff --git a/gulp/test.js b/gulp/test.js
index a0dcd42..e52f50a 100644
--- a/gulp/test.js
+++ b/gulp/test.js
@@ -2,12 +2,10 @@ import gulp from 'gulp';
import runSequence from 'run-sequence';
import helpers from './helpers/gulp-helpers';
-const {shellExec} = helpers;
+const { shellExec } = helpers;
-gulp.task('prune', done => {
- shellExec('npm prune', true, done);
+gulp.task('prune', (done) => {
+ shellExec('npm prune', true, done);
});
-gulp.task('test', callback => {
- return runSequence('prune', 'mocha', callback);
-});
+gulp.task('test', callback => runSequence('prune', 'mocha', callback));
diff --git a/gulp/tests/build-tests.js b/gulp/tests/build-tests.js
index 6d5b1b8..98786e8 100644
--- a/gulp/tests/build-tests.js
+++ b/gulp/tests/build-tests.js
@@ -2,8 +2,6 @@ import gulp from 'gulp';
import PATHS from './../helpers/src-paths';
import helpers from './../helpers/gulp-helpers';
-const {buildES6} = helpers;
+const { buildES6 } = helpers;
-gulp.task('build-tests', done => {
- return buildES6(PATHS.TEST_SRC_JS, PATHS.TEST_DEST, done);
-});
+gulp.task('build-tests', done => buildES6(PATHS.TEST_SRC_JS, PATHS.TEST_DEST, done));
diff --git a/gulp/tests/mocha.js b/gulp/tests/mocha.js
index bb67128..8aba174 100644
--- a/gulp/tests/mocha.js
+++ b/gulp/tests/mocha.js
@@ -1,32 +1,27 @@
import gulp from 'gulp';
+import istanbul from 'gulp-istanbul';
+import { Instrumenter } from 'isparta';
+import mocha from 'gulp-mocha';
import PATHS from './../helpers/src-paths';
-import istanbul from 'gulp-istanbul';
-import {Instrumenter} from 'isparta';
-import mocha from 'gulp-mocha';
-
-gulp.task('mocha', done => {
- gulp.src([PATHS.CLI_SRC_JS, '!src/cli.js'])
- .pipe(istanbul({
- instrumenter: Instrumenter,
- includeUntested: true
- }))
- .pipe(istanbul.hookRequire()) // Force `require` to return covered files
- .on('finish', () => {
- return gulp.src(PATHS.TEST_SRC, {read: false})
- .pipe(mocha({
- compilers: 'js:babel-core/register',
- recursive: true
- }))
- .pipe(istanbul.writeReports({
- dir: './coverage',
- reporters: ['lcov'],
- reportOpts: {dir: './coverage'}
- }))
- .on('end', done);
- });
+gulp.task('mocha', (done) => {
+ gulp.src([PATHS.CLI_SRC_JS, '!src/cli.js'])
+ .pipe(istanbul({
+ instrumenter: Instrumenter,
+ includeUntested: true,
+ }))
+ .pipe(istanbul.hookRequire()) // Force `require` to return covered files
+ .on('finish', () => gulp.src(PATHS.TEST_SRC, { read: false })
+ .pipe(mocha({
+ compilers: 'js:babel-core/register',
+ recursive: true,
+ }))
+ .pipe(istanbul.writeReports({
+ dir: './coverage',
+ reporters: ['lcov'],
+ reportOpts: { dir: './coverage' },
+ }))
+ .on('end', done));
});
-gulp.task('tdd', ['mocha'], () => {
- return gulp.watch(['src/**/*.js', 'test/**/*.js'], ['mocha']);
-});
+gulp.task('tdd', ['mocha'], () => gulp.watch(['src/**/*.js', 'test/**/*.js'], ['mocha']));
diff --git a/gulp/watch.js b/gulp/watch.js
index c1d5433..9bc325d 100644
--- a/gulp/watch.js
+++ b/gulp/watch.js
@@ -2,15 +2,15 @@ import gulp from 'gulp';
import PATHS from './helpers/src-paths';
gulp.task('watch', ['build'], () => {
- var handleError = function(error) {
- console.error(error);
- };
- gulp.watch(PATHS.APP_ALL, ['build-app'])
+ const handleError = function (error) {
+ console.error(error);
+ };
+ gulp.watch(PATHS.APP_ALL, ['build-app'])
.on('error', handleError);
- gulp.watch(PATHS.CLI_SRC_JS, ['build-cli'])
+ gulp.watch(PATHS.CLI_SRC_JS, ['build-cli'])
.on('error', handleError);
- gulp.watch(PATHS.TEST_SRC_JS, ['build-tests'])
+ gulp.watch(PATHS.TEST_SRC_JS, ['build-tests'])
.on('error', handleError);
});
diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index 912b3d4..0cfb1c6 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -2,8 +2,8 @@ import gulp from 'gulp';
import requireDir from 'require-dir';
requireDir('./gulp', {
- recurse: true,
- duplicates: true
+ recurse: true,
+ duplicates: true,
});
gulp.task('default', ['build']);
diff --git a/package.json b/package.json
index aa92937..04b7f0d 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"test": "gulp test",
"tdd": "gulp tdd",
"lint": "eslint .",
+ "lint:fix": "eslint . --fix",
"ci": "gulp build test && npm run lint",
"clean": "gulp clean",
"build": "gulp build",
@@ -68,8 +69,9 @@
"babel-register": "^6.6.0",
"chai": "^3.4.1",
"del": "^2.2.0",
- "eslint": "^2.10.2",
- "eslint-config-google": "^0.5.0",
+ "eslint": "^3.19.0",
+ "eslint-config-airbnb-base": "^11.1.3",
+ "eslint-plugin-import": "^2.2.0",
"gulp": "^3.9.0",
"gulp-babel": "^6.1.1",
"gulp-istanbul": "^1.1.1",
diff --git a/src/build/buildApp.js b/src/build/buildApp.js
index 9214201..d82da8a 100644
--- a/src/build/buildApp.js
+++ b/src/build/buildApp.js
@@ -7,8 +7,100 @@ import ncp from 'ncp';
const copy = ncp.ncp;
/**
- * Creates a temporary directory and copies the './app folder' inside, and adds a text file with the configuration
- * for the single page app.
+ * Only picks certain app args to pass to nativefier.json
+ * @param options
+ */
+function selectAppArgs(options) {
+ return {
+ name: options.name,
+ targetUrl: options.targetUrl,
+ counter: options.counter,
+ width: options.width,
+ height: options.height,
+ minWidth: options.minWidth,
+ minHeight: options.minHeight,
+ maxWidth: options.maxWidth,
+ maxHeight: options.maxHeight,
+ showMenuBar: options.showMenuBar,
+ fastQuit: options.fastQuit,
+ userAgent: options.userAgent,
+ nativefierVersion: options.nativefierVersion,
+ ignoreCertificate: options.ignoreCertificate,
+ insecure: options.insecure,
+ flashPluginDir: options.flashPluginDir,
+ fullScreen: options.fullScreen,
+ hideWindowFrame: options.hideWindowFrame,
+ maximize: options.maximize,
+ disableContextMenu: options.disableContextMenu,
+ disableDevTools: options.disableDevTools,
+ zoom: options.zoom,
+ internalUrls: options.internalUrls,
+ crashReporter: options.crashReporter,
+ singleInstance: options.singleInstance,
+ };
+}
+
+function maybeCopyScripts(srcs, dest) {
+ if (!srcs) {
+ return new Promise((resolve) => {
+ resolve();
+ });
+ }
+ const promises = srcs.map(src => new Promise((resolve, reject) => {
+ if (!fs.existsSync(src)) {
+ reject('Error copying injection files: file not found');
+ return;
+ }
+
+ let destFileName;
+ if (path.extname(src) === '.js') {
+ destFileName = 'inject.js';
+ } else if (path.extname(src) === '.css') {
+ destFileName = 'inject.css';
+ } else {
+ resolve();
+ return;
+ }
+
+ copy(src, path.join(dest, 'inject', destFileName), (error) => {
+ if (error) {
+ reject(`Error Copying injection files: ${error}`);
+ return;
+ }
+ resolve();
+ });
+ }));
+
+ return new Promise((resolve, reject) => {
+ Promise.all(promises)
+ .then(() => {
+ resolve();
+ })
+ .catch((error) => {
+ reject(error);
+ });
+ });
+}
+
+function normalizeAppName(appName, url) {
+ // use a simple 3 byte random string to prevent collision
+ const hash = crypto.createHash('md5');
+ hash.update(url);
+ const postFixHash = hash.digest('hex').substring(0, 6);
+ const normalized = _.kebabCase(appName.toLowerCase());
+ return `${normalized}-nativefier-${postFixHash}`;
+}
+
+function changeAppPackageJsonName(appPath, name, url) {
+ const packageJsonPath = path.join(appPath, '/package.json');
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath));
+ packageJson.name = normalizeAppName(name, url);
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson));
+}
+
+/**
+ * Creates a temporary directory and copies the './app folder' inside,
+ * and adds a text file with the configuration for the single page app.
*
* @param {string} src
* @param {string} dest
@@ -16,119 +108,25 @@ const copy = ncp.ncp;
* @param callback
*/
function buildApp(src, dest, options, callback) {
- const appArgs = selectAppArgs(options);
- copy(src, dest, error => {
- if (error) {
- callback(`Error Copying temporary directory: ${error}`);
- return;
- }
-
- fs.writeFileSync(path.join(dest, '/nativefier.json'), JSON.stringify(appArgs));
-
- maybeCopyScripts(options.inject, dest)
- .catch(error => {
- console.warn(error);
- })
- .then(() => {
- changeAppPackageJsonName(dest, appArgs.name, appArgs.targetUrl);
- callback();
- });
- });
-}
-
-function maybeCopyScripts(srcs, dest) {
- if (!srcs) {
- return new Promise(resolve => {
- resolve();
- });
+ const appArgs = selectAppArgs(options);
+ copy(src, dest, (error) => {
+ if (error) {
+ callback(`Error Copying temporary directory: ${error}`);
+ return;
}
- const promises = srcs.map(src => {
- return new Promise((resolve, reject) => {
- if (!fs.existsSync(src)) {
- reject('Error copying injection files: file not found');
- return;
- }
- let destFileName;
- if (path.extname(src) === '.js') {
- destFileName = 'inject.js';
- } else if (path.extname(src) === '.css') {
- destFileName = 'inject.css';
- } else {
- resolve();
- return;
- }
+ fs.writeFileSync(path.join(dest, '/nativefier.json'), JSON.stringify(appArgs));
- copy(src, path.join(dest, 'inject', destFileName), error => {
- if (error) {
- reject(`Error Copying injection files: ${error}`);
- return;
- }
- resolve();
- });
- });
- });
-
- return new Promise((resolve, reject) => {
- Promise.all(promises)
- .then(() => {
- resolve();
- })
- .catch(error => {
- reject(error);
- });
- });
+ maybeCopyScripts(options.inject, dest)
+ .catch((error) => {
+ console.warn(error);
+ })
+ .then(() => {
+ changeAppPackageJsonName(dest, appArgs.name, appArgs.targetUrl);
+ callback();
+ });
+ });
}
-function changeAppPackageJsonName(appPath, name, url) {
- const packageJsonPath = path.join(appPath, '/package.json');
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath));
- packageJson.name = normalizeAppName(name, url);
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson));
-}
-
-/**
- * Only picks certain app args to pass to nativefier.json
- * @param options
- * @returns {{name: (*|string), targetUrl: (string|*), counter: *, width: *, height: *, showMenuBar: *, userAgent: *, nativefierVersion: *, insecure: *, disableWebSecurity: *}}
- */
-function selectAppArgs(options) {
- return {
- name: options.name,
- targetUrl: options.targetUrl,
- counter: options.counter,
- width: options.width,
- height: options.height,
- minWidth: options.minWidth,
- minHeight: options.minHeight,
- maxWidth: options.maxWidth,
- maxHeight: options.maxHeight,
- showMenuBar: options.showMenuBar,
- fastQuit: options.fastQuit,
- userAgent: options.userAgent,
- nativefierVersion: options.nativefierVersion,
- ignoreCertificate: options.ignoreCertificate,
- insecure: options.insecure,
- flashPluginDir: options.flashPluginDir,
- fullScreen: options.fullScreen,
- hideWindowFrame: options.hideWindowFrame,
- maximize: options.maximize,
- disableContextMenu: options.disableContextMenu,
- disableDevTools: options.disableDevTools,
- zoom: options.zoom,
- internalUrls: options.internalUrls,
- crashReporter: options.crashReporter,
- singleInstance: options.singleInstance
- };
-}
-
-function normalizeAppName(appName, url) {
- // use a simple 3 byte random string to prevent collision
- let hash = crypto.createHash('md5');
- hash.update(url);
- const postFixHash = hash.digest('hex').substring(0, 6);
- const normalized = _.kebabCase(appName.toLowerCase());
- return `${normalized}-nativefier-${postFixHash}`;
-}
export default buildApp;
diff --git a/src/build/buildMain.js b/src/build/buildMain.js
index 429b607..8b3eff8 100644
--- a/src/build/buildMain.js
+++ b/src/build/buildMain.js
@@ -15,118 +15,39 @@ import buildApp from './buildApp';
const copy = ncp.ncp;
const isWindows = helpers.isWindows;
-/**
- * @callback buildAppCallback
- * @param error
- * @param {string} appPath
- */
-
-/**
- *
- * @param {{}} options
- * @param {buildAppCallback} callback
- */
-function buildMain(options, callback) {
- // pre process app
-
- const tmpObj = tmp.dirSync({unsafeCleanup: true});
- const tmpPath = tmpObj.name;
-
- // todo check if this is still needed on later version of packager
- const packagerConsole = new PackagerConsole();
-
- const progress = new DishonestProgress(5);
-
- async.waterfall([
- callback => {
- progress.tick('inferring');
- optionsFactory(options, callback);
- },
- (options, callback) => {
- progress.tick('copying');
- buildApp(options.dir, tmpPath, options, error => {
- if (error) {
- callback(error);
- return;
- }
- // dir now correctly references the app folder to package
- options.dir = tmpPath;
- callback(null, options);
- });
- },
- (options, callback) => {
- progress.tick('icons');
- iconBuild(options, (error, optionsWithIcon) => {
- callback(null, optionsWithIcon);
- });
- },
- (options, callback) => {
- progress.tick('packaging');
- // maybe skip passing icon parameter to electron packager
- const packageOptions = maybeNoIconOption(options);
-
- packagerConsole.override();
-
- packager(packageOptions, (error, appPathArray) => {
-
- // restore console.error
- packagerConsole.restore();
-
- // pass options which still contains the icon to waterfall
- callback(error, options, appPathArray);
- });
- },
- (options, appPathArray, callback) => {
- progress.tick('finalizing');
- // somehow appPathArray is a 1 element array
- const appPath = getAppPath(appPathArray);
- if (!appPath) {
- callback();
- return;
- }
-
- maybeCopyIcons(options, appPath, error => {
- callback(error, appPath);
- });
- }
- ], (error, appPath) => {
- packagerConsole.playback();
- callback(error, appPath);
- });
-}
-
/**
* Checks the app path array to determine if the packaging was completed successfully
* @param appPathArray Result from electron-packager
* @returns {*}
*/
function getAppPath(appPathArray) {
- if (appPathArray.length === 0) {
- // directory already exists, --overwrite is not set
- // exit here
- return null;
- }
+ if (appPathArray.length === 0) {
+ // directory already exists, --overwrite is not set
+ // exit here
+ return null;
+ }
- if (appPathArray.length > 1) {
- log.warn('Warning: This should not be happening, packaged app path contains more than one element:', appPathArray);
- }
+ if (appPathArray.length > 1) {
+ log.warn('Warning: This should not be happening, packaged app path contains more than one element:', appPathArray);
+ }
- return appPathArray[0];
+ return appPathArray[0];
}
/**
- * Removes the `icon` parameter from options if building for Windows while not on Windows and Wine is not installed
+ * Removes the `icon` parameter from options if building for Windows while not on Windows
+ * and Wine is not installed
* @param options
*/
function maybeNoIconOption(options) {
- const packageOptions = JSON.parse(JSON.stringify(options));
- if (options.platform === 'win32' && !isWindows()) {
- if (!hasBinary.sync('wine')) {
- log.warn('Wine is required to set the icon for a Windows app when packaging on non-windows platforms');
- packageOptions.icon = null;
- }
+ const packageOptions = JSON.parse(JSON.stringify(options));
+ if (options.platform === 'win32' && !isWindows()) {
+ if (!hasBinary.sync('wine')) {
+ log.warn('Wine is required to set the icon for a Windows app when packaging on non-windows platforms');
+ packageOptions.icon = null;
}
- return packageOptions;
+ }
+ return packageOptions;
}
/**
@@ -137,23 +58,105 @@ function maybeNoIconOption(options) {
* @param callback
*/
function maybeCopyIcons(options, appPath, callback) {
- if (!options.icon) {
+ if (!options.icon) {
+ callback();
+ return;
+ }
+
+ if (options.platform === 'darwin') {
+ callback();
+ return;
+ }
+
+ // windows & linux
+ // put the icon file into the app
+ const destIconPath = path.join(appPath, 'resources/app');
+ const destFileName = `icon${path.extname(options.icon)}`;
+ copy(options.icon, path.join(destIconPath, destFileName), (error) => {
+ callback(error);
+ });
+}
+
+
+/**
+ * @callback buildAppCallback
+ * @param error
+ * @param {string} appPath
+ */
+
+/**
+ *
+ * @param {{}} inpOptions
+ * @param {buildAppCallback} callback
+ */
+function buildMain(inpOptions, callback) {
+ const options = Object.assign({}, inpOptions);
+
+ // pre process app
+
+ const tmpObj = tmp.dirSync({ unsafeCleanup: true });
+ const tmpPath = tmpObj.name;
+
+ // todo check if this is still needed on later version of packager
+ const packagerConsole = new PackagerConsole();
+
+ const progress = new DishonestProgress(5);
+
+ async.waterfall([
+ (callback) => {
+ progress.tick('inferring');
+ optionsFactory(options, callback);
+ },
+ (options, callback) => {
+ progress.tick('copying');
+ buildApp(options.dir, tmpPath, options, (error) => {
+ if (error) {
+ callback(error);
+ return;
+ }
+ // Change the reference file for the Electron app to be the temporary path
+ const newOptions = Object.assign({}, options, { dir: tmpPath });
+ callback(null, newOptions);
+ });
+ },
+ (options, callback) => {
+ progress.tick('icons');
+ iconBuild(options, (error, optionsWithIcon) => {
+ callback(null, optionsWithIcon);
+ });
+ },
+ (options, callback) => {
+ progress.tick('packaging');
+ // maybe skip passing icon parameter to electron packager
+ const packageOptions = maybeNoIconOption(options);
+
+ packagerConsole.override();
+
+ packager(packageOptions, (error, appPathArray) => {
+ // restore console.error
+ packagerConsole.restore();
+
+ // pass options which still contains the icon to waterfall
+ callback(error, options, appPathArray);
+ });
+ },
+ (options, appPathArray, callback) => {
+ progress.tick('finalizing');
+ // somehow appPathArray is a 1 element array
+ const appPath = getAppPath(appPathArray);
+ if (!appPath) {
callback();
return;
- }
+ }
- if (options.platform === 'darwin') {
- callback();
- return;
- }
-
- // windows & linux
- // put the icon file into the app
- const destIconPath = path.join(appPath, 'resources/app');
- const destFileName = `icon${path.extname(options.icon)}`;
- copy(options.icon, path.join(destIconPath, destFileName), error => {
- callback(error);
- });
+ maybeCopyIcons(options, appPath, (error) => {
+ callback(error, appPath);
+ });
+ },
+ ], (error, appPath) => {
+ packagerConsole.playback();
+ callback(error, appPath);
+ });
}
export default buildMain;
diff --git a/src/build/iconBuild.js b/src/build/iconBuild.js
index cc754df..dcdaa95 100644
--- a/src/build/iconBuild.js
+++ b/src/build/iconBuild.js
@@ -3,8 +3,20 @@ import log from 'loglevel';
import helpers from './../helpers/helpers';
import iconShellHelpers from './../helpers/iconShellHelpers';
-const {isOSX} = helpers;
-const {convertToPng, convertToIco, convertToIcns} = iconShellHelpers;
+const { isOSX } = helpers;
+const { convertToPng, convertToIco, convertToIcns } = iconShellHelpers;
+
+function iconIsIco(iconPath) {
+ return path.extname(iconPath) === '.ico';
+}
+
+function iconIsPng(iconPath) {
+ return path.extname(iconPath) === '.png';
+}
+
+function iconIsIcns(iconPath) {
+ return path.extname(iconPath) === '.icns';
+}
/**
* @callback augmentIconsCallback
@@ -16,88 +28,76 @@ const {convertToPng, convertToIco, convertToIcns} = iconShellHelpers;
* Will check and convert a `.png` to `.icns` if necessary and augment
* options.icon with the result
*
- * @param options will need options.platform and options.icon
+ * @param inpOptions will need options.platform and options.icon
* @param {augmentIconsCallback} callback
*/
-function iconBuild(options, callback) {
+function iconBuild(inpOptions, callback) {
+ const options = Object.assign({}, inpOptions);
+ const returnCallback = () => {
+ callback(null, options);
+ };
- const returnCallback = () => {
- callback(null, options);
- };
+ if (!options.icon) {
+ returnCallback();
+ return;
+ }
- if (!options.icon) {
+ if (options.platform === 'win32') {
+ if (iconIsIco(options.icon)) {
+ returnCallback();
+ return;
+ }
+
+ convertToIco(options.icon)
+ .then((outPath) => {
+ options.icon = outPath;
returnCallback();
- return;
- }
-
- if (options.platform === 'win32') {
- if (iconIsIco(options.icon)) {
- returnCallback();
- return;
- }
-
- convertToIco(options.icon)
- .then(outPath => {
- options.icon = outPath;
- returnCallback();
- })
- .catch(error => {
- log.warn('Skipping icon conversion to .ico', error);
- returnCallback();
- });
- return;
- }
-
- if (options.platform === 'linux') {
- if (iconIsPng(options.icon)) {
- returnCallback();
- return;
- }
-
- convertToPng(options.icon)
- .then(outPath => {
- options.icon = outPath;
- returnCallback();
- })
- .catch(error => {
- log.warn('Skipping icon conversion to .png', error);
- returnCallback();
- });
- return;
- }
-
- if (iconIsIcns(options.icon)) {
+ })
+ .catch((error) => {
+ log.warn('Skipping icon conversion to .ico', error);
returnCallback();
- return;
+ });
+ return;
+ }
+
+ if (options.platform === 'linux') {
+ if (iconIsPng(options.icon)) {
+ returnCallback();
+ return;
}
- if (!isOSX()) {
- log.warn('Skipping icon conversion to .icns, conversion is only supported on OSX');
+ convertToPng(options.icon)
+ .then((outPath) => {
+ options.icon = outPath;
returnCallback();
- return;
- }
+ })
+ .catch((error) => {
+ log.warn('Skipping icon conversion to .png', error);
+ returnCallback();
+ });
+ return;
+ }
- convertToIcns(options.icon)
- .then(outPath => {
- options.icon = outPath;
- returnCallback();
- })
- .catch(error => {
- log.warn('Skipping icon conversion to .icns', error);
- returnCallback();
- });
-}
+ if (iconIsIcns(options.icon)) {
+ returnCallback();
+ return;
+ }
-function iconIsIco(iconPath) {
- return path.extname(iconPath) === '.ico';
-}
+ if (!isOSX()) {
+ log.warn('Skipping icon conversion to .icns, conversion is only supported on OSX');
+ returnCallback();
+ return;
+ }
-function iconIsPng(iconPath) {
- return path.extname(iconPath) === '.png';
-}
-
-function iconIsIcns(iconPath) {
- return path.extname(iconPath) === '.icns';
+ convertToIcns(options.icon)
+ .then((outPath) => {
+ options.icon = outPath;
+ returnCallback();
+ })
+ .catch((error) => {
+ log.warn('Skipping icon conversion to .icns', error);
+ returnCallback();
+ });
}
export default iconBuild;
diff --git a/src/cli.js b/src/cli.js
index c58fdae..3441bd0 100755
--- a/src/cli.js
+++ b/src/cli.js
@@ -1,75 +1,73 @@
#! /usr/bin/env node
import 'source-map-support/register';
-
-import path from 'path';
import program from 'commander';
import nativefier from './index';
-const packageJson = require(path.join('..', 'package'));
+
+const packageJson = require('./../package');
function collect(val, memo) {
- memo.push(val);
- return memo;
+ memo.push(val);
+ return memo;
}
if (require.main === module) {
+ program
+ .version(packageJson.version)
+ .arguments(' [dest]')
+ .action((targetUrl, appDir) => {
+ program.targetUrl = targetUrl;
+ program.out = appDir;
+ })
+ .option('-n, --name ', 'app name')
+ .option('-p, --platform ', '\'osx\', \'linux\' or \'windows\'')
+ .option('-a, --arch ', '\'ia32\' or \'x64\'')
+ .option('-e, --electron-version ', 'electron version to package, without the \'v\', see https://github.com/atom/electron/releases')
+ .option('--no-overwrite', 'do not override output directory if it already exists, defaults to false')
+ .option('-c, --conceal', 'packages the source code within your app into an archive, defaults to false, see http://electron.atom.io/docs/v0.36.0/tutorial/application-packaging/')
+ .option('--counter', 'if the target app should use a persistant counter badge in the dock (OSX only), defaults to false')
+ .option('-i, --icon ', 'the icon file to use as the icon for the app (should be a .icns file on OSX, .png for Windows and Linux)')
+ .option('--width ', 'set window default width, defaults to 1280px', parseInt)
+ .option('--height ', 'set window default height, defaults to 800px', parseInt)
+ .option('--min-width ', 'set window minimum width, defaults to 0px', parseInt)
+ .option('--min-height ', 'set window minimum height, defaults to 0px', parseInt)
+ .option('--max-width ', 'set window maximum width, default is no limit', parseInt)
+ .option('--max-height ', 'set window maximum height, default is no limit', parseInt)
+ .option('-m, --show-menu-bar', 'set menu bar visible, defaults to false')
+ .option('-f, --fast-quit', 'quit app after window close (OSX only), defaults to false')
+ .option('-u, --user-agent ', 'set the user agent string for the app')
+ .option('--honest', 'prevent the nativefied app from changing the user agent string to masquerade as a regular chrome browser')
+ .option('--ignore-certificate', 'ignore certificate related errors')
+ .option('--insecure', 'enable loading of insecure content, defaults to false')
+ .option('--flash', 'if flash should be enabled')
+ .option('--flash-path ', 'path to Chrome flash plugin, find it in `Chrome://plugins`')
+ .option('--inject ', 'path to a CSS/JS file to be injected', collect, [])
+ .option('--full-screen', 'if the app should always be started in full screen')
+ .option('--maximize', 'if the app should always be started maximized')
+ .option('--hide-window-frame', 'disable window frame and controls')
+ .option('--verbose', 'if verbose logs should be displayed')
+ .option('--disable-context-menu', 'disable the context menu')
+ .option('--disable-dev-tools', 'disable developer tools')
+ .option('--zoom ', 'default zoom factor to use when the app is opened, defaults to 1.0', parseFloat)
+ .option('--internal-urls ', 'regular expression of URLs to consider "internal"; all other URLs will be opened in an external browser. (default: URLs on same second-level domain as app)')
+ .option('--crash-reporter ', 'remote server URL to send crash reports')
+ .option('--single-instance', 'allow only a single instance of the application')
+ .parse(process.argv);
- program
- .version(packageJson.version)
- .arguments(' [dest]')
- .action(function(targetUrl, appDir) {
- program.targetUrl = targetUrl;
- program.out = appDir;
- })
- .option('-n, --name ', 'app name')
- .option('-p, --platform ', '\'osx\', \'linux\' or \'windows\'')
- .option('-a, --arch ', '\'ia32\' or \'x64\'')
- .option('-e, --electron-version ', 'electron version to package, without the \'v\', see https://github.com/atom/electron/releases')
- .option('--no-overwrite', 'do not override output directory if it already exists, defaults to false')
- .option('-c, --conceal', 'packages the source code within your app into an archive, defaults to false, see http://electron.atom.io/docs/v0.36.0/tutorial/application-packaging/')
- .option('--counter', 'if the target app should use a persistant counter badge in the dock (OSX only), defaults to false')
- .option('-i, --icon ', 'the icon file to use as the icon for the app (should be a .icns file on OSX, .png for Windows and Linux)')
- .option('--width ', 'set window default width, defaults to 1280px', parseInt)
- .option('--height ', 'set window default height, defaults to 800px', parseInt)
- .option('--min-width ', 'set window minimum width, defaults to 0px', parseInt)
- .option('--min-height ', 'set window minimum height, defaults to 0px', parseInt)
- .option('--max-width ', 'set window maximum width, default is no limit', parseInt)
- .option('--max-height ', 'set window maximum height, default is no limit', parseInt)
- .option('-m, --show-menu-bar', 'set menu bar visible, defaults to false')
- .option('-f, --fast-quit', 'quit app after window close (OSX only), defaults to false')
- .option('-u, --user-agent ', 'set the user agent string for the app')
- .option('--honest', 'prevent the nativefied app from changing the user agent string to masquerade as a regular chrome browser')
- .option('--ignore-certificate', 'ignore certificate related errors')
- .option('--insecure', 'enable loading of insecure content, defaults to false')
- .option('--flash', 'if flash should be enabled')
- .option('--flash-path ', 'path to Chrome flash plugin, find it in `Chrome://plugins`')
- .option('--inject ', 'path to a CSS/JS file to be injected', collect, [])
- .option('--full-screen', 'if the app should always be started in full screen')
- .option('--maximize', 'if the app should always be started maximized')
- .option('--hide-window-frame', 'disable window frame and controls')
- .option('--verbose', 'if verbose logs should be displayed')
- .option('--disable-context-menu', 'disable the context menu')
- .option('--disable-dev-tools', 'disable developer tools')
- .option('--zoom ', 'default zoom factor to use when the app is opened, defaults to 1.0', parseFloat)
- .option('--internal-urls ', 'regular expression of URLs to consider "internal"; all other URLs will be opened in an external browser. (default: URLs on same second-level domain as app)')
- .option('--crash-reporter ', 'remote server URL to send crash reports')
- .option('--single-instance', 'allow only a single instance of the application')
- .parse(process.argv);
+ if (!process.argv.slice(2).length) {
+ program.help();
+ }
- if (!process.argv.slice(2).length) {
- program.help();
+ nativefier(program, (error, appPath) => {
+ if (error) {
+ console.error(error);
+ return;
}
- nativefier(program, (error, appPath) => {
- if (error) {
- console.error(error);
- return;
- }
-
- if (!appPath) {
- // app exists and --overwrite is not passed
- return;
- }
- console.log(`App built to ${appPath}`);
- });
+ if (!appPath) {
+ // app exists and --overwrite is not passed
+ return;
+ }
+ console.log(`App built to ${appPath}`);
+ });
}
diff --git a/src/helpers/convertToIcns.js b/src/helpers/convertToIcns.js
index 09bea58..5c86199 100644
--- a/src/helpers/convertToIcns.js
+++ b/src/helpers/convertToIcns.js
@@ -2,6 +2,7 @@ import shell from 'shelljs';
import path from 'path';
import tmp from 'tmp';
import helpers from './helpers';
+
const isOSX = helpers.isOSX;
tmp.setGracefulCleanup();
@@ -20,27 +21,27 @@ const PNG_TO_ICNS_BIN_PATH = path.join(__dirname, '../..', 'bin/convertToIcns');
* @param {pngToIcnsCallback} callback
*/
function convertToIcns(pngSrc, icnsDest, callback) {
- if (!isOSX()) {
- callback('OSX is required to convert .png to .icns icon', pngSrc);
+ if (!isOSX()) {
+ callback('OSX is required to convert .png to .icns icon', pngSrc);
+ return;
+ }
+
+ shell.exec(`${PNG_TO_ICNS_BIN_PATH} ${pngSrc} ${icnsDest}`, { silent: true }, (exitCode, stdOut, stdError) => {
+ if (stdOut.includes('icon.iconset:error') || exitCode) {
+ if (exitCode) {
+ callback({
+ stdOut,
+ stdError,
+ }, pngSrc);
return;
+ }
+
+ callback(stdOut, pngSrc);
+ return;
}
- shell.exec(`${PNG_TO_ICNS_BIN_PATH} ${pngSrc} ${icnsDest}`, {silent: true}, (exitCode, stdOut, stdError) => {
- if (stdOut.includes('icon.iconset:error') || exitCode) {
- if (exitCode) {
- callback({
- stdOut: stdOut,
- stdError: stdError
- }, pngSrc);
- return;
- }
-
- callback(stdOut, pngSrc);
- return;
- }
-
- callback(null, icnsDest);
- });
+ callback(null, icnsDest);
+ });
}
/**
@@ -49,9 +50,9 @@ function convertToIcns(pngSrc, icnsDest, callback) {
* @param {pngToIcnsCallback} callback
*/
function convertToIcnsTmp(pngSrc, callback) {
- const tempIconDirObj = tmp.dirSync({unsafeCleanup: true});
- const tempIconDirPath = tempIconDirObj.name;
- convertToIcns(pngSrc, `${tempIconDirPath}/icon.icns`, callback);
+ const tempIconDirObj = tmp.dirSync({ unsafeCleanup: true });
+ const tempIconDirPath = tempIconDirObj.name;
+ convertToIcns(pngSrc, `${tempIconDirPath}/icon.icns`, callback);
}
export default convertToIcnsTmp;
diff --git a/src/helpers/dishonestProgress.js b/src/helpers/dishonestProgress.js
index 02e20cf..beac6fe 100644
--- a/src/helpers/dishonestProgress.js
+++ b/src/helpers/dishonestProgress.js
@@ -1,68 +1,70 @@
import ProgressBar from 'progress';
class DishonestProgress {
- constructor(total) {
- this.tickParts = total * 10;
+ constructor(total) {
+ this.tickParts = total * 10;
- this.bar = new ProgressBar(' :task [:bar] :percent', {
- complete: '=',
- incomplete: ' ',
- total: total * this.tickParts,
- width: 50,
- clear: true
- });
+ this.bar = new ProgressBar(' :task [:bar] :percent', {
+ complete: '=',
+ incomplete: ' ',
+ total: total * this.tickParts,
+ width: 50,
+ clear: true,
+ });
- this.tickingPrevious = {
- message: '',
- remainder: 0,
- interval: null
- };
+ this.tickingPrevious = {
+ message: '',
+ remainder: 0,
+ interval: null,
+ };
+ }
+
+ tick(message) {
+ const {
+ remainder: prevRemainder,
+ message: prevMessage,
+ interval: prevInterval,
+ } = this.tickingPrevious;
+
+ if (prevRemainder) {
+ this.bar.tick(prevRemainder, {
+ task: prevMessage,
+ });
+ clearInterval(prevInterval);
}
- tick(message) {
-
- const {remainder: prevRemainder, message: prevMessage, interval: prevInterval} = this.tickingPrevious;
-
- if (prevRemainder) {
- this.bar.tick(prevRemainder, {
- task: prevMessage
- });
- clearInterval(prevInterval);
- }
-
- const realRemainder = this.bar.total - this.bar.curr;
- if (realRemainder === this.tickParts) {
- this.bar.tick(this.tickParts, {
- task: message
- });
- return;
- }
-
- this.bar.tick({
- task: message
- });
-
- this.tickingPrevious = {
- message: message,
- remainder: this.tickParts,
- interval: null
- };
-
- this.tickingPrevious.remainder -= 1;
-
- this.tickingPrevious.interval = setInterval(() => {
- if (this.tickingPrevious.remainder === 1) {
- clearInterval(this.tickingPrevious.interval);
- return;
- }
-
- this.bar.tick({
- task: message
- });
- this.tickingPrevious.remainder -= 1;
- }, 200);
-
+ const realRemainder = this.bar.total - this.bar.curr;
+ if (realRemainder === this.tickParts) {
+ this.bar.tick(this.tickParts, {
+ task: message,
+ });
+ return;
}
+
+ this.bar.tick({
+ task: message,
+ });
+
+ this.tickingPrevious = {
+ message,
+ remainder: this.tickParts,
+ interval: null,
+ };
+
+ this.tickingPrevious.remainder -= 1;
+
+ this.tickingPrevious.interval = setInterval(() => {
+ if (this.tickingPrevious.remainder === 1) {
+ clearInterval(this.tickingPrevious.interval);
+ return;
+ }
+
+ this.bar.tick({
+ task: message,
+ });
+ this.tickingPrevious.remainder -= 1;
+ }, 200);
+ }
}
export default DishonestProgress;
diff --git a/src/helpers/helpers.js b/src/helpers/helpers.js
index f0bc904..1341650 100644
--- a/src/helpers/helpers.js
+++ b/src/helpers/helpers.js
@@ -4,100 +4,100 @@ import hasBinary from 'hasbin';
import path from 'path';
function isOSX() {
- return os.platform() === 'darwin';
+ return os.platform() === 'darwin';
}
function isWindows() {
- return os.platform() === 'win32';
+ return os.platform() === 'win32';
}
function downloadFile(fileUrl) {
- return axios.get(
- fileUrl, {
- responseType: 'arraybuffer'
- })
- .then(function(response) {
- if (!response.data) {
- return null;
- }
- return {
- data: response.data,
- ext: path.extname(fileUrl)
- };
- });
+ return axios.get(
+ fileUrl, {
+ responseType: 'arraybuffer',
+ })
+ .then((response) => {
+ if (!response.data) {
+ return null;
+ }
+ return {
+ data: response.data,
+ ext: path.extname(fileUrl),
+ };
+ });
}
function allowedIconFormats(platform) {
- const hasIdentify = hasBinary.sync('identify');
- const hasConvert = hasBinary.sync('convert');
- const hasIconUtil = hasBinary.sync('iconutil');
+ const hasIdentify = hasBinary.sync('identify');
+ const hasConvert = hasBinary.sync('convert');
+ const hasIconUtil = hasBinary.sync('iconutil');
- const pngToIcns = hasConvert && hasIconUtil;
- const pngToIco = hasConvert;
- const icoToIcns = pngToIcns && hasIdentify;
- const icoToPng = hasConvert;
+ const pngToIcns = hasConvert && hasIconUtil;
+ const pngToIco = hasConvert;
+ const icoToIcns = pngToIcns && hasIdentify;
+ const icoToPng = hasConvert;
- // todo scripts for the following
- const icnsToPng = false;
- const icnsToIco = false;
+ // todo scripts for the following
+ const icnsToPng = false;
+ const icnsToIco = false;
- const formats = [];
-
- // todo shell scripting is not supported on windows, temporary override
- if (isWindows()) {
- switch (platform) {
- case 'darwin':
- formats.push('.icns');
- break;
- case 'linux':
- formats.push('.png');
- break;
- case 'win32':
- formats.push('.ico');
- break;
- default:
- throw `function allowedIconFormats error: Unknown platform ${platform}`;
- }
- return formats;
- }
+ const formats = [];
+ // todo shell scripting is not supported on windows, temporary override
+ if (isWindows()) {
switch (platform) {
- case 'darwin':
- formats.push('.icns');
- if (pngToIcns) {
- formats.push('.png');
- }
- if (icoToIcns) {
- formats.push('.ico');
- }
- break;
- case 'linux':
- formats.push('.png');
- if (icoToPng) {
- formats.push('.ico');
- }
- if (icnsToPng) {
- formats.push('.icns');
- }
- break;
- case 'win32':
- formats.push('.ico');
- if (pngToIco) {
- formats.push('.png');
- }
- if (icnsToIco) {
- formats.push('.icns');
- }
- break;
- default:
- throw `function allowedIconFormats error: Unknown platform ${platform}`;
+ case 'darwin':
+ formats.push('.icns');
+ break;
+ case 'linux':
+ formats.push('.png');
+ break;
+ case 'win32':
+ formats.push('.ico');
+ break;
+ default:
+ throw new Error(`function allowedIconFormats error: Unknown platform ${platform}`);
}
return formats;
+ }
+
+ switch (platform) {
+ case 'darwin':
+ formats.push('.icns');
+ if (pngToIcns) {
+ formats.push('.png');
+ }
+ if (icoToIcns) {
+ formats.push('.ico');
+ }
+ break;
+ case 'linux':
+ formats.push('.png');
+ if (icoToPng) {
+ formats.push('.ico');
+ }
+ if (icnsToPng) {
+ formats.push('.icns');
+ }
+ break;
+ case 'win32':
+ formats.push('.ico');
+ if (pngToIco) {
+ formats.push('.png');
+ }
+ if (icnsToIco) {
+ formats.push('.icns');
+ }
+ break;
+ default:
+ throw new Error(`function allowedIconFormats error: Unknown platform ${platform}`);
+ }
+ return formats;
}
export default {
- isOSX,
- isWindows,
- downloadFile,
- allowedIconFormats
+ isOSX,
+ isWindows,
+ downloadFile,
+ allowedIconFormats,
};
diff --git a/src/helpers/iconShellHelpers.js b/src/helpers/iconShellHelpers.js
index 16ebc37..947edb7 100644
--- a/src/helpers/iconShellHelpers.js
+++ b/src/helpers/iconShellHelpers.js
@@ -2,15 +2,16 @@ import shell from 'shelljs';
import path from 'path';
import tmp from 'tmp';
import helpers from './helpers';
-const {isWindows, isOSX} = helpers;
+
+const { isWindows, isOSX } = helpers;
tmp.setGracefulCleanup();
const SCRIPT_PATHS = {
- singleIco: path.join(__dirname, '../..', 'bin/singleIco'),
- convertToPng: path.join(__dirname, '../..', 'bin/convertToPng'),
- convertToIco: path.join(__dirname, '../..', 'bin/convertToIco'),
- convertToIcns: path.join(__dirname, '../..', 'bin/convertToIcns')
+ singleIco: path.join(__dirname, '../..', 'bin/singleIco'),
+ convertToPng: path.join(__dirname, '../..', 'bin/convertToPng'),
+ convertToIco: path.join(__dirname, '../..', 'bin/convertToIco'),
+ convertToIcns: path.join(__dirname, '../..', 'bin/convertToIcns'),
};
/**
@@ -20,29 +21,29 @@ const SCRIPT_PATHS = {
* @param {string} dest has to be a .ico path
*/
function iconShellHelper(shellScriptPath, icoSrc, dest) {
- return new Promise((resolve, reject) => {
- if (isWindows()) {
- reject('OSX or Linux is required');
- return;
- }
+ return new Promise((resolve, reject) => {
+ if (isWindows()) {
+ reject('OSX or Linux is required');
+ return;
+ }
- shell.exec(`${shellScriptPath} ${icoSrc} ${dest}`, {silent: true}, (exitCode, stdOut, stdError) => {
- if (exitCode) {
- reject({
- stdOut: stdOut,
- stdError: stdError
- });
- return;
- }
-
- resolve(dest);
+ shell.exec(`${shellScriptPath} ${icoSrc} ${dest}`, { silent: true }, (exitCode, stdOut, stdError) => {
+ if (exitCode) {
+ reject({
+ stdOut,
+ stdError,
});
+ return;
+ }
+
+ resolve(dest);
});
+ });
}
function getTmpDirPath() {
- const tempIconDirObj = tmp.dirSync({unsafeCleanup: true});
- return tempIconDirObj.name;
+ const tempIconDirObj = tmp.dirSync({ unsafeCleanup: true });
+ return tempIconDirObj.name;
}
/**
@@ -52,27 +53,27 @@ function getTmpDirPath() {
*/
function singleIco(icoSrc) {
- return iconShellHelper(SCRIPT_PATHS.singleIco, icoSrc, `${getTmpDirPath()}/icon.ico`);
+ return iconShellHelper(SCRIPT_PATHS.singleIco, icoSrc, `${getTmpDirPath()}/icon.ico`);
}
function convertToPng(icoSrc) {
- return iconShellHelper(SCRIPT_PATHS.convertToPng, icoSrc, `${getTmpDirPath()}/icon.png`);
+ return iconShellHelper(SCRIPT_PATHS.convertToPng, icoSrc, `${getTmpDirPath()}/icon.png`);
}
function convertToIco(icoSrc) {
- return iconShellHelper(SCRIPT_PATHS.convertToIco, icoSrc, `${getTmpDirPath()}/icon.ico`);
+ return iconShellHelper(SCRIPT_PATHS.convertToIco, icoSrc, `${getTmpDirPath()}/icon.ico`);
}
function convertToIcns(icoSrc) {
- if (!isOSX()) {
- return new Promise((resolve, reject) => reject('OSX is required to convert to a .icns icon'));
- }
- return iconShellHelper(SCRIPT_PATHS.convertToIcns, icoSrc, `${getTmpDirPath()}/icon.icns`);
+ if (!isOSX()) {
+ return new Promise((resolve, reject) => reject('OSX is required to convert to a .icns icon'));
+ }
+ return iconShellHelper(SCRIPT_PATHS.convertToIcns, icoSrc, `${getTmpDirPath()}/icon.icns`);
}
export default {
- singleIco,
- convertToPng,
- convertToIco,
- convertToIcns
+ singleIco,
+ convertToPng,
+ convertToIco,
+ convertToIcns,
};
diff --git a/src/helpers/packagerConsole.js b/src/helpers/packagerConsole.js
index 59d85b6..a7ea9b6 100644
--- a/src/helpers/packagerConsole.js
+++ b/src/helpers/packagerConsole.js
@@ -1,27 +1,29 @@
+// TODO: remove this file and use quiet mode of new version of electron packager
class PackagerConsole {
- constructor() {
- this.logs = [];
- }
+ constructor() {
+ this.logs = [];
+ }
- _log(...messages) {
- this.logs.push(...messages);
- }
+ _log(...messages) {
+ this.logs.push(...messages);
+ }
- override() {
- this.consoleError = console.error;
+ override() {
+ this.consoleError = console.error;
- // need to bind because somehow when _log() is called this refers to console
- console.error = this._log.bind(this);
- }
+ // need to bind because somehow when _log() is called this refers to console
+ // eslint-disable-next-line no-underscore-dangle
+ console.error = this._log.bind(this);
+ }
- restore() {
- console.error = this.consoleError;
- }
+ restore() {
+ console.error = this.consoleError;
+ }
- playback() {
- console.log(this.logs.join(' '));
- }
+ playback() {
+ console.log(this.logs.join(' '));
+ }
}
export default PackagerConsole;
diff --git a/src/infer/inferIcon.js b/src/infer/inferIcon.js
index dfdf419..a29cf6a 100644
--- a/src/infer/inferIcon.js
+++ b/src/infer/inferIcon.js
@@ -5,117 +5,100 @@ import tmp from 'tmp';
import gitCloud from 'gitcloud';
import helpers from './../helpers/helpers';
-const {downloadFile, allowedIconFormats} = helpers;
+const { downloadFile, allowedIconFormats } = helpers;
tmp.setGracefulCleanup();
const GITCLOUD_SPACE_DELIMITER = '-';
-function inferIconFromStore(targetUrl, platform) {
- const allowedFormats = allowedIconFormats(platform);
-
- return gitCloud('http://jiahaog.com/nativefier-icons/')
- .then(fileIndex => {
- const iconWithScores = mapIconWithMatchScore(fileIndex, targetUrl);
- const maxScore = getMaxMatchScore(iconWithScores);
-
- if (maxScore === 0) {
- return null;
- }
-
- const matchingIcons = getMatchingIcons(iconWithScores, maxScore);
-
- let matchingUrl;
- for (let format of allowedFormats) {
- for (let icon of matchingIcons) {
- if (icon.ext !== format) {
- continue;
- }
- matchingUrl = icon.url;
- }
- }
-
- if (!matchingUrl) {
- return null;
- }
- return downloadFile(matchingUrl);
- });
-}
-
-function mapIconWithMatchScore(fileIndex, targetUrl) {
- const normalisedTargetUrl = targetUrl.toLowerCase();
- return fileIndex
- .map(item => {
- const itemWords = item.name.split(GITCLOUD_SPACE_DELIMITER);
- const score = itemWords.reduce((currentScore, word) => {
- if (normalisedTargetUrl.includes(word)) {
- return currentScore + 1;
- }
- return currentScore;
- }, 0);
-
- return Object.assign({},
- item,
- {score}
- );
- });
-}
-
function getMaxMatchScore(iconWithScores) {
- return iconWithScores.reduce((maxScore, currentIcon) => {
- const currentScore = currentIcon.score;
- if (currentScore > maxScore) {
- return currentScore;
- }
- return maxScore;
- }, 0);
+ return iconWithScores.reduce((maxScore, currentIcon) => {
+ const currentScore = currentIcon.score;
+ if (currentScore > maxScore) {
+ return currentScore;
+ }
+ return maxScore;
+ }, 0);
}
/**
* also maps ext to icon object
*/
-function getMatchingIcons(iconWithScores, maxScore) {
- return iconWithScores
- .filter(item => {
- return item.score === maxScore;
- })
- .map(item => {
- return Object.assign(
- {},
- item,
- {ext: path.extname(item.url)}
- );
- });
+function getMatchingIcons(iconsWithScores, maxScore) {
+ return iconsWithScores
+ .filter(item => item.score === maxScore)
+ .map(item => Object.assign({}, item, { ext: path.extname(item.url) }));
}
-function writeFilePromise(outPath, data) {
- return new Promise((resolve, reject) => {
- fs.writeFile(outPath, data, error => {
- if (error) {
- reject(error);
- return;
- }
- resolve(outPath);
- });
+function mapIconWithMatchScore(fileIndex, targetUrl) {
+ const normalisedTargetUrl = targetUrl.toLowerCase();
+ return fileIndex
+ .map((item) => {
+ const itemWords = item.name.split(GITCLOUD_SPACE_DELIMITER);
+ const score = itemWords.reduce((currentScore, word) => {
+ if (normalisedTargetUrl.includes(word)) {
+ return currentScore + 1;
+ }
+ return currentScore;
+ }, 0);
+
+ return Object.assign({}, item, { score });
});
}
-function inferFromPage(targetUrl, platform, outDir) {
- let preferredExt = '.png';
- if (platform === 'win32') {
- preferredExt = '.ico';
- }
+function inferIconFromStore(targetUrl, platform) {
+ const allowedFormats = new Set(allowedIconFormats(platform));
- // todo might want to pass list of preferences instead
- return pageIcon(targetUrl, {ext: preferredExt})
- .then(icon => {
- if (!icon) {
- return null;
- }
+ return gitCloud('http://jiahaog.com/nativefier-icons/')
+ .then((fileIndex) => {
+ const iconWithScores = mapIconWithMatchScore(fileIndex, targetUrl);
+ const maxScore = getMaxMatchScore(iconWithScores);
- const outfilePath = path.join(outDir, `/icon${icon.ext}`);
- return writeFilePromise(outfilePath, icon.data);
- });
+ if (maxScore === 0) {
+ return null;
+ }
+
+ const iconsMatchingScore = getMatchingIcons(iconWithScores, maxScore);
+ const iconsMatchingExt = iconsMatchingScore.filter(icon => allowedFormats.has(icon.ext));
+ const matchingIcon = iconsMatchingExt[0];
+ const iconUrl = matchingIcon && matchingIcon.url;
+
+ if (!iconUrl) {
+ return null;
+ }
+ return downloadFile(iconUrl);
+ });
}
+
+function writeFilePromise(outPath, data) {
+ return new Promise((resolve, reject) => {
+ fs.writeFile(outPath, data, (error) => {
+ if (error) {
+ reject(error);
+ return;
+ }
+ resolve(outPath);
+ });
+ });
+}
+
+function inferFromPage(targetUrl, platform, outDir) {
+ let preferredExt = '.png';
+ if (platform === 'win32') {
+ preferredExt = '.ico';
+ }
+
+ // todo might want to pass list of preferences instead
+ return pageIcon(targetUrl, { ext: preferredExt })
+ .then((icon) => {
+ if (!icon) {
+ return null;
+ }
+
+ const outfilePath = path.join(outDir, `/icon${icon.ext}`);
+ return writeFilePromise(outfilePath, icon.data);
+ });
+}
+
/**
*
* @param {string} targetUrl
@@ -123,16 +106,15 @@ function inferFromPage(targetUrl, platform, outDir) {
* @param {string} outDir
*/
function inferIconFromUrlToPath(targetUrl, platform, outDir) {
+ return inferIconFromStore(targetUrl, platform)
+ .then((icon) => {
+ if (!icon) {
+ return inferFromPage(targetUrl, platform, outDir);
+ }
- return inferIconFromStore(targetUrl, platform)
- .then(icon => {
- if (!icon) {
- return inferFromPage(targetUrl, platform, outDir);
- }
-
- const outfilePath = path.join(outDir, `/icon${icon.ext}`);
- return writeFilePromise(outfilePath, icon.data);
- });
+ const outfilePath = path.join(outDir, `/icon${icon.ext}`);
+ return writeFilePromise(outfilePath, icon.data);
+ });
}
/**
@@ -140,9 +122,9 @@ function inferIconFromUrlToPath(targetUrl, platform, outDir) {
* @param {string} platform
*/
function inferIcon(targetUrl, platform) {
- const tmpObj = tmp.dirSync({unsafeCleanup: true});
- const tmpPath = tmpObj.name;
- return inferIconFromUrlToPath(targetUrl, platform, tmpPath);
+ const tmpObj = tmp.dirSync({ unsafeCleanup: true });
+ const tmpPath = tmpObj.name;
+ return inferIconFromUrlToPath(targetUrl, platform, tmpPath);
}
export default inferIcon;
diff --git a/src/infer/inferOs.js b/src/infer/inferOs.js
index 2f091c9..f0c1a31 100644
--- a/src/infer/inferOs.js
+++ b/src/infer/inferOs.js
@@ -1,23 +1,23 @@
import os from 'os';
function inferPlatform() {
- const platform = os.platform();
- if (platform === 'darwin' || platform === 'win32' || platform === 'linux') {
- return platform;
- }
+ const platform = os.platform();
+ if (platform === 'darwin' || platform === 'win32' || platform === 'linux') {
+ return platform;
+ }
- throw `Untested platform ${platform} detected`;
+ throw new Error(`Untested platform ${platform} detected`);
}
function inferArch() {
- const arch = os.arch();
- if (arch !== 'ia32' && arch !== 'x64') {
- throw `Incompatible architecture ${arch} detected`;
- }
- return arch;
+ const arch = os.arch();
+ if (arch !== 'ia32' && arch !== 'x64') {
+ throw new Error(`Incompatible architecture ${arch} detected`);
+ }
+ return arch;
}
export default {
- inferPlatform: inferPlatform,
- inferArch: inferArch
+ inferPlatform,
+ inferArch,
};
diff --git a/src/infer/inferTitle.js b/src/infer/inferTitle.js
index a23056a..d20a397 100644
--- a/src/infer/inferTitle.js
+++ b/src/infer/inferTitle.js
@@ -4,19 +4,19 @@ import cheerio from 'cheerio';
const USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36';
function inferTitle(url) {
- const options = {
- method: 'get',
- url,
- headers: {
- // fake a user agent because pages like http://messenger.com will throw 404 error
- 'User-Agent': USER_AGENT
- }
- };
+ const options = {
+ method: 'get',
+ url,
+ headers: {
+ // fake a user agent because pages like http://messenger.com will throw 404 error
+ 'User-Agent': USER_AGENT,
+ },
+ };
- return axios(options).then(({data}) => {
- const $ = cheerio.load(data);
- return $('title').first().text().replace(/\//g, '');
- });
+ return axios(options).then(({ data }) => {
+ const $ = cheerio.load(data);
+ return $('title').first().text().replace(/\//g, '');
+ });
}
export default inferTitle;
diff --git a/src/infer/inferUserAgent.js b/src/infer/inferUserAgent.js
index e10bd0e..7f9258e 100644
--- a/src/infer/inferUserAgent.js
+++ b/src/infer/inferUserAgent.js
@@ -6,50 +6,49 @@ const ELECTRON_VERSIONS_URL = 'https://atom.io/download/atom-shell/index.json';
const DEFAULT_CHROME_VERSION = '56.0.2924.87';
function getChromeVersionForElectronVersion(electronVersion, url = ELECTRON_VERSIONS_URL) {
- return axios.get(url, {timeout: 5000})
- .then(response => {
- if (response.status !== 200) {
- throw `Bad request: Status code ${response.status}`;
- }
+ return axios.get(url, { timeout: 5000 })
+ .then((response) => {
+ if (response.status !== 200) {
+ throw new Error(`Bad request: Status code ${response.status}`);
+ }
- const data = response.data;
- const electronVersionToChromeVersion = _.zipObject(data.map(d => d.version), data.map(d => d.chrome));
+ const data = response.data;
+ const electronVersionToChromeVersion = _.zipObject(data.map(d => d.version),
+ data.map(d => d.chrome));
- if (!(electronVersion in electronVersionToChromeVersion)) {
- throw `Electron version '${electronVersion}' not found in retrieved version list!`;
- }
+ if (!(electronVersion in electronVersionToChromeVersion)) {
+ throw new Error(`Electron version '${electronVersion}' not found in retrieved version list!`);
+ }
- return electronVersionToChromeVersion[electronVersion];
- });
+ return electronVersionToChromeVersion[electronVersion];
+ });
}
export function getUserAgentString(chromeVersion, platform) {
- let userAgent;
- switch (platform) {
- case 'darwin':
- userAgent = `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
- break;
- case 'win32':
- userAgent = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
- break;
- case 'linux':
- userAgent = `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
- break;
- default:
- throw 'Error invalid platform specified to getUserAgentString()';
- }
- return userAgent;
+ let userAgent;
+ switch (platform) {
+ case 'darwin':
+ userAgent = `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
+ break;
+ case 'win32':
+ userAgent = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
+ break;
+ case 'linux':
+ userAgent = `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
+ break;
+ default:
+ throw new Error('Error invalid platform specified to getUserAgentString()');
+ }
+ return userAgent;
}
function inferUserAgent(electronVersion, platform, url = ELECTRON_VERSIONS_URL) {
- return getChromeVersionForElectronVersion(electronVersion, url)
- .then(chromeVersion => {
- return getUserAgentString(chromeVersion, platform);
- })
- .catch(() => {
- log.warn(`Unable to infer chrome version for user agent, using ${DEFAULT_CHROME_VERSION}`);
- return getUserAgentString(DEFAULT_CHROME_VERSION, platform);
- });
+ return getChromeVersionForElectronVersion(electronVersion, url)
+ .then(chromeVersion => getUserAgentString(chromeVersion, platform))
+ .catch(() => {
+ log.warn(`Unable to infer chrome version for user agent, using ${DEFAULT_CHROME_VERSION}`);
+ return getUserAgentString(DEFAULT_CHROME_VERSION, platform);
+ });
}
export default inferUserAgent;
diff --git a/src/options/normalizeUrl.js b/src/options/normalizeUrl.js
index 0fe1263..d4d487c 100644
--- a/src/options/normalizeUrl.js
+++ b/src/options/normalizeUrl.js
@@ -2,25 +2,25 @@ import url from 'url';
import validator from 'validator';
function appendProtocol(testUrl) {
- const parsed = url.parse(testUrl);
- if (!parsed.protocol) {
- return `http://${testUrl}`;
- }
- return testUrl;
+ const parsed = url.parse(testUrl);
+ if (!parsed.protocol) {
+ return `http://${testUrl}`;
+ }
+ return testUrl;
}
function normalizeUrl(testUrl) {
- const urlWithProtocol = appendProtocol(testUrl);
+ const urlWithProtocol = appendProtocol(testUrl);
- const validatorOptions = {
- require_protocol: true,
- require_tld: false,
- allow_trailing_dot: true // mDNS addresses, https://github.com/jiahaog/nativefier/issues/308
- };
- if (!validator.isURL(urlWithProtocol, validatorOptions)) {
- throw `Your Url: "${urlWithProtocol}" is invalid!`;
- }
- return urlWithProtocol;
+ const validatorOptions = {
+ require_protocol: true,
+ require_tld: false,
+ allow_trailing_dot: true, // mDNS addresses, https://github.com/jiahaog/nativefier/issues/308
+ };
+ if (!validator.isURL(urlWithProtocol, validatorOptions)) {
+ throw new Error(`Your Url: "${urlWithProtocol}" is invalid!`);
+ }
+ return urlWithProtocol;
}
export default normalizeUrl;
diff --git a/src/options/optionsMain.js b/src/options/optionsMain.js
index 4d16793..eabb7f5 100644
--- a/src/options/optionsMain.js
+++ b/src/options/optionsMain.js
@@ -11,13 +11,31 @@ import inferUserAgent from './../infer/inferUserAgent';
import normalizeUrl from './normalizeUrl';
import packageJson from './../../package.json';
-const {inferPlatform, inferArch} = inferOs;
+const { inferPlatform, inferArch } = inferOs;
const PLACEHOLDER_APP_DIR = path.join(__dirname, '../../', 'app');
const ELECTRON_VERSION = '1.6.6';
-
const DEFAULT_APP_NAME = 'APP';
+function sanitizeFilename(platform, str) {
+ let result = sanitizeFilenameLib(str);
+
+ // remove all non ascii or use default app name
+ // eslint-disable-next-line no-control-regex
+ result = result.replace(/[^\x00-\x7F]/g, '') || DEFAULT_APP_NAME;
+
+ // spaces will cause problems with Ubuntu when pinned to the dock
+ if (platform === 'linux') {
+ return _.kebabCase(result);
+ }
+ return result;
+}
+
+function sanitizeOptions(options) {
+ const name = sanitizeFilename(options.platform, options.name);
+ return Object.assign({}, options, { name });
+}
+
/**
* @callback optionsCallback
* @param error
@@ -30,143 +48,128 @@ const DEFAULT_APP_NAME = 'APP';
* @param {optionsCallback} callback
*/
function optionsFactory(inpOptions, callback) {
-
- const options = {
- dir: PLACEHOLDER_APP_DIR,
- name: inpOptions.name,
- targetUrl: normalizeUrl(inpOptions.targetUrl),
- platform: inpOptions.platform || inferPlatform(),
- arch: inpOptions.arch || inferArch(),
- electronVersion: inpOptions.electronVersion || ELECTRON_VERSION,
- nativefierVersion: packageJson.version,
- out: inpOptions.out || process.cwd(),
- overwrite: inpOptions.overwrite,
- asar: inpOptions.conceal || false,
- icon: inpOptions.icon,
- counter: inpOptions.counter || false,
- width: inpOptions.width || 1280,
- height: inpOptions.height || 800,
- minWidth: inpOptions.minWidth,
- minHeight: inpOptions.minHeight,
- maxWidth: inpOptions.maxWidth,
- maxHeight: inpOptions.maxHeight,
- showMenuBar: inpOptions.showMenuBar || false,
- fastQuit: inpOptions.fastQuit || false,
- userAgent: inpOptions.userAgent,
- ignoreCertificate: inpOptions.ignoreCertificate || false,
- insecure: inpOptions.insecure || false,
- flashPluginDir: inpOptions.flashPath || inpOptions.flash || null,
- inject: inpOptions.inject || null,
- ignore: 'src',
- fullScreen: inpOptions.fullScreen || false,
- maximize: inpOptions.maximize || false,
- hideWindowFrame: inpOptions.hideWindowFrame,
- verbose: inpOptions.verbose,
- disableContextMenu: inpOptions.disableContextMenu,
- disableDevTools: inpOptions.disableDevTools,
- crashReporter: inpOptions.crashReporter,
+ const options = {
+ dir: PLACEHOLDER_APP_DIR,
+ name: inpOptions.name,
+ targetUrl: normalizeUrl(inpOptions.targetUrl),
+ platform: inpOptions.platform || inferPlatform(),
+ arch: inpOptions.arch || inferArch(),
+ electronVersion: inpOptions.electronVersion || ELECTRON_VERSION,
+ nativefierVersion: packageJson.version,
+ out: inpOptions.out || process.cwd(),
+ overwrite: inpOptions.overwrite,
+ asar: inpOptions.conceal || false,
+ icon: inpOptions.icon,
+ counter: inpOptions.counter || false,
+ width: inpOptions.width || 1280,
+ height: inpOptions.height || 800,
+ minWidth: inpOptions.minWidth,
+ minHeight: inpOptions.minHeight,
+ maxWidth: inpOptions.maxWidth,
+ maxHeight: inpOptions.maxHeight,
+ showMenuBar: inpOptions.showMenuBar || false,
+ fastQuit: inpOptions.fastQuit || false,
+ userAgent: inpOptions.userAgent,
+ ignoreCertificate: inpOptions.ignoreCertificate || false,
+ insecure: inpOptions.insecure || false,
+ flashPluginDir: inpOptions.flashPath || inpOptions.flash || null,
+ inject: inpOptions.inject || null,
+ ignore: 'src',
+ fullScreen: inpOptions.fullScreen || false,
+ maximize: inpOptions.maximize || false,
+ hideWindowFrame: inpOptions.hideWindowFrame,
+ verbose: inpOptions.verbose,
+ disableContextMenu: inpOptions.disableContextMenu,
+ disableDevTools: inpOptions.disableDevTools,
+ crashReporter: inpOptions.crashReporter,
// workaround for electron-packager#375
- tmpdir: false,
- zoom: inpOptions.zoom || 1.0,
- internalUrls: inpOptions.internalUrls || null,
- singleInstance: inpOptions.singleInstance || false
- };
+ tmpdir: false,
+ zoom: inpOptions.zoom || 1.0,
+ internalUrls: inpOptions.internalUrls || null,
+ singleInstance: inpOptions.singleInstance || false,
+ };
- if (options.verbose) {
- log.setLevel('trace');
- } else {
- log.setLevel('error');
+ if (options.verbose) {
+ log.setLevel('trace');
+ } else {
+ log.setLevel('error');
+ }
+
+ if (options.flashPluginDir) {
+ options.insecure = true;
+ }
+
+ if (inpOptions.honest) {
+ options.userAgent = null;
+ }
+
+ if (options.platform.toLowerCase() === 'windows') {
+ options.platform = 'win32';
+ }
+
+ if (options.platform.toLowerCase() === 'osx' || options.platform.toLowerCase() === 'mac') {
+ options.platform = 'darwin';
+ }
+
+ if (options.width > options.maxWidth) {
+ options.width = options.maxWidth;
+ }
+
+ if (options.height > options.maxHeight) {
+ options.height = options.maxHeight;
+ }
+
+ async.waterfall([
+ (callback) => {
+ if (options.userAgent) {
+ callback();
+ return;
+ }
+ inferUserAgent(options.electronVersion, options.platform)
+ .then((userAgent) => {
+ options.userAgent = userAgent;
+ callback();
+ })
+ .catch(callback);
+ },
+ (callback) => {
+ if (options.icon) {
+ callback();
+ return;
+ }
+ inferIcon(options.targetUrl, options.platform)
+ .then((pngPath) => {
+ options.icon = pngPath;
+ callback();
+ })
+ .catch((error) => {
+ log.warn('Cannot automatically retrieve the app icon:', error);
+ callback();
+ });
+ },
+ (callback) => {
+ // length also checks if its the commanderJS function or a string
+ if (options.name && options.name.length > 0) {
+ callback();
+ return;
+ }
+ options.name = DEFAULT_APP_NAME;
+
+ inferTitle(options.targetUrl).then((pageTitle) => {
+ options.name = pageTitle;
+ }).catch((error) => {
+ log.warn(`Unable to automatically determine app name, falling back to '${DEFAULT_APP_NAME}'. Reason: ${error}`);
+ }).then(() => {
+ callback();
+ });
+ },
+ ], (error) => {
+ if (error) {
+ callback(error);
+ return;
}
-
- if (options.flashPluginDir) {
- options.insecure = true;
- }
-
- if (inpOptions.honest) {
- options.userAgent = null;
- }
-
- if (options.platform.toLowerCase() === 'windows') {
- options.platform = 'win32';
- }
-
- if (options.platform.toLowerCase() === 'osx' || options.platform.toLowerCase() === 'mac') {
- options.platform = 'darwin';
- }
-
- if (options.width > options.maxWidth) {
- options.width = options.maxWidth;
- }
-
- if (options.height > options.maxHeight) {
- options.height = options.maxHeight;
- }
-
- async.waterfall([
- callback => {
- if (options.userAgent) {
- callback();
- return;
- }
- inferUserAgent(options.electronVersion, options.platform)
- .then(userAgent => {
- options.userAgent = userAgent;
- callback();
- })
- .catch(callback);
- },
- callback => {
- if (options.icon) {
- callback();
- return;
- }
- inferIcon(options.targetUrl, options.platform)
- .then(pngPath => {
- options.icon = pngPath;
- callback();
- })
- .catch(error => {
- log.warn('Cannot automatically retrieve the app icon:', error);
- callback();
- });
- },
- callback => {
- // length also checks if its the commanderJS function or a string
- if (options.name && options.name.length > 0) {
- callback();
- return;
- }
- options.name = DEFAULT_APP_NAME;
-
- inferTitle(options.targetUrl).then(pageTitle => {
- options.name = pageTitle;
- }).catch(error => {
- log.warn(`Unable to automatically determine app name, falling back to '${DEFAULT_APP_NAME}'. Reason: ${error}`);
- }).then(() => {
- callback();
- });
- }
- ], error => {
- callback(error, sanitizeOptions(options));
- });
-}
-
-function sanitizeFilename(platform, str) {
- let result = sanitizeFilenameLib(str);
-
- // remove all non ascii or use default app name
- result = result.replace(/[^\x00-\x7F]/g, '') || DEFAULT_APP_NAME;
-
- // spaces will cause problems with Ubuntu when pinned to the dock
- if (platform === 'linux') {
- return _.kebabCase(result);
- }
- return result;
-}
-
-function sanitizeOptions(options) {
- options.name = sanitizeFilename(options.platform, options.name);
- return options;
+ callback(null, sanitizeOptions(options));
+ });
}
export default optionsFactory;
diff --git a/test/module/.eslintrc.yml b/test/module/.eslintrc.yml
new file mode 100644
index 0000000..9808c3b
--- /dev/null
+++ b/test/module/.eslintrc.yml
@@ -0,0 +1,2 @@
+env:
+ mocha: true
diff --git a/test/module/getIconSpec.js b/test/module/getIconSpec.js
index e773d07..af487aa 100644
--- a/test/module/getIconSpec.js
+++ b/test/module/getIconSpec.js
@@ -7,36 +7,36 @@ import os from 'os';
import path from 'path';
import convertToIcns from './../../lib/helpers/convertToIcns';
-let assert = chai.assert;
+const assert = chai.assert;
// Prerequisite for test: to use OSX with sips, iconutil and imagemagick convert
function testConvertPng(pngName, done) {
- convertToIcns(path.join(__dirname, '../../', 'test-resources', pngName), (error, icnsPath) => {
- if (error) {
- done(error);
- return;
- }
+ convertToIcns(path.join(__dirname, '../../', 'test-resources', pngName), (error, icnsPath) => {
+ if (error) {
+ done(error);
+ return;
+ }
- let stat = fs.statSync(icnsPath);
- assert.isTrue(stat.isFile(), 'Output icns file should be a path');
- done();
- });
+ const stat = fs.statSync(icnsPath);
+ assert.isTrue(stat.isFile(), 'Output icns file should be a path');
+ done();
+ });
}
-describe('Get Icon Module', function() {
- it('Can convert icons', function() {
- if (os.platform() !== 'darwin') {
- console.warn('Skipping png conversion tests, OSX is required');
- return;
- }
+describe('Get Icon Module', () => {
+ it('Can convert icons', () => {
+ if (os.platform() !== 'darwin') {
+ console.warn('Skipping png conversion tests, OSX is required');
+ return;
+ }
- it('Can convert a rgb png to icns', function(done) {
- testConvertPng('iconSample.png', done);
- });
-
- it('Can convert a grey png to icns', function(done) {
- testConvertPng('iconSampleGrey.png', done);
- });
+ it('Can convert a rgb png to icns', (done) => {
+ testConvertPng('iconSample.png', done);
});
+
+ it('Can convert a grey png to icns', (done) => {
+ testConvertPng('iconSampleGrey.png', done);
+ });
+ });
});
diff --git a/test/module/indexSpec.js b/test/module/indexSpec.js
index ab73df0..29e82e6 100644
--- a/test/module/indexSpec.js
+++ b/test/module/indexSpec.js
@@ -11,65 +11,65 @@ tmp.setGracefulCleanup();
const assert = chai.assert;
function checkApp(appPath, inputOptions, callback) {
- try {
- let relPathToConfig;
+ try {
+ let relPathToConfig;
- switch (inputOptions.platform) {
- case 'darwin':
- relPathToConfig = path.join('google-test-app.app', 'Contents/Resources/app');
- break;
- case 'linux':
- relPathToConfig = 'resources/app';
- break;
- case 'win32':
- relPathToConfig = 'resources/app';
- break;
- default:
- throw 'Unknown app platform';
- }
-
- const nativefierConfigPath = path.join(appPath, relPathToConfig, 'nativefier.json');
- const nativefierConfig = JSON.parse(fs.readFileSync(nativefierConfigPath));
-
- assert.strictEqual(inputOptions.targetUrl, nativefierConfig.targetUrl, 'Packaged app must have the same targetUrl as the input parameters');
- // app name is not consistent for linux
- // assert.strictEqual(inputOptions.appName, nativefierConfig.name, 'Packaged app must have the same name as the input parameters');
- callback();
- } catch (exception) {
- callback(exception);
+ switch (inputOptions.platform) {
+ case 'darwin':
+ relPathToConfig = path.join('google-test-app.app', 'Contents/Resources/app');
+ break;
+ case 'linux':
+ relPathToConfig = 'resources/app';
+ break;
+ case 'win32':
+ relPathToConfig = 'resources/app';
+ break;
+ default:
+ throw new Error('Unknown app platform');
}
+
+ const nativefierConfigPath = path.join(appPath, relPathToConfig, 'nativefier.json');
+ const nativefierConfig = JSON.parse(fs.readFileSync(nativefierConfigPath));
+
+ assert.strictEqual(inputOptions.targetUrl, nativefierConfig.targetUrl, 'Packaged app must have the same targetUrl as the input parameters');
+ // app name is not consistent for linux
+ // assert.strictEqual(inputOptions.appName, nativefierConfig.name,
+ // 'Packaged app must have the same name as the input parameters');
+ callback();
+ } catch (exception) {
+ callback(exception);
+ }
}
-describe('Nativefier Module', function() {
- this.timeout(240000);
- it('Can build an app from a target url', function(done) {
- async.eachSeries(PLATFORMS, (platform, callback) => {
+describe('Nativefier Module', function () {
+ this.timeout(240000);
+ it('Can build an app from a target url', (done) => {
+ async.eachSeries(PLATFORMS, (platform, callback) => {
+ const tmpObj = tmp.dirSync({ unsafeCleanup: true });
- const tmpObj = tmp.dirSync({unsafeCleanup: true});
+ const tmpPath = tmpObj.name;
+ const options = {
+ name: 'google-test-app',
+ targetUrl: 'http://google.com',
+ out: tmpPath,
+ overwrite: true,
+ platform: null,
+ };
- const tmpPath = tmpObj.name;
- const options = {
- name: 'google-test-app',
- targetUrl: 'http://google.com',
- out: tmpPath,
- overwrite: true,
- platform: null
- };
+ options.platform = platform;
+ nativefier(options, (error, appPath) => {
+ if (error) {
+ callback(error);
+ return;
+ }
- options.platform = platform;
- nativefier(options, (error, appPath) => {
- if (error) {
- callback(error);
- return;
- }
-
- checkApp(appPath, options, error => {
- callback(error);
- });
- });
- }, error => {
- done(error);
+ checkApp(appPath, options, (error) => {
+ callback(error);
});
+ });
+ }, (error) => {
+ done(error);
});
+ });
});
diff --git a/test/module/inferUserAgentSpec.js b/test/module/inferUserAgentSpec.js
index 71e16ec..db8acc3 100644
--- a/test/module/inferUserAgentSpec.js
+++ b/test/module/inferUserAgentSpec.js
@@ -1,49 +1,47 @@
-import inferUserAgent from './../../lib/infer/inferUserAgent';
import chai from 'chai';
import _ from 'lodash';
+import inferUserAgent from './../../lib/infer/inferUserAgent';
const assert = chai.assert;
const TEST_RESULT = {
- darwin: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36',
- win32: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36',
- linux: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36'
+ darwin: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36',
+ win32: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36',
+ linux: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36',
};
function testPlatform(platform) {
- return inferUserAgent('0.37.1', platform)
- .then(userAgent => {
- assert.equal(userAgent, TEST_RESULT[platform], 'Correct user agent should be inferred');
+ return inferUserAgent('0.37.1', platform)
+ .then((userAgent) => {
+ assert.equal(userAgent, TEST_RESULT[platform], 'Correct user agent should be inferred');
});
}
-describe('Infer User Agent', function() {
- this.timeout(15000);
- it('Can infer userAgent for all platforms', function(done) {
- const testPromises = _.keys(TEST_RESULT).map(platform => {
- return testPlatform(platform);
- });
- Promise
+describe('Infer User Agent', function () {
+ this.timeout(15000);
+ it('Can infer userAgent for all platforms', (done) => {
+ const testPromises = _.keys(TEST_RESULT).map(platform => testPlatform(platform));
+ Promise
.all(testPromises)
.then(() => {
- done();
+ done();
})
- .catch(error => {
- done(error);
+ .catch((error) => {
+ done(error);
});
- });
+ });
- it('Connection error will still get a user agent', function(done) {
- const TIMEOUT_URL = 'http://www.google.com:81/';
- inferUserAgent('1.6.7', 'darwin', TIMEOUT_URL)
- .then(userAgent => {
- assert.equal(
+ it('Connection error will still get a user agent', (done) => {
+ const TIMEOUT_URL = 'http://www.google.com:81/';
+ inferUserAgent('1.6.7', 'darwin', TIMEOUT_URL)
+ .then((userAgent) => {
+ assert.equal(
userAgent,
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
- 'Expect default user agent on connection error'
+ 'Expect default user agent on connection error',
);
- done();
+ done();
})
.catch(done);
- });
+ });
});
diff --git a/test/module/options/normalizeUrlSpec.js b/test/module/options/normalizeUrlSpec.js
index 6734529..3b64b2c 100644
--- a/test/module/options/normalizeUrlSpec.js
+++ b/test/module/options/normalizeUrlSpec.js
@@ -1,25 +1,25 @@
-import normalizeUrl from '../../../src/options/normalizeUrl';
import chai from 'chai';
+import normalizeUrl from '../../../src/options/normalizeUrl';
+
const assert = chai.assert;
const expect = chai.expect;
describe('Normalize URL', () => {
-
- describe('given a valid URL without a protocol', () => {
- it('should allow the url', () => {
- assert.equal(normalizeUrl('http://www.google.com'), 'http://www.google.com');
- });
+ describe('given a valid URL without a protocol', () => {
+ it('should allow the url', () => {
+ assert.equal(normalizeUrl('http://www.google.com'), 'http://www.google.com');
});
+ });
- describe('given a valid URL without a protocol', () => {
- it('should allow the url and prepend the HTTP protocol', () => {
- assert.equal(normalizeUrl('www.google.com'), 'http://www.google.com');
- });
+ describe('given a valid URL without a protocol', () => {
+ it('should allow the url and prepend the HTTP protocol', () => {
+ assert.equal(normalizeUrl('www.google.com'), 'http://www.google.com');
});
+ });
- describe('given an invalid URL', () => {
- it('should throw an exception', () => {
- expect(() => normalizeUrl('http://ssddfoo bar')).to.throw('Your Url: "http://ssddfoo bar" is invalid!');
- });
+ describe('given an invalid URL', () => {
+ it('should throw an exception', () => {
+ expect(() => normalizeUrl('http://ssddfoo bar')).to.throw('Your Url: "http://ssddfoo bar" is invalid!');
});
+ });
});
diff --git a/webpack.config.js b/webpack.config.js
index c1aac0a..14f7c1a 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,24 +1,24 @@
-var electronPublicApi = ['electron'];
+const electronPublicApi = ['electron'];
-var nodeModules = {};
-electronPublicApi.forEach(apiString => {
- nodeModules[apiString] = 'commonjs ' + apiString;
+const nodeModules = {};
+electronPublicApi.forEach((apiString) => {
+ nodeModules[apiString] = `commonjs ${apiString}`;
});
module.exports = {
- target: 'node',
- output: {
- filename: 'main.js'
- },
- node: {
- global: false,
- __dirname: false
- },
- externals: nodeModules,
- module: {
- loaders: [
- {test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'}
- ]
- },
- devtool: 'source-map'
+ target: 'node',
+ output: {
+ filename: 'main.js',
+ },
+ node: {
+ global: false,
+ __dirname: false,
+ },
+ externals: nodeModules,
+ module: {
+ loaders: [
+ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
+ ],
+ },
+ devtool: 'source-map',
};