mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
parent
9785baacc3
commit
439f283916
@ -135,10 +135,10 @@
|
||||
});
|
||||
|
||||
var win;
|
||||
|
||||
var openWinButton = document.getElementById('open-win');
|
||||
openWinButton.addEventListener('click', function() {
|
||||
console.log('win=', win)
|
||||
win = window.open('win.html', 'test-window', 'height=100,width=100');
|
||||
win = window.open('win.html?x=100&y=100', 'test-window', 'height=100,width=100');
|
||||
});
|
||||
|
||||
var front = document.getElementById('bring-to-front');
|
||||
@ -146,5 +146,12 @@
|
||||
window.SYM_API.activate(win.name);
|
||||
});
|
||||
|
||||
// register callback to be notified when size/position changes for win.
|
||||
SYM_API.registerBoundsChange(onBoundsChange);
|
||||
|
||||
function onBoundsChange(arg) {
|
||||
console.log('bounds changed for=', arg)
|
||||
}
|
||||
|
||||
</script>
|
||||
</html>
|
||||
|
167
js/config.js
Normal file
167
js/config.js
Normal file
@ -0,0 +1,167 @@
|
||||
'use strict';
|
||||
|
||||
const electron = require('electron');
|
||||
const app = electron.app;
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const isDevEnv = require('./utils/misc.js').isDevEnv;
|
||||
const isMac = require('./utils/misc.js').isMac;
|
||||
const getRegistry = require('./utils/getRegistry.js');
|
||||
const configFileName = 'Symphony.config';
|
||||
|
||||
/**
|
||||
* Tries to read given field from user config file, if field doesn't exist
|
||||
* then tries reading from global config. User config is stord in directory:
|
||||
* app.getPath('userData') and file called Symphony.config. Global config is
|
||||
* stored in file Symphony.config in directory where executable gets installed.
|
||||
*
|
||||
* Config is a flat key/value file.
|
||||
* e.g. { url: 'https://my.symphony.com', }
|
||||
*
|
||||
* @param {String} fieldName Name of field to try fetching
|
||||
* @return {Promise} Returns promise that will succeed with field
|
||||
* value if found in either user or global config. Otherwise will fail promise.
|
||||
*/
|
||||
function getConfigField(fieldName) {
|
||||
return getUserConfigField(fieldName)
|
||||
.then(function(value) {
|
||||
// got value from user config
|
||||
return value;
|
||||
}, function () {
|
||||
// failed to get value from user config, so try global config
|
||||
return getGlobalConfigField(fieldName);
|
||||
});
|
||||
}
|
||||
|
||||
function getUserConfigField(fieldName) {
|
||||
return readUserConfig().then(function(config) {
|
||||
if (typeof fieldName === 'string' && fieldName in config) {
|
||||
return config[fieldName];
|
||||
}
|
||||
|
||||
throw new Error('field does not exist in user config: ' + fieldName);
|
||||
});
|
||||
}
|
||||
|
||||
function readUserConfig() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
let configPath = path.join(app.getPath('userData'), configFileName);
|
||||
|
||||
fs.readFile(configPath, 'utf8', function(err, data) {
|
||||
if (err) {
|
||||
reject('cannot open user config file: ' + configPath + ', error: ' + err);
|
||||
} else {
|
||||
let config = {};
|
||||
try {
|
||||
// data is the contents of the text file we just read
|
||||
config = JSON.parse(data);
|
||||
} catch (e) {
|
||||
reject('can not parse user config file data: ' + data + ', error: ' + err);
|
||||
}
|
||||
|
||||
resolve(config);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getGlobalConfigField(fieldName) {
|
||||
return readGlobalConfig().then(function(config) {
|
||||
if (typeof fieldName === 'string' && fieldName in config) {
|
||||
return config[fieldName];
|
||||
}
|
||||
|
||||
throw new Error('field does not exist in global config: ' + fieldName);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* reads global configuration file: config/Symphony.config. this file is
|
||||
* hold items (such as the start url) that are intended to be used as
|
||||
* global (or default) values for all users running this app. for production
|
||||
* this file is located relative to the executable - it is placed there by
|
||||
* the installer. this makes the file easily modifable by admin (or person who
|
||||
* installed app). for dev env, the file is read directly from packed asar file.
|
||||
*/
|
||||
function readGlobalConfig() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
let configPath;
|
||||
let globalConfigFileName = path.join('config', configFileName);
|
||||
if (isDevEnv) {
|
||||
// for dev env, get config file from asar
|
||||
configPath = path.join(app.getAppPath(), globalConfigFileName);
|
||||
} else {
|
||||
// for non-dev, config file is placed by installer relative to exe.
|
||||
// this is so the config can be easily be changed post install.
|
||||
let execPath = path.dirname(app.getPath('exe'));
|
||||
// for mac exec is stored in subdir, for linux/windows config
|
||||
// dir is in the same location.
|
||||
configPath = path.join(execPath, isMac ? '..' : '', globalConfigFileName);
|
||||
}
|
||||
|
||||
fs.readFile(configPath, 'utf8', function(err, data) {
|
||||
if (err) {
|
||||
reject('cannot open global config file: ' + configPath + ', error: ' + err);
|
||||
} else {
|
||||
let config = {};
|
||||
try {
|
||||
// data is the contents of the text file we just read
|
||||
config = JSON.parse(data);
|
||||
} catch (e) {
|
||||
reject('can not parse config file data: ' + data + ', error: ' + err);
|
||||
}
|
||||
getRegistry('PodUrl')
|
||||
.then(function(url){
|
||||
config.url = url;
|
||||
resolve(config);
|
||||
}).catch(function (){
|
||||
resolve(config);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates user config with given field with new value
|
||||
* @param {String} fieldName [description]
|
||||
* @param {Object} newValue object to replace given value
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
function updateConfigField(fieldName, newValue) {
|
||||
return readUserConfig()
|
||||
.then(function(config) {
|
||||
return saveUserConfig(fieldName, newValue, config);
|
||||
},
|
||||
function() {
|
||||
// in case config doesn't exist, can't read or is corrupted.
|
||||
return saveUserConfig(fieldName, newValue, {});
|
||||
});
|
||||
}
|
||||
|
||||
function saveUserConfig(fieldName, newValue, oldConfig) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
let configPath = path.join(app.getPath('userData'), configFileName);
|
||||
|
||||
if (!oldConfig || !fieldName) {
|
||||
reject('can not save config, invalid input');
|
||||
return;
|
||||
}
|
||||
|
||||
// clone and set new value
|
||||
let newConfig = Object.assign({}, oldConfig);
|
||||
newConfig[fieldName] = newValue;
|
||||
|
||||
let jsonNewConfig = JSON.stringify(newConfig, null, ' ');
|
||||
|
||||
fs.writeFile(configPath, jsonNewConfig, 'utf8', (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { getConfigField, updateConfigField };
|
@ -7,7 +7,8 @@ const cmds = keyMirror({
|
||||
registerLogger: null,
|
||||
setBadgeCount: null,
|
||||
badgeDataUrl: null,
|
||||
activate: null
|
||||
activate: null,
|
||||
registerBoundsChange: null
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
|
@ -1,59 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const electron = require('electron');
|
||||
const app = electron.app;
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const isDevEnv = require('./utils/misc.js').isDevEnv;
|
||||
const isMac = require('./utils/misc.js').isMac;
|
||||
const getRegistry = require('./utils/getRegistry.js');
|
||||
|
||||
/**
|
||||
* reads global configuration file: config/Symphony.config. this file is
|
||||
* hold items (such as the start url) that are intended to be used as
|
||||
* global (or default) values for all users running this app. for production
|
||||
* this file is located relative to the executable - it is placed there by
|
||||
* the installer. this makes the file easily modifable by admin (or person who
|
||||
* installed app). for dev env, the file is read directly from packed asar file.
|
||||
*/
|
||||
var getConfig = function () {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
let configPath;
|
||||
const configFile = 'config/Symphony.config';
|
||||
if (isDevEnv) {
|
||||
// for dev env, get config file from asar
|
||||
configPath = path.join(app.getAppPath(), configFile);
|
||||
} else {
|
||||
// for non-dev, config file is placed by installer relative to exe.
|
||||
// this is so the config can be easily be changed post install.
|
||||
let execPath = path.dirname(app.getPath('exe'));
|
||||
// for mac exec is stored in subdir, for linux/windows config
|
||||
// dir is in the same location.
|
||||
configPath = path.join(execPath, isMac ? '..' : '', configFile);
|
||||
}
|
||||
|
||||
fs.readFile(configPath, 'utf8', function(err, data) {
|
||||
if (err) {
|
||||
reject('cannot open config file: ' + configPath + ', error: ' + err);
|
||||
} else {
|
||||
let config = {};
|
||||
try {
|
||||
// data is the contents of the text file we just read
|
||||
config = JSON.parse(data);
|
||||
} catch (e) {
|
||||
reject('can not parse config file data: ' + data + ', error: ' + err);
|
||||
}
|
||||
getRegistry('PodUrl')
|
||||
.then(function(url){
|
||||
config.url = url;
|
||||
resolve(config);
|
||||
}).catch(function (){
|
||||
resolve(config);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
module.exports = getConfig
|
@ -5,7 +5,7 @@ const app = electron.app;
|
||||
const nodeURL = require('url');
|
||||
const squirrelStartup = require('electron-squirrel-startup');
|
||||
|
||||
const getConfig = require('./getConfig.js');
|
||||
const { getConfigField } = require('./config.js');
|
||||
const { isMac, isDevEnv } = require('./utils/misc.js');
|
||||
|
||||
|
||||
@ -44,17 +44,17 @@ function getUrlAndOpenMainWindow() {
|
||||
}
|
||||
}
|
||||
|
||||
getConfig()
|
||||
getConfigField('url')
|
||||
.then(createWin).catch(function (err){
|
||||
let title = 'Error loading configuration';
|
||||
electron.dialog.showErrorBox(title, title + ': ' + err);
|
||||
});
|
||||
}
|
||||
|
||||
function createWin(config){
|
||||
function createWin(urlFromConfig){
|
||||
let protocol = '';
|
||||
// add https protocol if none found.
|
||||
let parsedUrl = nodeURL.parse(config.url);
|
||||
let parsedUrl = nodeURL.parse(urlFromConfig);
|
||||
if (!parsedUrl.protocol) {
|
||||
protocol = 'https';
|
||||
}
|
||||
|
@ -79,6 +79,10 @@ electron.ipcMain.on(apiName, (event, arg) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg.cmd === apiCmds.registerBoundsChange) {
|
||||
windowMgr.setBoundsChangeWindow(event.sender);
|
||||
}
|
||||
|
||||
if (arg.cmd === apiCmds.registerLogger) {
|
||||
// renderer window that has a registered logger from JS.
|
||||
log.setLogWindow(event.sender);
|
||||
|
@ -87,6 +87,22 @@ function createAPI() {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows JS to register a callback to be invoked when size/positions
|
||||
* changes for any pop-out window (i.e., window.open). The main
|
||||
* process will emit IPC event 'boundsChange' (see below). Currently
|
||||
* only one window can register for bounds change.
|
||||
* @param {Function} callback Function invoked when bounds changes.
|
||||
*/
|
||||
registerBoundsChange: function(callback) {
|
||||
if (typeof callback === 'function') {
|
||||
local.boundsChangeCallback = callback;
|
||||
local.ipcRenderer.send(apiName, {
|
||||
cmd: apiCmds.registerBoundsChange
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* allows JS to register a logger that can be used by electron main process.
|
||||
* @param {Object} logger function that can be called accepting
|
||||
@ -94,9 +110,6 @@ function createAPI() {
|
||||
* logLevel: 'ERROR'|'CONFLICT'|'WARN'|'ACTION'|'INFO'|'DEBUG',
|
||||
* logDetails: String
|
||||
* }
|
||||
*
|
||||
* note: only main window is allowed to register a logger, others are
|
||||
* ignored.
|
||||
*/
|
||||
registerLogger: function(logger) {
|
||||
if (typeof logger === 'function') {
|
||||
@ -119,6 +132,20 @@ function createAPI() {
|
||||
}
|
||||
});
|
||||
|
||||
// listen for notifications that some window size/position has changed
|
||||
local.ipcRenderer.on('boundsChange', (event, arg) => {
|
||||
if (local.boundsChangeCallback && arg.windowName &&
|
||||
arg.x && arg.y && arg.width && arg.height) {
|
||||
local.boundsChangeCallback({
|
||||
x: arg.x,
|
||||
y: arg.y,
|
||||
width: arg.width,
|
||||
height: arg.height,
|
||||
windowName: arg.windowName
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Use render process to create badge count img and send back to main process.
|
||||
* If number is greater than 99 then 99+ img is returned.
|
||||
|
29
js/utils/isInDisplayBounds.js
Normal file
29
js/utils/isInDisplayBounds.js
Normal file
@ -0,0 +1,29 @@
|
||||
'use strict'
|
||||
|
||||
const electron = require('electron');
|
||||
|
||||
/**
|
||||
* Returns true if given rectangle is contained within the workArea of at
|
||||
* least one of the screens.
|
||||
* @param {x: Number, y: Number, width: Number, height: Number} rect
|
||||
* @return {Boolean} true if condition in desc is met.
|
||||
*/
|
||||
function isInDisplayBounds(rect) {
|
||||
if (!rect) {
|
||||
return false;
|
||||
}
|
||||
let displays = electron.screen.getAllDisplays();
|
||||
|
||||
for(let i = 0, len = displays.length; i < len; i++) {
|
||||
let workArea = displays[i].workArea;
|
||||
if (rect.x >= workArea.x && rect.y >= workArea.y &&
|
||||
((rect.x + rect.width) <= (workArea.x + workArea.width)) &&
|
||||
((rect.y + rect.height) <= (workArea.y + workArea.height))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = isInDisplayBounds;
|
@ -18,7 +18,7 @@ function throttle(throttleTime, func) {
|
||||
|
||||
function cancel() {
|
||||
if (timer) {
|
||||
window.clearTimeout(timer);
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
|
204
js/windowMgr.js
204
js/windowMgr.js
@ -4,14 +4,18 @@ const electron = require('electron');
|
||||
const app = electron.app;
|
||||
const path = require('path');
|
||||
const nodeURL = require('url');
|
||||
const querystring = require('querystring');
|
||||
|
||||
const menuTemplate = require('./menus/menuTemplate.js');
|
||||
const loadErrors = require('./dialogs/showLoadError.js');
|
||||
const { isMac } = require('./utils/misc.js');
|
||||
const isInDisplayBounds = require('./utils/isInDisplayBounds.js');
|
||||
const getGuid = require('./utils/getGuid.js');
|
||||
const log = require('./log.js')
|
||||
const logLevels = require('./enums/logLevels.js');
|
||||
const notify = require('./notify/electron-notify.js');
|
||||
const throttle = require('./utils/throttle.js');
|
||||
const { getConfigField, updateConfigField } = require('./config.js');
|
||||
|
||||
//context menu
|
||||
const contextMenu = require('./menus/contextMenu.js');
|
||||
@ -25,6 +29,7 @@ let mainWindow;
|
||||
let windows = {};
|
||||
let willQuitApp = false;
|
||||
let isOnline = true;
|
||||
let boundsChangeWindow;
|
||||
|
||||
// note: this file is built using browserify in prebuild step.
|
||||
const preloadMainScript = path.join(__dirname, 'preload/_preloadMain.js');
|
||||
@ -37,19 +42,29 @@ function removeWindowKey(key) {
|
||||
delete windows[ key ];
|
||||
}
|
||||
|
||||
function getHostFromUrl(url) {
|
||||
function getParsedUrl(url) {
|
||||
let parsedUrl = nodeURL.parse(url);
|
||||
let UrlHost = parsedUrl.host;
|
||||
return UrlHost
|
||||
return parsedUrl;
|
||||
}
|
||||
|
||||
function createMainWindow(initialUrl) {
|
||||
getConfigField('mainWinPos').then(
|
||||
function(bounds) {
|
||||
doCreateMainWindow(initialUrl, bounds);
|
||||
},
|
||||
function() {
|
||||
// failed, use default bounds
|
||||
doCreateMainWindow(initialUrl, null);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function doCreateMainWindow(initialUrl, initialBounds) {
|
||||
let url = initialUrl;
|
||||
let key = getGuid();
|
||||
|
||||
let newWinOpts = {
|
||||
title: 'Symphony',
|
||||
width: 1024, height: 768,
|
||||
show: true,
|
||||
webPreferences: {
|
||||
sandbox: true,
|
||||
@ -59,12 +74,39 @@ function createMainWindow(initialUrl) {
|
||||
}
|
||||
};
|
||||
|
||||
// set size and postion
|
||||
let bounds = initialBounds;
|
||||
|
||||
// if bounds if not fully contained in some display then use default size
|
||||
// and position.
|
||||
if (!isInDisplayBounds(bounds)) {
|
||||
bounds = null;
|
||||
}
|
||||
|
||||
if (bounds && bounds.width && bounds.height) {
|
||||
newWinOpts.width = bounds.width;
|
||||
newWinOpts.height = bounds.height;
|
||||
} else {
|
||||
newWinOpts.width = 1024;
|
||||
newWinOpts.height = 768;
|
||||
}
|
||||
|
||||
// will center on screen if values not provided
|
||||
if (bounds && bounds.x && bounds.y) {
|
||||
newWinOpts.x = bounds.x;
|
||||
newWinOpts.y = bounds.y;
|
||||
}
|
||||
|
||||
// note: augmenting with some custom values
|
||||
newWinOpts.winKey = key;
|
||||
|
||||
mainWindow = new electron.BrowserWindow(newWinOpts);
|
||||
mainWindow.winName = 'main';
|
||||
|
||||
let throttledMainWinBoundsChange = throttle(5000, saveMainWinBounds);
|
||||
mainWindow.on('move', throttledMainWinBoundsChange);
|
||||
mainWindow.on('resize',throttledMainWinBoundsChange);
|
||||
|
||||
function retry() {
|
||||
if (!isOnline) {
|
||||
loadErrors.showNetworkConnectivityError(mainWindow, url, retry);
|
||||
@ -128,8 +170,11 @@ function createMainWindow(initialUrl) {
|
||||
// open external links in default browser - a tag, window.open
|
||||
mainWindow.webContents.on('new-window', function(event, newWinUrl,
|
||||
frameName, disposition, newWinOptions) {
|
||||
let newWinHost = getHostFromUrl(newWinUrl);
|
||||
let mainWinHost = getHostFromUrl(url);
|
||||
let newWinParsedUrl = getParsedUrl(newWinUrl);
|
||||
let mainWinParsedUrl = getParsedUrl(url);
|
||||
|
||||
let newWinHost = newWinParsedUrl && newWinParsedUrl.host;
|
||||
let mainWinHost = mainWinParsedUrl && mainWinParsedUrl.host;
|
||||
|
||||
// if host url doesn't match then open in external browser
|
||||
if (newWinHost !== mainWinHost) {
|
||||
@ -144,44 +189,70 @@ function createMainWindow(initialUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// reposition new window
|
||||
let mainWinPos = mainWindow.getPosition();
|
||||
if (mainWinPos && mainWinPos.length === 2) {
|
||||
let newWinKey = getGuid();
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
newWinOptions.x = mainWinPos[0] + 50;
|
||||
newWinOptions.y = mainWinPos[1] + 50;
|
||||
let width = newWinOptions.width || 300;
|
||||
let height = newWinOptions.height || 600;
|
||||
|
||||
newWinOptions.winKey = newWinKey;
|
||||
/* eslint-enable no-param-reassign */
|
||||
// try getting x and y position from query parameters
|
||||
var query = newWinParsedUrl && querystring.parse(newWinParsedUrl.query);
|
||||
if (query && query.x && query.y) {
|
||||
let newX = Number.parseInt(query.x, 10);
|
||||
let newY = Number.parseInt(query.y, 10);
|
||||
|
||||
let webContents = newWinOptions.webContents;
|
||||
let newWinRect = { x: newX, y: newY, width, height };
|
||||
|
||||
webContents.once('did-finish-load', function() {
|
||||
let browserWin = electron.BrowserWindow.fromWebContents(webContents);
|
||||
|
||||
if (browserWin) {
|
||||
browserWin.winName = frameName;
|
||||
|
||||
browserWin.once('closed', function() {
|
||||
removeWindowKey(newWinKey);
|
||||
});
|
||||
|
||||
addWindowKey(newWinKey, browserWin);
|
||||
}
|
||||
|
||||
// note: will use later for save-layout feature
|
||||
// browserWin.on('move', function() {
|
||||
// var newPos = browserWin.getPosition();
|
||||
// console.log('new pos=', newPos)
|
||||
// });
|
||||
// browserWin.on('resize', function() {
|
||||
// var newSize = browserWin.getSize();
|
||||
// console.log('new size=', newSize)
|
||||
// });
|
||||
});
|
||||
// only accept if both are successfully parsed.
|
||||
if (Number.isInteger(newX) && Number.isInteger(newY) &&
|
||||
isInDisplayBounds(newWinRect)) {
|
||||
x = newX;
|
||||
y = newY;
|
||||
} else {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
} else {
|
||||
// create new window at slight offset from main window.
|
||||
({ x, y } = getWindowSizeAndPosition(mainWindow));
|
||||
x+=50;
|
||||
y+=50;
|
||||
}
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
newWinOptions.x = x;
|
||||
newWinOptions.y = y;
|
||||
newWinOptions.width = width;
|
||||
newWinOptions.height = height;
|
||||
|
||||
let newWinKey = getGuid();
|
||||
|
||||
newWinOptions.winKey = newWinKey;
|
||||
/* eslint-enable no-param-reassign */
|
||||
|
||||
let webContents = newWinOptions.webContents;
|
||||
|
||||
webContents.once('did-finish-load', function() {
|
||||
let browserWin = electron.BrowserWindow.fromWebContents(webContents);
|
||||
|
||||
if (browserWin) {
|
||||
browserWin.winName = frameName;
|
||||
|
||||
browserWin.once('closed', function() {
|
||||
removeWindowKey(newWinKey);
|
||||
browserWin.removeListener('move', throttledBoundsChange);
|
||||
browserWin.removeListener('resize', throttledBoundsChange);
|
||||
});
|
||||
|
||||
addWindowKey(newWinKey, browserWin);
|
||||
|
||||
// throttle changes so we don't flood client.
|
||||
let throttledBoundsChange = throttle(1000,
|
||||
sendChildWinBoundsChange.bind(null, browserWin));
|
||||
browserWin.on('move', throttledBoundsChange);
|
||||
browserWin.on('resize',throttledBoundsChange);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -192,10 +263,35 @@ app.on('before-quit', function() {
|
||||
willQuitApp = true;
|
||||
});
|
||||
|
||||
function saveMainWinBounds() {
|
||||
let newBounds = getWindowSizeAndPosition(mainWindow);
|
||||
|
||||
if (newBounds) {
|
||||
updateConfigField('mainWinPos', newBounds);
|
||||
}
|
||||
}
|
||||
|
||||
function getMainWindow() {
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
function getWindowSizeAndPosition(window) {
|
||||
let newPos = window.getPosition();
|
||||
let newSize = window.getSize();
|
||||
|
||||
if (newPos && newPos.length === 2 &&
|
||||
newSize && newSize.length === 2 ) {
|
||||
return {
|
||||
x: newPos[0],
|
||||
y: newPos[1],
|
||||
width: newSize[0],
|
||||
height: newSize[1],
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function showMainWindow() {
|
||||
mainWindow.show();
|
||||
}
|
||||
@ -217,6 +313,12 @@ function setIsOnline(status) {
|
||||
isOnline = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries finding a window we have created with given name. If founds then
|
||||
* brings to front and gives focus.
|
||||
* @param {String} windowName Name of target window. Note: main window has
|
||||
* name 'main'.
|
||||
*/
|
||||
function activate(windowName) {
|
||||
let keys = Object.keys(windows);
|
||||
for(let i = 0, len = keys.length; i < len; i++) {
|
||||
@ -229,6 +331,27 @@ function activate(windowName) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* name of renderer window to notify when bounds of child window changes.
|
||||
* @param {object} window Renderer window to use IPC with to inform about size/
|
||||
* position change.
|
||||
*/
|
||||
function setBoundsChangeWindow(window) {
|
||||
boundsChangeWindow = window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when bounds of child window changes size/position
|
||||
* @param {object} window Child window which has changed size/position.
|
||||
*/
|
||||
function sendChildWinBoundsChange(window) {
|
||||
let newBounds = getWindowSizeAndPosition(window);
|
||||
if (newBounds && boundsChangeWindow) {
|
||||
newBounds.windowName = window.winName;
|
||||
boundsChangeWindow.send('boundsChange', newBounds);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createMainWindow: createMainWindow,
|
||||
getMainWindow: getMainWindow,
|
||||
@ -236,5 +359,6 @@ module.exports = {
|
||||
isMainWindow: isMainWindow,
|
||||
hasWindow: hasWindow,
|
||||
setIsOnline: setIsOnline,
|
||||
activate: activate
|
||||
activate: activate,
|
||||
setBoundsChangeWindow: setBoundsChangeWindow
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
const getConfig = require('../js/getconfig');
|
||||
const { getConfigField } = require('../js/config');
|
||||
|
||||
// mock required so getConfig reads config from correct path
|
||||
jest.mock('../js/utils/misc.js', function() {
|
||||
@ -9,7 +9,7 @@ jest.mock('../js/utils/misc.js', function() {
|
||||
});
|
||||
|
||||
test('getConfig should have proper url', function() {
|
||||
return getConfig(false).then(function(result) {
|
||||
expect(result.url).toBe('https://my.symphony.com');
|
||||
return getConfigField('url').then(function(url) {
|
||||
expect(url).toBe('https://my.symphony.com');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user