Merge branch 'refactor/splitcomponents'

- Merge in gulp dev envirnoment
- Zoom functionality
- Split app into multiple components
This commit is contained in:
Jia Hao 2016-01-23 13:43:33 +08:00
commit 264037a867
15 changed files with 350 additions and 128 deletions

View File

@ -1 +0,0 @@
Placeholder file here to commit the lib folder, as we cannot mkdir -p on Windows

View File

@ -3,6 +3,5 @@
"targetUrl": "http:\/\/www.google.com",
"badge": false,
"width": 1280,
"height": 800,
"showDevTools": false
"height": 800
}

View File

@ -0,0 +1,21 @@
var electron = require('electron');
var BrowserWindow = electron.BrowserWindow;
var ipcMain = electron.ipcMain;
function createLoginWindow(loginCallback) {
var loginWindow = new BrowserWindow({
width: 300,
height: 400,
frame: false,
resizable: false
});
loginWindow.loadURL('file://' + __dirname + '/static/login/login.html');
ipcMain.once('login-message', function(event, usernameAndPassword) {
loginCallback(usernameAndPassword[0], usernameAndPassword[1]);
loginWindow.close();
});
return loginWindow;
}
module.exports = createLoginWindow;

View File

@ -0,0 +1,105 @@
var path = require('path');
var electron = require('electron');
var helpers = require('./../../helpers/helpers');
var createMenu = require('./../menu/menu');
var BrowserWindow = electron.BrowserWindow;
var shell = electron.shell;
var isOSX = helpers.isOSX;
var linkIsInternal = helpers.linkIsInternal;
const ZOOM_INTERVAL = 0.1;
/**
*
* @param {{}} options AppArgs from nativefier.json
* @param {electron.app.quit} onAppQuit
* @param {electron.app.dock.setBadge} setDockBadge
* @returns {electron.BrowserWindow}
*/
function createMainWindow(options, onAppQuit, setDockBadge) {
var mainWindow = new BrowserWindow(
{
width: options.width || 1280,
height: options.height || 800,
'web-preferences': {
javascript: true,
plugins: true,
nodeIntegration: false,
preload: path.join(__dirname, 'static', 'preload.js')
}
}
);
var currentZoom = 1;
var onZoomIn = function () {
currentZoom += ZOOM_INTERVAL;
mainWindow.webContents.send('change-zoom', currentZoom);
};
var onZoomOut = function () {
currentZoom -= ZOOM_INTERVAL;
mainWindow.webContents.send('change-zoom', currentZoom);
};
createMenu(options.nativefierVersion, onAppQuit, onZoomIn, onZoomOut);
if (options.userAgent) {
mainWindow.webContents.setUserAgent(options.userAgent);
}
mainWindow.webContents.on('did-finish-load', function () {
mainWindow.webContents.send('params', JSON.stringify(options));
});
if (options.counter) {
mainWindow.on('page-title-updated', function () {
if (!isOSX() || mainWindow.isFocused()) {
return;
}
if (options.counter) {
var itemCountRegex = /[\(](\d*?)[\)]/;
var match = itemCountRegex.exec(mainWindow.getTitle());
if (match) {
setDockBadge(match[1]);
}
return;
}
setDockBadge('●');
});
}
mainWindow.webContents.on('new-window', function (event, urlToGo) {
if (linkIsInternal(options.targetUrl, urlToGo)) {
return;
}
event.preventDefault();
shell.openExternal(urlToGo);
});
mainWindow.loadURL(options.targetUrl);
mainWindow.on('focus', function () {
if (!isOSX()) {
return;
}
setDockBadge('');
});
mainWindow.on('close', (e) => {
if (isOSX()) {
// this is called when exiting from clicking the cross button on the window
e.preventDefault();
mainWindow.hide();
}
});
return mainWindow;
}
module.exports = createMainWindow;

View File

@ -2,7 +2,14 @@ var electron = require('electron');
var Menu = electron.Menu;
var shell = electron.shell;
module.exports = function (mainWindow, nativefierVersion, onQuit) {
/**
*
* @param {string} nativefierVersion
* @param {electron.app.quit} onQuit should be from app.quit
* @param {function} onZoomIn
* @param {function} onZoomOut
*/
function createMenu(nativefierVersion, onQuit, onZoomIn, onZoomOut) {
if (Menu.getApplicationMenu())
return;
@ -51,33 +58,57 @@ module.exports = function (mainWindow, nativefierVersion, onQuit) {
{
label: 'Reload',
accelerator: 'CmdOrCtrl+R',
click: function(item, focusedWindow) {
click: function (item, focusedWindow) {
if (focusedWindow)
focusedWindow.reload();
}
},
{
label: 'Toggle Full Screen',
accelerator: (function() {
accelerator: (function () {
if (process.platform == 'darwin')
return 'Ctrl+Command+F';
else
return 'F11';
})(),
click: function(item, focusedWindow) {
click: function (item, focusedWindow) {
if (focusedWindow)
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
}
},
{
label: 'Zoom In',
accelerator: (function () {
if (process.platform == 'darwin')
return 'Command+=';
else
return 'Ctrl+=';
})(),
click: function () {
onZoomIn();
}
},
{
label: 'Zoom Out',
accelerator: (function () {
if (process.platform == 'darwin')
return 'Command+-';
else
return 'Ctrl+-';
})(),
click: function () {
onZoomOut();
}
},
{
label: 'Toggle Window Developer Tools',
accelerator: (function() {
accelerator: (function () {
if (process.platform == 'darwin')
return 'Alt+Command+I';
else
return 'Ctrl+Shift+I';
})(),
click: function(item, focusedWindow) {
click: function (item, focusedWindow) {
if (focusedWindow)
focusedWindow.toggleDevTools();
}
@ -106,11 +137,15 @@ module.exports = function (mainWindow, nativefierVersion, onQuit) {
submenu: [
{
label: `Built with Nativefier v${nativefierVersion}`,
click: function() { shell.openExternal('https://github.com/jiahaog/nativefier') }
click: function () {
shell.openExternal('https://github.com/jiahaog/nativefier')
}
},
{
label: 'Report an Issue',
click: function() { shell.openExternal('https://github.com/jiahaog/nativefier/issues') }
click: function () {
shell.openExternal('https://github.com/jiahaog/nativefier/issues')
}
}
]
}
@ -148,7 +183,9 @@ module.exports = function (mainWindow, nativefierVersion, onQuit) {
{
label: 'Quit',
accelerator: 'Command+Q',
click: function() { onQuit(); }
click: function () {
onQuit();
}
},
]
});
@ -165,4 +202,6 @@ module.exports = function (mainWindow, nativefierVersion, onQuit) {
var menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
};
}
module.exports = createMenu;

View File

@ -0,0 +1,17 @@
var wurl = require('wurl');
var os = require('os');
function isOSX() {
return os.platform() === 'darwin';
}
function linkIsInternal(currentUrl, newUrl) {
var currentDomain = wurl('domain', currentUrl);
var newDomain = wurl('domain', newUrl);
return currentDomain === newDomain;
}
module.exports = {
isOSX: isOSX,
linkIsInternal: linkIsInternal
};

View File

@ -3,25 +3,22 @@
*/
var fs = require('fs');
var os = require('os');
var path = require('path');
var electron = require('electron');
var wurl = require('wurl');
var createMainWindow = require('./components/mainWindow/mainWindow');
var createLoginWindow = require('./components/login/loginWindow');
var helpers = require('./helpers/helpers');
var app = electron.app;
var BrowserWindow = electron.BrowserWindow;
var shell = electron.shell;
var ipcMain = electron.ipcMain;
var buildMenu = require('./components/menu/menu');
var isOSX = helpers.isOSX;
const APP_ARGS_FILE_PATH = path.join(__dirname, '..', 'nativefier.json');
var mainWindow = null;
var appArgs = JSON.parse(fs.readFileSync(APP_ARGS_FILE_PATH, 'utf8'));
var mainWindow;
app.on('window-all-closed', function () {
if (!isOSX()) {
app.quit();
@ -37,7 +34,7 @@ app.on('activate', function (event, hasVisibleWindows) {
}
});
app.on('before-quit', () => {
app.on('before-quit', function () {
// 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
@ -50,106 +47,19 @@ app.on('before-quit', () => {
});
app.on('ready', function () {
mainWindow = new BrowserWindow(
{
width: appArgs.width || 1280,
height: appArgs.height || 800,
'web-preferences': {
javascript: true,
plugins: true,
nodeIntegration: false,
preload: path.join(__dirname, 'preload.js')
}
}
);
buildMenu(mainWindow, appArgs.nativefierVersion, app.quit);
if (appArgs.userAgent) {
mainWindow.webContents.setUserAgent(appArgs.userAgent);
}
mainWindow.webContents.on('did-finish-load', function () {
mainWindow.webContents.send('params', JSON.stringify(appArgs));
});
if (appArgs.counter) {
mainWindow.on('page-title-updated', function () {
if (!isOSX() || mainWindow.isFocused()) {
return;
}
if (appArgs.counter) {
var itemCountRegex = /[\(](\d*?)[\)]/;
var match = itemCountRegex.exec(mainWindow.getTitle());
console.log(mainWindow.getTitle(), match);
if (match) {
app.dock.setBadge(match[1]);
}
return;
}
app.dock.setBadge('●');
});
}
ipcMain.on('notification', function(event, title, opts) {
if (!isOSX() || mainWindow.isFocused()) {
return;
}
app.dock.setBadge('●');
});
mainWindow.webContents.on('new-window', function (event, urlToGo) {
if (linkIsInternal(appArgs.targetUrl, urlToGo)) {
return;
}
event.preventDefault();
shell.openExternal(urlToGo);
});
mainWindow.loadURL(appArgs.targetUrl);
mainWindow.on('focus', function () {
if (!isOSX()) {
return;
}
app.dock.setBadge('');
});
mainWindow.on('close', (e) => {
if (isOSX()) {
// this is called when exiting from clicking the cross button on the window
e.preventDefault();
mainWindow.hide();
}
});
mainWindow = createMainWindow(appArgs, app.quit, app.dock.setBadge);
});
app.on('login', function(event, webContents, request, authInfo, callback) {
// for http authentication
event.preventDefault();
var loginWindow = new BrowserWindow({
width: 300,
height: 400,
frame: false,
resizable: false
});
loginWindow.loadURL('file://' + __dirname + '/components/login/login.html');
ipcMain.once('login-message', function(event, usernameAndPassword) {
callback(usernameAndPassword[0], usernameAndPassword[1]);
loginWindow.close();
});
createLoginWindow(callback);
});
function isOSX() {
return os.platform() === 'darwin';
}
ipcMain.on('notification', function(event, title, opts) {
if (!isOSX() || mainWindow.isFocused()) {
return;
}
function linkIsInternal(currentUrl, newUrl) {
var currentDomain = wurl('domain', currentUrl);
var newDomain = wurl('domain', newUrl);
return currentDomain === newDomain;
}
app.dock.setBadge('●');
});

View File

@ -2,7 +2,9 @@
Preload file that will be executed in the renderer process
*/
var ipc = require('electron').ipcRenderer;
var electron = require('electron');
var ipc = electron.ipcRenderer;
var webFrame = electron.webFrame;
setNotificationCallback(function (title, opt) {
ipc.send('notification', title, opt);
@ -17,6 +19,11 @@ ipc.on('params', function (event, message) {
console.log('nativefier.json', appArgs);
});
ipc.on('change-zoom', function (event, message) {
webFrame.setZoomFactor(message);
});
/**
* Patches window.Notification to set a callback on a new Notification
* @param callback

75
gulpfile.babel.js Normal file
View File

@ -0,0 +1,75 @@
import gulp from 'gulp';
import del from 'del';
import sourcemaps from 'gulp-sourcemaps';
import webpack from 'webpack-stream';
import babel from 'gulp-babel';
import watchify from 'watchify';
import runSequence from 'run-sequence';
import path from 'path';
const PATHS = setUpPaths();
gulp.task('default', ['build']);
gulp.task('build', callback => {
runSequence('clean', ['build-cli', 'build-app'], callback);
});
gulp.task('build-app', ['build-static'], () => {
return gulp.src(PATHS.APP_MAIN_JS)
.pipe(webpack(require(PATHS.WEBPACK_CONFIG)))
.pipe(gulp.dest(PATHS.APP_DEST));
});
gulp.task('clean', callback => {
del(PATHS.CLI_DEST).then(() => {
del(PATHS.APP_DEST).then(() => {
callback();
});
});
});
gulp.task('build-cli', done => {
return gulp.src(PATHS.CLI_SRC_JS)
.pipe(sourcemaps.init())
.pipe(babel())
.on('error', done)
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('lib'));
});
gulp.task('build-static', () => {
// copy any html files in source/ to public/
return gulp.src(PATHS.APP_STATIC_ALL)
.pipe(gulp.dest(PATHS.APP_STATIC_DEST));
});
gulp.task('watch', ['build'], () => {
var handleError = function (error) {
console.error(error);
};
gulp.watch(PATHS.APP_ALL, ['build-app'])
.on('error', handleError);
gulp.watch(PATHS.CLI_SRC_JS, ['build-cli'])
.on('error', handleError);
});
function setUpPaths() {
const paths = {
WEBPACK_CONFIG: './webpack.config.js',
APP_SRC: 'app/src',
APP_DEST: 'app/lib',
CLI_SRC: 'src',
CLI_DEST: 'lib'
};
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_DEST = path.join(paths.APP_DEST, 'static');
paths.CLI_SRC_JS = paths.CLI_SRC + '/**/*.js';
return paths;
}

View File

@ -13,14 +13,12 @@
"scripts": {
"dev-up": "npm install && (cd app && npm install)",
"test": "echo \"Error: no test specified\" && exit 1",
"build-app": "browserify app/src/main.js --node --ignore-missing --detect-globals false --debug -o app/lib/main.js && cp app/src/preload.js app/lib/preload.js",
"build-module": "babel src -d lib",
"build": "npm run build-app && npm run build-module",
"watch": "babel --watch src -d lib",
"build": "gulp build",
"watch": "while true ; do gulp watch ; done",
"prepublish": "npm run build",
"package-placeholder": "npm run build && node lib/cli.js http://www.medium.com ~/Desktop --overwrite && open ~/Desktop/Medium-darwin-x64/Medium.app",
"start-placeholder": "npm run build && electron app",
"debug-auth": "npm run build && node lib/cli.js http://feedly.com/i/welcome ~/Desktop --overwrite --app-name feedly && open ~/Desktop/feedly-darwin-x64/feedly.app"
"clean": "gulp clean"
},
"bin": {
"nativefier": "lib/cli.js"
@ -52,9 +50,15 @@
]
},
"devDependencies": {
"babel-cli": "^6.4.0",
"babel-core": "^6.4.5",
"babel-loader": "^6.2.1",
"babel-preset-es2015": "^6.3.13",
"browserify": "^13.0.0",
"electron-prebuilt": "^0.36.4"
"del": "^2.2.0",
"electron-prebuilt": "^0.36.5",
"gulp": "^3.9.0",
"gulp-babel": "^6.1.1",
"gulp-sourcemaps": "^1.6.0",
"run-sequence": "^1.1.5",
"webpack-stream": "^3.1.0"
}
}

12
trying.js Normal file
View File

@ -0,0 +1,12 @@
var fs = require('fs');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
console.log(nodeModules);

34
webpack.config.js Normal file
View File

@ -0,0 +1,34 @@
var path = require('path');
var fs = require('fs');
//http://jlongster.com/Backend-Apps-with-Webpack--Part-I
// set all modules in node_modules as external
var nodeModules = {};
fs
.readdirSync('./app/node_modules')
.filter(function (x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function (mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
// add electron to external module
nodeModules['electron'] = 'commonjs electron';
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"}
]
}
};