mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
upgrade electron 1.6.5 (#51)
This commit is contained in:
@@ -71,10 +71,8 @@
|
||||
|
||||
notf.addEventListener('click', onclick);
|
||||
function onclick(event) {
|
||||
event.target.data.then(function(value) {
|
||||
alert('notification clicked: ' + value.hello);
|
||||
event.target.close();
|
||||
})
|
||||
event.target.close();
|
||||
alert('notification clicked: ' + event.target.data.hello);
|
||||
}
|
||||
|
||||
notf.addEventListener('close', onclose);
|
||||
|
@@ -47,7 +47,7 @@ function getUrlAndOpenMainWindow() {
|
||||
getConfig()
|
||||
.then(createWin).catch(function (err){
|
||||
let title = 'Error loading configuration';
|
||||
electron.dialog.showErrorBox(title, title + ': ' + err);
|
||||
electron.dialog.showErrorBox(title, title + ': ' + err);
|
||||
});
|
||||
}
|
||||
|
||||
|
373
js/mainApiMgr.js
373
js/mainApiMgr.js
@@ -13,7 +13,6 @@ const badgeCount = require('./badgeCount.js');
|
||||
const apiEnums = require('./enums/api.js');
|
||||
const apiCmds = apiEnums.cmds;
|
||||
const apiName = apiEnums.apiName;
|
||||
const apiProxyCmds = apiEnums.proxyCmds
|
||||
|
||||
// can be overridden for testing
|
||||
let checkValidWindow = true;
|
||||
@@ -90,380 +89,8 @@ electron.ipcMain.on(apiName, (event, arg) => {
|
||||
}
|
||||
});
|
||||
|
||||
const Notify = require('./notify/notifyImpl.js');
|
||||
|
||||
// holds all project classes that can be created.
|
||||
let api = {
|
||||
Notify: Notify
|
||||
}
|
||||
|
||||
// holds all proxy object instances
|
||||
let liveObjs = {};
|
||||
|
||||
let id = 1;
|
||||
function uniqueId() {
|
||||
return id++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates instance of given class for proxy in renderer process.
|
||||
*
|
||||
* @param {Object} args {
|
||||
* className {String} name of class to create.
|
||||
* }
|
||||
*
|
||||
* @return {Number} unique id for class intance created.
|
||||
*/
|
||||
electron.ipcMain.on(apiProxyCmds.createObject, function(event, args) {
|
||||
if (!isValidWindow(event)) {
|
||||
setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
function setResult(value) {
|
||||
/* eslint-disable no-param-reassign */
|
||||
event.returnValue = value;
|
||||
/* eslint-enable no-param-reassign */
|
||||
}
|
||||
|
||||
if (args.className && api[args.className]) {
|
||||
var obj = new api[args.className](...args.constructorArgsArray);
|
||||
obj._callbacks = {};
|
||||
|
||||
let objId = uniqueId();
|
||||
liveObjs[objId] = obj;
|
||||
|
||||
// special destroy event listener so implementation can raise event to
|
||||
// clean up everything.
|
||||
if (typeof obj.addEventListener === 'function' &&
|
||||
typeof obj.removeEventListener === 'function') {
|
||||
let destroy = function() {
|
||||
var callbackIds = Object.keys(obj._callbacks);
|
||||
callbackIds.forEach(function(callbackId) {
|
||||
let callback = obj._callbacks[ callbackId ];
|
||||
if (typeof callback === 'function') {
|
||||
// invoke callback to proxy so it clean up itself.
|
||||
callback(null, 'destroy');
|
||||
|
||||
if (callback.eventName) {
|
||||
obj.removeEventListener(callback.eventName, callback);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
obj.removeEventListener('destroy', destroy);
|
||||
obj._callbacks = null;
|
||||
|
||||
var liveObj = liveObjs[objId];
|
||||
if (liveObj) {
|
||||
delete liveObjs[objId];
|
||||
}
|
||||
}
|
||||
|
||||
obj.addEventListener('destroy', destroy);
|
||||
}
|
||||
|
||||
setResult(objId);
|
||||
} else {
|
||||
setResult(null);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Invokes a method for the proxy.
|
||||
*
|
||||
* @param {Object} args {
|
||||
* objId {Number} id of object previously created, not needed for static call.
|
||||
* invokeId {Number} id used by proxy to uniquely identify this method call
|
||||
* methodName {String} name of method to call
|
||||
* arguments: {Array} arguments to invoke method with.
|
||||
* isStatic: {bool} true is this is a static method.
|
||||
* className {String} name of class on which func is invoked.
|
||||
* }
|
||||
*
|
||||
* @return {Object} {
|
||||
* returnValue {Object} result of calling method
|
||||
* invokeId {Number} id so proxy can identify method call
|
||||
* }
|
||||
*/
|
||||
electron.ipcMain.on(apiProxyCmds.invokeMethod, function(event, args) {
|
||||
if (!isValidWindow(event) || !args.invokeId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.isStatic && (!args.objId || !liveObjs[args.objId])) {
|
||||
event.sender.send(apiProxyCmds.invokeResult, {
|
||||
error: 'calling obj is not present',
|
||||
invokeId: args.invokeId
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// static method call must have className and class must exist in api
|
||||
if (args.isStatic) {
|
||||
if (!args.className) {
|
||||
event.sender.send(apiProxyCmds.invokeResult, {
|
||||
error: 'for static method must provide class name',
|
||||
invokeId: args.invokeId
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!api[args.className]) {
|
||||
event.sender.send(apiProxyCmds.invokeResult, {
|
||||
error: 'no class exists: ' + args.className,
|
||||
invokeId: args.invokeId
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let result;
|
||||
let funcArgs = args.arguments || [];
|
||||
|
||||
if (args.isStatic) {
|
||||
let classType = api[args.className];
|
||||
|
||||
if (!args.methodName || !classType[args.methodName]) {
|
||||
event.sender.send(apiProxyCmds.invokeResult, {
|
||||
error: 'no such static method',
|
||||
invokeId: args.invokeId
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
result = classType[args.methodName](...funcArgs);
|
||||
} else {
|
||||
let obj = liveObjs[args.objId];
|
||||
if (!args.methodName || !obj[args.methodName]) {
|
||||
event.sender.send(apiProxyCmds.invokeResult, {
|
||||
error: 'no such method',
|
||||
invokeId: args.invokeId
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// special method to lose ref to obj
|
||||
if (args.methodName === 'destroy') {
|
||||
delete liveObjs[args.objId];
|
||||
}
|
||||
|
||||
result = obj[args.methodName](...funcArgs);
|
||||
}
|
||||
|
||||
event.sender.send(apiProxyCmds.invokeResult, {
|
||||
returnValue: result,
|
||||
invokeId: args.invokeId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Getter implementation. Allows proxy to retrieve value from implementation
|
||||
* object.
|
||||
*
|
||||
* @param {Object} args {
|
||||
* objId {Number} id of object previously created (not needed for static get)
|
||||
* getterId {Number} id used by proxy to uniquely identify this getter call.
|
||||
* getterProperty {String} name of getter property to retrieve.
|
||||
* isStatic {boo} true if this if getter is for static property.
|
||||
* className {String} name of class we are operating on here.
|
||||
* }
|
||||
*
|
||||
* @return {Object} {
|
||||
* returnValue {Object} result of calling method
|
||||
* getterId {Number} id so proxy can identify getter call
|
||||
* }
|
||||
*/
|
||||
electron.ipcMain.on(apiProxyCmds.get, function(event, args) {
|
||||
if (!isValidWindow(event) || !args.getterId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// non-static calls must have an live instance available
|
||||
if (!args.isStatic && (!args.objId || !liveObjs[args.objId])) {
|
||||
event.sender.send(apiProxyCmds.getResult, {
|
||||
error: 'calling obj is not present',
|
||||
getterId: args.getterId
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// static get must have className and class must exist in api
|
||||
if (args.isStatic) {
|
||||
if (!args.className) {
|
||||
event.sender.send(apiProxyCmds.getResult, {
|
||||
error: 'for static getter must provide class name',
|
||||
getterId: args.getterId
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!api[args.className]) {
|
||||
event.sender.send(apiProxyCmds.getResult, {
|
||||
error: 'no class exists: ' + args.className,
|
||||
getterId: args.getterId
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.getterProperty) {
|
||||
event.sender.send(apiProxyCmds.getResult, {
|
||||
error: 'property name not provided',
|
||||
getterId: args.getterId
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let result;
|
||||
if (args.isStatic) {
|
||||
let classType = api[args.className]
|
||||
result = classType[args.getterProperty];
|
||||
} else {
|
||||
let obj = liveObjs[args.objId];
|
||||
result = obj[args.getterProperty];
|
||||
}
|
||||
|
||||
event.sender.send(apiProxyCmds.getResult, {
|
||||
returnValue: result,
|
||||
getterId: args.getterId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Setter implementation. Allows proxy to set value on implementation object.
|
||||
*
|
||||
* @param {Object} args {
|
||||
* objId {Number} id of object previously created.
|
||||
* setterProperty {String} name of setter property.
|
||||
* setterValue {object} new value to set.
|
||||
* }
|
||||
*
|
||||
* @return {Object} input setter value
|
||||
*/
|
||||
electron.ipcMain.on(apiProxyCmds.set, function(event, args) {
|
||||
if (!isValidWindow(event)) {
|
||||
setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.objId || !liveObjs[args.objId]) {
|
||||
setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.setterProperty) {
|
||||
setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
function setResult(value) {
|
||||
/* eslint-disable no-param-reassign */
|
||||
event.returnValue = value;
|
||||
/* eslint-enable no-param-reassign */
|
||||
}
|
||||
|
||||
let obj = liveObjs[args.objId];
|
||||
obj[args.setterProperty] = args.setterValue;
|
||||
setResult(args.setterValue);
|
||||
});
|
||||
|
||||
/**
|
||||
* Listens to an event and calls back to renderer proxy when given event occurs.
|
||||
*
|
||||
* @param {Object} args {
|
||||
* objId {Number} id of object previously created.
|
||||
* callbackId {Number} id used by proxy to uniquely identify this event.
|
||||
* eventName {String} name of event to listen for.
|
||||
* }
|
||||
*
|
||||
* @return {Object} {
|
||||
* result {Object} result from invoking callback.
|
||||
* callbackId {Number} id so proxy can identify event that occurred.
|
||||
* }
|
||||
*/
|
||||
electron.ipcMain.on(apiProxyCmds.addEvent, function(event, args) {
|
||||
if (!isValidWindow(event)) {
|
||||
return;
|
||||
}
|
||||
/* eslint-disable no-console */
|
||||
if (!args.objId || !liveObjs[args.objId]) {
|
||||
console.log('calling obj is not present');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.callbackId) {
|
||||
console.log('no callback id provided');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.eventName) {
|
||||
console.log('no eventName provided');
|
||||
return;
|
||||
}
|
||||
/* eslint-enable no-console */
|
||||
|
||||
let obj = liveObjs[args.objId];
|
||||
|
||||
// callback invoked from implementation or locally in destroy to
|
||||
// clean up event handlers.
|
||||
let callbackFunc = function(result, type) {
|
||||
event.sender.send(apiProxyCmds.eventCallback, {
|
||||
callbackId: args.callbackId,
|
||||
result: result,
|
||||
type: type
|
||||
});
|
||||
}
|
||||
callbackFunc.eventName = args.eventName;
|
||||
obj._callbacks[args.callbackId] = callbackFunc;
|
||||
obj.addEventListener(args.eventName, callbackFunc);
|
||||
});
|
||||
|
||||
/**
|
||||
* Stops listening to given event.
|
||||
*
|
||||
* @param {Object} args {
|
||||
* objId {Number} id of object previously created.
|
||||
* callbackId {Number} id used by proxy to uniquely identify this event.
|
||||
* eventName {String} name of event to listen for.
|
||||
* }
|
||||
*/
|
||||
electron.ipcMain.on(apiProxyCmds.removeEvent, function(event, args) {
|
||||
if (!isValidWindow(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* eslint-disable no-console */
|
||||
if (!args.objId || !liveObjs[args.objId]) {
|
||||
console.log('calling obj is not present');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.callbackId) {
|
||||
console.log('no callback id provided');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.eventName) {
|
||||
console.log('no eventName provided');
|
||||
return;
|
||||
}
|
||||
/* eslint-enable no-console */
|
||||
|
||||
let obj = liveObjs[args.objId];
|
||||
let callbackFunc = obj._callbacks[args.callbackId];
|
||||
if (typeof callbackFunc === 'function') {
|
||||
obj.removeEventListener(args.eventName, callbackFunc);
|
||||
}
|
||||
});
|
||||
|
||||
function addNewInterface(name, interfaceClass) {
|
||||
api[name] = interfaceClass;
|
||||
}
|
||||
|
||||
// expose these methods primarily for testing...
|
||||
module.exports = {
|
||||
addNewInterface: addNewInterface,
|
||||
shouldCheckValidWindow: function(shouldCheck) {
|
||||
checkValidWindow = shouldCheck;
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ function setStyle(config) {
|
||||
setStyleOnDomElement(config.defaultStyleClose, close);
|
||||
}
|
||||
|
||||
function setContents(notificationObj) {
|
||||
function setContents(event, notificationObj) {
|
||||
// sound
|
||||
if (notificationObj.sound) {
|
||||
// Check if file is accessible
|
||||
@@ -122,7 +122,7 @@ function setStyleOnDomElement(styleObj, domElement) {
|
||||
}
|
||||
}
|
||||
|
||||
function loadConfig(conf) {
|
||||
function loadConfig(event, conf) {
|
||||
setStyle(conf || {})
|
||||
}
|
||||
|
||||
|
@@ -131,7 +131,13 @@ let config = {
|
||||
// calcDimensions();
|
||||
// }
|
||||
|
||||
app.on('ready', function() {
|
||||
if (app.isReady) {
|
||||
setup();
|
||||
} else {
|
||||
app.on('ready', setup);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
setupConfig();
|
||||
|
||||
// if display added/removed/changed then re-run setup and remove all existing
|
||||
@@ -139,8 +145,7 @@ app.on('ready', function() {
|
||||
electron.screen.on('display-added', setupConfig);
|
||||
electron.screen.on('display-removed', setupConfig);
|
||||
electron.screen.on('display-metrics-changed', setupConfig);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function getTemplatePath() {
|
||||
let templatePath = path.join(__dirname, 'electron-notify.html');
|
||||
|
@@ -8,6 +8,24 @@ const { notify } = require('./electron-notify.js');
|
||||
* wrapper around electron-notify.
|
||||
*/
|
||||
class Notify {
|
||||
/**
|
||||
* Dislays a notifications
|
||||
*
|
||||
* @param {String} title Title of notification
|
||||
* @param {Object} options {
|
||||
* body {string} main text to display in notifications
|
||||
* image {string} url of image to show in notification
|
||||
* icon {string} url of image to show in notification
|
||||
* flash {bool} true if notification should flash (default false)
|
||||
* color {string} background color for notification
|
||||
* tag {string} non-empty string to unique identify notf, if another
|
||||
* notification arrives with same tag then it's content will
|
||||
* replace existing notification.
|
||||
* sticky {bool} if true notification will stay until user closes. default
|
||||
* is false.
|
||||
* data {object} arbitrary object to be stored with notification
|
||||
* }
|
||||
*/
|
||||
constructor(title, options) {
|
||||
this.emitter = new EventEmitter();
|
||||
|
||||
@@ -36,13 +54,17 @@ class Notify {
|
||||
|
||||
function onClick(arg) {
|
||||
if (arg.id === this._id) {
|
||||
this.emitter.emit('click');
|
||||
this.emitter.emit('click', {
|
||||
target: this
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onClose(arg) {
|
||||
if (arg.id === this._id || arg.event === 'close-all') {
|
||||
this.emitter.emit('close');
|
||||
this.emitter.emit('close', {
|
||||
target: this
|
||||
});
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
@@ -59,6 +81,9 @@ class Notify {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* close notification
|
||||
*/
|
||||
close() {
|
||||
if (typeof this._closeNotification === 'function') {
|
||||
this._closeNotification('close');
|
||||
@@ -66,20 +91,39 @@ class Notify {
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* always allow showing notifications.
|
||||
* @return {string} 'granted'
|
||||
*/
|
||||
static get permission() {
|
||||
return 'granted';
|
||||
}
|
||||
|
||||
/**
|
||||
* returns data object passed in via constructor options
|
||||
*/
|
||||
get data() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
/**
|
||||
* add event listeners for 'click', 'close', 'show', 'error' events
|
||||
*
|
||||
* @param {String} event event to listen for
|
||||
* @param {func} cb callback invoked when event occurs
|
||||
*/
|
||||
addEventListener(event, cb) {
|
||||
if (event && typeof cb === 'function') {
|
||||
this.emitter.on(event, cb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove event listeners for 'click', 'close', 'show', 'error' events
|
||||
*
|
||||
* @param {String} event event to stop listening for.
|
||||
* @param {func} cb callback associated with original addEventListener
|
||||
*/
|
||||
removeEventListener(event, cb) {
|
||||
if (event && typeof cb === 'function') {
|
||||
this.emitter.removeListener(event, cb);
|
||||
@@ -89,10 +133,7 @@ class Notify {
|
||||
//
|
||||
// private stuff below here
|
||||
//
|
||||
|
||||
destroy() {
|
||||
// allow live instance to be destroyed
|
||||
this.emitter.emit('destroy');
|
||||
this.emitter.removeAllListeners();
|
||||
}
|
||||
|
||||
|
@@ -1,72 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* interface defn for notifications. Implementation of this interface
|
||||
* is in notifyImpl.js
|
||||
*
|
||||
* Used by preloadMain.js to create proxy for actual implementation.
|
||||
*
|
||||
* Keep interface here in sync with implementation, in order
|
||||
* to expose methods/props to renderer.
|
||||
*
|
||||
* Note: getters and method calls here return a promise.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
class Notify {
|
||||
/**
|
||||
* Dislays a notifications
|
||||
*
|
||||
* @param {String} title Title of notification
|
||||
* @param {Object} options {
|
||||
* body {string} main text to display in notifications
|
||||
* image {string} url of image to show in notification
|
||||
* icon {string} url of image to show in notification
|
||||
* flash {bool} true if notification should flash (default false)
|
||||
* color {string} background color for notification
|
||||
* tag {string} non-empty string to unique identify notf, if another
|
||||
* notification arrives with same tag then it's content will
|
||||
* replace existing notification.
|
||||
* sticky {bool} if true notification will stay until user closes. default
|
||||
* is false.
|
||||
* data {object} arbitrary object to be stored with notification
|
||||
* }
|
||||
*/
|
||||
constructor(title, options) {}
|
||||
|
||||
/**
|
||||
* close notification
|
||||
*/
|
||||
close() {}
|
||||
|
||||
/**
|
||||
* This returns a promise and is always 'granted'
|
||||
* @return {promise} promise fullfilled with 'granted'
|
||||
*/
|
||||
static get permission() {}
|
||||
|
||||
/**
|
||||
* returns data object passed in via constructor options, return a
|
||||
* promise that will be fullfilled with the data.
|
||||
*/
|
||||
get data() {}
|
||||
|
||||
/**
|
||||
* add event listeners for 'click', 'close', 'show', 'error' events
|
||||
*
|
||||
* @param {String} event event to listen for
|
||||
* @param {func} cb callback invoked when event occurs
|
||||
*/
|
||||
addEventListener(event, cb) {}
|
||||
|
||||
/**
|
||||
* remove event listeners for 'click', 'close', 'show', 'error' events
|
||||
*
|
||||
* @param {String} event event to stop listening for.
|
||||
* @param {func} cb callback associated with original addEventListener
|
||||
*/
|
||||
removeEventListener(event, cb) {}
|
||||
}
|
||||
/* eslint-enable */
|
||||
|
||||
module.exports = Notify;
|
@@ -1,279 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const { ipcRenderer } = require('electron');
|
||||
|
||||
const apiEnums = require('../enums/api.js');
|
||||
const proxyCmds = apiEnums.proxyCmds;
|
||||
|
||||
/**
|
||||
* Creates and returns a proxy (in renderer process) that will use IPC
|
||||
* with main process where "real" instance is created.
|
||||
*
|
||||
* The constructor is executed synchronously, so take care to not block
|
||||
* processes.
|
||||
*
|
||||
* All method calls will be sent over IPC to main process, evaulated and
|
||||
* result returned back to main process. Method calls return a promise.
|
||||
*
|
||||
* Special method calls: "addEventListener" and "removeEventListener" allow
|
||||
* attaching/detaching to events.
|
||||
*
|
||||
* Getters (e.g., x.y) will return a promise that gets fullfilled
|
||||
* when ipc returns value.
|
||||
*
|
||||
* Setters are synchronously executed (so take care).
|
||||
*
|
||||
* Note: The "real" instance should implement a destroy method (e.g., close) that
|
||||
* should be used to destroy the instance held in main process, otherwise a
|
||||
* memory leak will occur - as renderer can not know when instance is no longer
|
||||
* used. Would like to incorporate: https://github.com/EvolveLabs/electron-weak
|
||||
*
|
||||
* @param {Class} ApiClass reference to prototype/class constructor.
|
||||
* @return {object} proxy for ApiClass.
|
||||
*/
|
||||
function createProxy(ApiClass) {
|
||||
return new Proxy(ApiClass, constructorHandler);
|
||||
}
|
||||
|
||||
let id = 1;
|
||||
function uniqueId() {
|
||||
return id++;
|
||||
}
|
||||
|
||||
let constructorHandler = {
|
||||
construct: function(target, argumentsList) {
|
||||
var arg = {
|
||||
className: target.name,
|
||||
constructorArgsArray: argumentsList
|
||||
};
|
||||
|
||||
var objId = ipcRenderer.sendSync(proxyCmds.createObject, arg);
|
||||
|
||||
if (!objId) {
|
||||
throw new Error('can not create obj: ' + target.name);
|
||||
}
|
||||
|
||||
var ProxyClass = new target();
|
||||
ProxyClass._objId = objId;
|
||||
ProxyClass._callbacks = new WeakMap();
|
||||
|
||||
let instanceHandler = {
|
||||
get: instanceGetHandler,
|
||||
set: instanceSetHandler
|
||||
}
|
||||
|
||||
// work like to incorporate something like https://github.com/EvolveLabs/electron-weak
|
||||
// here to tell when object is destroyed so we can ipc main process to
|
||||
// loss ref to liveObj.
|
||||
|
||||
return new Proxy(ProxyClass, instanceHandler);
|
||||
},
|
||||
|
||||
// static getter and method handler
|
||||
get: staticGetHandler
|
||||
}
|
||||
|
||||
function instanceGetHandler(target, name) {
|
||||
// all methods and getters we support should be on the prototype
|
||||
let prototype = Object.getPrototypeOf(target);
|
||||
let desc = Object.getOwnPropertyDescriptor(prototype, name);
|
||||
|
||||
// does this have a "getter"
|
||||
if (desc && desc.get) {
|
||||
return getHandler(target, name, false);
|
||||
}
|
||||
// does this have a method
|
||||
if (desc && typeof desc.value === 'function') {
|
||||
if (name === 'addEventListener') {
|
||||
return addEventHandler(target);
|
||||
}
|
||||
|
||||
if (name === 'removeEventListener') {
|
||||
return removeEventHandler(target);
|
||||
}
|
||||
|
||||
return methodHandler(target, name, false);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function addEventHandler(target) {
|
||||
return function(eventName, callback) {
|
||||
var callbackId = eventName + uniqueId();
|
||||
var args = {
|
||||
callbackId: callbackId,
|
||||
objId: target._objId,
|
||||
eventName: eventName
|
||||
};
|
||||
ipcRenderer.send(proxyCmds.addEvent, args);
|
||||
|
||||
let callbackFunc = function(arg) {
|
||||
if (arg.callbackId === callbackId) {
|
||||
// special destroy callback so we can clean up event listeners.
|
||||
if (arg.type === 'destroy') {
|
||||
ipcRenderer.removeListener(proxyCmds.eventCallback,
|
||||
callbackFunc);
|
||||
target._callbacks.delete(callbackFunc);
|
||||
return;
|
||||
}
|
||||
callback({
|
||||
target: this,
|
||||
type: eventName,
|
||||
result: arg.result
|
||||
});
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
ipcRenderer.on(proxyCmds.eventCallback, callbackFunc);
|
||||
|
||||
target._callbacks.set(callback, {
|
||||
callbackId: callbackId,
|
||||
callbackFunc: callbackFunc
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function removeEventHandler(target) {
|
||||
return function(eventName, callback) {
|
||||
if (target._callbacks && target._callbacks.has(callback)) {
|
||||
let callbackObj = target._callbacks.get(callback);
|
||||
|
||||
let args = {
|
||||
eventName: eventName,
|
||||
callbackId: callbackObj.callbackId,
|
||||
objId: target._objId
|
||||
}
|
||||
|
||||
ipcRenderer.removeListener(proxyCmds.eventCallback,
|
||||
callbackObj.callbackFunc);
|
||||
|
||||
ipcRenderer.send(proxyCmds.removeEvent, args);
|
||||
|
||||
target._callbacks.delete(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function methodHandler(target, methodName, isStatic) {
|
||||
return function(...argPassedToMethod) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var invokeId = methodName + uniqueId();
|
||||
var args = {
|
||||
invokeId: invokeId,
|
||||
objId: target._objId,
|
||||
methodName: methodName,
|
||||
arguments: argPassedToMethod,
|
||||
isStatic: isStatic,
|
||||
className: target.name
|
||||
}
|
||||
|
||||
if (!isStatic) {
|
||||
args.objId = target._objId;
|
||||
}
|
||||
|
||||
ipcRenderer.on(proxyCmds.invokeResult, resultCallback);
|
||||
ipcRenderer.send(proxyCmds.invokeMethod, args);
|
||||
|
||||
function removeEventListener() {
|
||||
ipcRenderer.removeListener(proxyCmds.invokeResult,
|
||||
resultCallback);
|
||||
}
|
||||
function resultCallback(arg) {
|
||||
if (arg.invokeId === invokeId) {
|
||||
window.clearTimeout(timer);
|
||||
removeEventListener();
|
||||
if (arg.error) {
|
||||
reject('method called failed: ' + arg.error);
|
||||
} else {
|
||||
resolve(arg.returnValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// timeout in case we never hear anything back from main process
|
||||
let timer = setTimeout(function() {
|
||||
removeEventListener();
|
||||
reject('timeout_no_reponse');
|
||||
}, 5000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getHandler(target, property, isStatic) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var getterId = property + uniqueId();
|
||||
var args = {
|
||||
getterId: getterId,
|
||||
getterProperty: property,
|
||||
isStatic: isStatic,
|
||||
className: target.name
|
||||
}
|
||||
|
||||
if (!isStatic) {
|
||||
args.objId = target._objId;
|
||||
}
|
||||
|
||||
ipcRenderer.on(proxyCmds.getResult, resultCallback);
|
||||
ipcRenderer.send(proxyCmds.get, args);
|
||||
|
||||
function removeEventListener() {
|
||||
ipcRenderer.removeListener(proxyCmds.getResult,
|
||||
resultCallback);
|
||||
}
|
||||
function resultCallback(arg) {
|
||||
if (arg.getterId === getterId) {
|
||||
window.clearTimeout(timer);
|
||||
removeEventListener();
|
||||
if (arg.error) {
|
||||
reject('getter called failed: ' + arg.error);
|
||||
} else {
|
||||
resolve(arg.returnValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// timeout in case we never hear anything back from main process
|
||||
let timer = setTimeout(function() {
|
||||
removeEventListener();
|
||||
reject('timeout_no_reponse');
|
||||
}, 5000);
|
||||
});
|
||||
}
|
||||
|
||||
function instanceSetHandler(target, property, value) {
|
||||
let prototype = Object.getPrototypeOf(target);
|
||||
let desc = Object.getOwnPropertyDescriptor(prototype, property);
|
||||
if (desc && desc.set) {
|
||||
var args = {
|
||||
objId: target._objId,
|
||||
setterProperty: property,
|
||||
setterValue: value
|
||||
}
|
||||
|
||||
ipcRenderer.sendSync(proxyCmds.set, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function staticGetHandler(target, name) {
|
||||
// all methods and getters we support should be on the prototype
|
||||
let desc = Object.getOwnPropertyDescriptor(target, name);
|
||||
|
||||
// does this have a static "getter"
|
||||
if (desc && desc.get) {
|
||||
return getHandler(target, name, true);
|
||||
}
|
||||
// does this have a static method
|
||||
if (desc && typeof desc.value === 'function') {
|
||||
return methodHandler(target, name, true);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
module.exports = createProxy
|
@@ -12,22 +12,20 @@
|
||||
// https://github.com/electron/electron/issues/2984
|
||||
//
|
||||
|
||||
const { ipcRenderer } = require('electron');
|
||||
const { ipcRenderer, remote } = require('electron');
|
||||
|
||||
const throttle = require('../utils/throttle.js');
|
||||
const apiEnums = require('../enums/api.js');
|
||||
const apiCmds = apiEnums.cmds;
|
||||
const apiName = apiEnums.apiName;
|
||||
|
||||
const notifyInterface = require('../notify/notifyInterface.js');
|
||||
const createProxy = require('./createProxy.js');
|
||||
|
||||
// hold ref so doesn't get GC'ed
|
||||
const local = {
|
||||
ipcRenderer: ipcRenderer,
|
||||
|
||||
};
|
||||
|
||||
var notify = remote.require('./notify/notifyImpl.js');
|
||||
|
||||
// throttle calls to this func to at most once per sec, called on leading edge.
|
||||
const throttledSetBadgeCount = throttle(1000, function(count) {
|
||||
local.ipcRenderer.send(apiName, {
|
||||
@@ -63,9 +61,9 @@ window.SYM_API = {
|
||||
|
||||
/**
|
||||
* provides api similar to html5 Notification, see details
|
||||
* in notify/notifyInterface.js
|
||||
* in notify/notifyImpl.js
|
||||
*/
|
||||
Notification: createProxy(notifyInterface),
|
||||
Notification: notify,
|
||||
|
||||
/**
|
||||
* allows JS to register a logger that can be used by electron main process.
|
||||
@@ -93,7 +91,7 @@ window.SYM_API = {
|
||||
Object.freeze(window.SYM_API);
|
||||
|
||||
// listen for log message from main process
|
||||
local.ipcRenderer.on('log', (arg) => {
|
||||
local.ipcRenderer.on('log', (event, arg) => {
|
||||
if (local.logger && arg && arg.level && arg.msg) {
|
||||
local.logger({
|
||||
logLevel: arg.level,
|
||||
@@ -109,7 +107,7 @@ local.ipcRenderer.on('log', (arg) => {
|
||||
* need to use ipcRenderer to callback to main process.
|
||||
* @type {object} arg.count - number: count to be displayed
|
||||
*/
|
||||
local.ipcRenderer.on('createBadgeDataUrl', (arg) => {
|
||||
local.ipcRenderer.on('createBadgeDataUrl', (event, arg) => {
|
||||
const count = arg && arg.count || 0;
|
||||
|
||||
// create 32 x 32 img
|
||||
|
@@ -69,7 +69,7 @@
|
||||
"babel-preset-es2015": "^6.24.0",
|
||||
"browserify": "^14.1.0",
|
||||
"cross-env": "^3.2.4",
|
||||
"electron": "1.5.1",
|
||||
"electron": "1.6.5",
|
||||
"electron-builder": "^13.9.0",
|
||||
"electron-builder-squirrel-windows": "^12.3.0",
|
||||
"electron-packager": "^8.5.2",
|
||||
|
@@ -1,184 +0,0 @@
|
||||
|
||||
// Note: fork of polyfill since it doesn't handle creating
|
||||
// a Proxy from an existing Proxy.
|
||||
// ToDo: need to submit PR to https://github.com/GoogleChrome/proxy-polyfill
|
||||
|
||||
/*
|
||||
* Copyright 2016 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
// note: polyfill here can be removed when everyone is using node >= 6.4.0
|
||||
|
||||
'use strict';
|
||||
|
||||
(function(scope) {
|
||||
if (scope['Proxy']) {
|
||||
return;
|
||||
}
|
||||
let lastRevokeFn = null;
|
||||
|
||||
/**
|
||||
* @param {*} o
|
||||
* @return {boolean} whether this is probably a (non-null) Object
|
||||
*/
|
||||
function isObject(o) {
|
||||
return o ? (typeof o == 'object' || typeof o == 'function') : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {!Object} target
|
||||
* @param {{apply, construct, get, set}} handler
|
||||
*/
|
||||
scope.Proxy = function(target, handler) {
|
||||
|
||||
if (!isObject(target) || !isObject(handler)) {
|
||||
throw new TypeError('Cannot create proxy with a non-object as target or handler');
|
||||
}
|
||||
|
||||
// Construct revoke function, and set lastRevokeFn so that Proxy.revocable can steal it.
|
||||
// The caller might get the wrong revoke function if a user replaces or wraps scope.Proxy
|
||||
// to call itself, but that seems unlikely especially when using the polyfill.
|
||||
let throwRevoked = function() {};
|
||||
lastRevokeFn = function() {
|
||||
throwRevoked = function(trap) {
|
||||
throw new TypeError(`Cannot perform '${trap}' on a proxy that has been revoked`);
|
||||
};
|
||||
};
|
||||
|
||||
// Fail on unsupported traps: Chrome doesn't do this, but ensure that users of the polyfill
|
||||
// are a bit more careful. Copy the internal parts of handler to prevent user changes.
|
||||
let unsafeHandler = handler;
|
||||
handler = {'get': null, 'set': null, 'apply': null, 'construct': null};
|
||||
for (let k in unsafeHandler) {
|
||||
if (!(k in handler)) {
|
||||
throw new TypeError(`Proxy polyfill does not support trap '${k}'`);
|
||||
}
|
||||
handler[k] = unsafeHandler[k];
|
||||
}
|
||||
if (typeof unsafeHandler == 'function') {
|
||||
// Allow handler to be a function (which has an 'apply' method). This matches what is
|
||||
// probably a bug in native versions. It treats the apply call as a trap to be configured.
|
||||
handler.apply = unsafeHandler.apply.bind(unsafeHandler);
|
||||
}
|
||||
|
||||
// Define proxy as this, or a Function (if either it's callable, or apply is set).
|
||||
// TODO(samthor): Closure compiler doesn't know about 'construct', attempts to rename it.
|
||||
let proxy = this;
|
||||
let isMethod = false;
|
||||
let targetIsFunction = typeof target == 'function';
|
||||
if (handler.apply || handler['construct'] || targetIsFunction) {
|
||||
proxy = function Proxy() {
|
||||
let usingNew = (this && this.constructor === proxy);
|
||||
throwRevoked(usingNew ? 'construct' : 'apply');
|
||||
|
||||
if (usingNew && handler['construct']) {
|
||||
return handler['construct'].call(this, target, arguments);
|
||||
} else if (!usingNew && handler.apply) {
|
||||
return handler.apply(target, this, arguments);
|
||||
} else if (targetIsFunction) {
|
||||
// since the target was a function, fallback to calling it directly.
|
||||
if (usingNew) {
|
||||
// inspired by answers to https://stackoverflow.com/q/1606797
|
||||
let all = Array.prototype.slice.call(arguments);
|
||||
all.unshift(target); // pass class as first arg to constructor, although irrelevant
|
||||
// nb. cast to convince Closure compiler that this is a constructor
|
||||
let f = /** @type {!Function} */ (target.bind.apply(target, all));
|
||||
return new f();
|
||||
}
|
||||
return target.apply(this, arguments);
|
||||
}
|
||||
throw new TypeError(usingNew ? 'not a constructor' : 'not a function');
|
||||
};
|
||||
isMethod = true;
|
||||
}
|
||||
|
||||
// Create default getters/setters. Create different code paths as handler.get/handler.set can't
|
||||
// change after creation.
|
||||
let getter = handler.get ? function(prop) {
|
||||
throwRevoked('get');
|
||||
return handler.get(this, prop, proxy);
|
||||
} : function(prop) {
|
||||
throwRevoked('get');
|
||||
return this[prop];
|
||||
};
|
||||
let setter = handler.set ? function(prop, value) {
|
||||
throwRevoked('set');
|
||||
let status = handler.set(this, prop, value, proxy);
|
||||
if (!status) {
|
||||
// TODO(samthor): If the calling code is in strict mode, throw TypeError.
|
||||
// It's (sometimes) possible to work this out, if this code isn't strict- try to load the
|
||||
// callee, and if it's available, that code is non-strict. However, this isn't exhaustive.
|
||||
}
|
||||
} : function(prop, value) {
|
||||
throwRevoked('set');
|
||||
this[prop] = value;
|
||||
};
|
||||
|
||||
// Clone direct properties (i.e., not part of a prototype).
|
||||
let propertyNames = Object.getOwnPropertyNames(target);
|
||||
if (target.__proto__) {
|
||||
propertyNames = propertyNames.concat(Object.getOwnPropertyNames(target.__proto__))
|
||||
}
|
||||
let propertyMap = {};
|
||||
propertyNames.forEach(function(prop) {
|
||||
if (isMethod && prop in proxy) {
|
||||
return; // ignore properties already here, e.g. 'bind', 'prototype' etc
|
||||
}
|
||||
let real = Object.getOwnPropertyDescriptor(target, prop);
|
||||
let desc = {
|
||||
enumerable: real && !!real.enumerable,
|
||||
get: getter.bind(target, prop),
|
||||
set: setter.bind(target, prop),
|
||||
};
|
||||
Object.defineProperty(proxy, prop, desc);
|
||||
propertyMap[prop] = true;
|
||||
});
|
||||
|
||||
// Set the prototype, or clone all prototype methods (always required if a getter is provided).
|
||||
// TODO(samthor): We don't allow prototype methods to be set. It's (even more) awkward.
|
||||
// An alternative here would be to _just_ clone methods to keep behavior consistent.
|
||||
let prototypeOk = true;
|
||||
if (Object.setPrototypeOf) {
|
||||
Object.setPrototypeOf(proxy, Object.getPrototypeOf(target));
|
||||
} else if (proxy.__proto__) {
|
||||
proxy.__proto__ = target.__proto__;
|
||||
} else {
|
||||
prototypeOk = false;
|
||||
}
|
||||
if (handler.get || !prototypeOk) {
|
||||
for (let k in target) {
|
||||
if (propertyMap[k]) {
|
||||
continue;
|
||||
}
|
||||
Object.defineProperty(proxy, k, {get: getter.bind(target, k)});
|
||||
}
|
||||
}
|
||||
|
||||
// The Proxy polyfill cannot handle adding new properties. Seal the target and proxy.
|
||||
Object.seal(target);
|
||||
Object.seal(proxy);
|
||||
|
||||
return proxy; // nb. if isMethod is true, proxy != this
|
||||
};
|
||||
|
||||
scope.Proxy.revocable = function(target, handler) {
|
||||
let p = new scope.Proxy(target, handler);
|
||||
return {'proxy': p, 'revoke': lastRevokeFn};
|
||||
};
|
||||
|
||||
scope.Proxy['revocable'] = scope.Proxy.revocable;
|
||||
scope['Proxy'] = scope.Proxy;
|
||||
})(typeof module !== 'undefined' && module['exports'] ? global : window);
|
@@ -1,319 +0,0 @@
|
||||
const EventEmitter = require('events');
|
||||
|
||||
const createProxy = require('../../js/preload/createProxy.js');
|
||||
const mainApiMgr = require('../../js/mainApiMgr.js');
|
||||
|
||||
mainApiMgr.shouldCheckValidWindow(false);
|
||||
|
||||
// need polyfil for html5 Proxy
|
||||
require('./proxy-polyfill');
|
||||
|
||||
class testInterface {
|
||||
constructor(arg1, arg2) {}
|
||||
|
||||
getArg1() {};
|
||||
|
||||
addToArg2(value) {}
|
||||
|
||||
get argumentOne() {}
|
||||
|
||||
set newArgOneValue(newValue) {}
|
||||
|
||||
static staticMethodSum(a, b) {}
|
||||
|
||||
static get staticGetter() {}
|
||||
|
||||
addEventListener(event,cb) {}
|
||||
|
||||
removeEventListener(event,cb) {}
|
||||
|
||||
emitEvent(event) {}
|
||||
|
||||
close() {}
|
||||
|
||||
destroy() {}
|
||||
}
|
||||
|
||||
class testImpl {
|
||||
constructor(arg1, arg2) {
|
||||
this._arg1 = arg1;
|
||||
this._arg2 = arg2;
|
||||
this.emitter = new EventEmitter();
|
||||
}
|
||||
|
||||
getArg1() {
|
||||
return this._arg1;
|
||||
};
|
||||
|
||||
addToArg2(value) {
|
||||
return this._arg2 + value;
|
||||
}
|
||||
|
||||
get argumentOne() {
|
||||
return this._arg1;
|
||||
}
|
||||
|
||||
set newArgOneValue(newValue) {
|
||||
this._arg1 = newValue;
|
||||
}
|
||||
|
||||
static staticMethodSum(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
static get staticGetter() {
|
||||
return 'hello world';
|
||||
}
|
||||
|
||||
addEventListener(event, cb) {
|
||||
this.emitter.on(event, cb);
|
||||
}
|
||||
|
||||
removeEventListener(event,cb) {
|
||||
this.emitter.removeListener(event, cb);
|
||||
}
|
||||
|
||||
emitEvent(event) {
|
||||
this.emitter.emit(event);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.emitter.emit('destroy');
|
||||
}
|
||||
|
||||
destroy() {}
|
||||
}
|
||||
|
||||
mainApiMgr.addNewInterface('testInterface', testImpl);
|
||||
|
||||
describe('proxy tests...', function() {
|
||||
var inst;
|
||||
var TestInterfaceProxy;
|
||||
|
||||
const arg1 = 3, arg2 = 2;
|
||||
|
||||
beforeEach(function() {
|
||||
TestInterfaceProxy = createProxy(testInterface);
|
||||
inst = new TestInterfaceProxy(arg1, arg2);
|
||||
});
|
||||
|
||||
test('getArg1 method', function(done) {
|
||||
inst.getArg1().then(function(result) {
|
||||
expect(result).toBe(arg1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('addToArg2 method', function(done) {
|
||||
inst.addToArg2(4).then(function(result) {
|
||||
expect(result).toBe(arg2 + 4);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('getter: argumentOne', function(done) {
|
||||
inst.argumentOne.then(function(result) {
|
||||
expect(result).toBe(arg1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('setter: newArgOneValue', function(done) {
|
||||
inst.newArgOneValue = 10;
|
||||
inst.argumentOne.then(function(result) {
|
||||
expect(result).toBe(10);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('static method', function(done) {
|
||||
TestInterfaceProxy.staticMethodSum(5, 6).then(function(result) {
|
||||
expect(result).toBe(11);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('static getter', function(done) {
|
||||
TestInterfaceProxy.staticGetter.then(function(result) {
|
||||
expect(result).toBe('hello world');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should call click handler', function(done) {
|
||||
inst.addEventListener('click', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
inst.emitEvent('click');
|
||||
});
|
||||
|
||||
test('should call click handler twice', function(done) {
|
||||
var timesCalled = 0;
|
||||
inst.addEventListener('click', function() {
|
||||
timesCalled++;
|
||||
if (timesCalled === 2) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
inst.emitEvent('click');
|
||||
inst.emitEvent('click');
|
||||
});
|
||||
|
||||
test('should only call close handler', function(done) {
|
||||
inst.addEventListener('click', function() {
|
||||
// shouldn't hit here
|
||||
expect(false).toBe(true);
|
||||
});
|
||||
|
||||
inst.addEventListener('close', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
inst.emitEvent('close');
|
||||
});
|
||||
|
||||
test('should not emit event addEventHandler', function(done) {
|
||||
inst.addEventListener('click', function() {
|
||||
// shouldn't hit here
|
||||
expect(false).toBe(true);
|
||||
});
|
||||
|
||||
inst.emitEvent('wrong-event');
|
||||
setTimeout(done, 500);
|
||||
});
|
||||
|
||||
test('should not call click handler after removed', function(done) {
|
||||
function onClick() {
|
||||
// shouldn't hit here
|
||||
expect(true).toBe(false);
|
||||
}
|
||||
inst.addEventListener('click', onClick);
|
||||
inst.removeEventListener('click', onClick);
|
||||
inst.emitEvent('click');
|
||||
setTimeout(done, 500);
|
||||
});
|
||||
|
||||
test('should call click handler after add, remove, add', function(done) {
|
||||
function onClick() {
|
||||
done();
|
||||
}
|
||||
inst.addEventListener('click', onClick);
|
||||
inst.removeEventListener('click', onClick);
|
||||
inst.addEventListener('click', onClick);
|
||||
inst.emitEvent('click');
|
||||
});
|
||||
});
|
||||
|
||||
describe('proxy test with multiple instances...', function() {
|
||||
var inst1, inst2;
|
||||
var TestInterfaceProxy;
|
||||
|
||||
const arg1 = 3, arg2 = 2;
|
||||
|
||||
beforeEach(function() {
|
||||
TestInterfaceProxy = createProxy(testInterface);
|
||||
inst1 = new TestInterfaceProxy(arg1, arg2);
|
||||
inst2 = new TestInterfaceProxy(arg1, arg2);
|
||||
});
|
||||
|
||||
test('should have indepdendent setters', function(done) {
|
||||
inst1.newArgOneValue = 10;
|
||||
inst2.newArgOneValue = 5;
|
||||
inst1.argumentOne.then(function(result) {
|
||||
expect(result).toBe(10);
|
||||
inst2.argumentOne.then(function(result) {
|
||||
expect(result).toBe(5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should only call event handler for inst2', function(done) {
|
||||
inst1.addEventListener('click', function() {
|
||||
// shouldn't hit here
|
||||
expect(true).toBe(false);
|
||||
});
|
||||
inst2.addEventListener('click', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
inst2.emitEvent('click');
|
||||
});
|
||||
|
||||
test('should call event handler for inst1 and inst2', function(done) {
|
||||
let isInst1Clicked = false;
|
||||
let isInst2Clicked = false;
|
||||
inst1.addEventListener('click', function() {
|
||||
if (isInst1Clicked) { return; }
|
||||
isInst1Clicked = true;
|
||||
clicked();
|
||||
});
|
||||
inst2.addEventListener('click', function() {
|
||||
if (isInst2Clicked) { return; }
|
||||
isInst2Clicked = true;
|
||||
clicked();
|
||||
});
|
||||
|
||||
function clicked() {
|
||||
if (isInst1Clicked && isInst1Clicked) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
inst1.emitEvent('click');
|
||||
inst2.emitEvent('click');
|
||||
});
|
||||
});
|
||||
|
||||
describe('proxy destroy tests...', function() {
|
||||
var inst, arg1 = 5, arg2 = 4;
|
||||
var TestInterfaceProxy;
|
||||
|
||||
beforeEach(function() {
|
||||
TestInterfaceProxy = createProxy(testInterface);
|
||||
inst = new TestInterfaceProxy(arg1, arg2);
|
||||
});
|
||||
|
||||
test('can not use inst after destroy is invoked', function(done) {
|
||||
inst.destroy();
|
||||
|
||||
inst.getArg1()
|
||||
.then(function() {
|
||||
// shouldn't get here
|
||||
})
|
||||
.catch(function(err) {
|
||||
expect(err).toBe('method called failed: calling obj is not present')
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('destroy from implementation side', function(done) {
|
||||
inst.close();
|
||||
|
||||
inst.getArg1()
|
||||
.then(function() {
|
||||
// shouldn't get here
|
||||
})
|
||||
.catch(function(err) {
|
||||
expect(err).toBe('method called failed: calling obj is not present')
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('after destroy should not raise events', function(done) {
|
||||
inst.destroy();
|
||||
|
||||
var clickedCalled = false;
|
||||
inst.addEventListener('click', function() {
|
||||
clickedCalled = true;
|
||||
});
|
||||
inst.emitEvent('click');
|
||||
setTimeout(function() {
|
||||
if (!clickedCalled) {
|
||||
done();
|
||||
}
|
||||
}, 200);
|
||||
})
|
||||
});
|
Reference in New Issue
Block a user