diff --git a/demo/win.html b/demo/win.html index e0a336ac..fe18a2ae 100644 --- a/demo/win.html +++ b/demo/win.html @@ -2,4 +2,23 @@ Test Window has been opened +

+ + +

+ +
+

Badge Count:

+ +
+ + diff --git a/installer/win/Symphony-x64.aip b/installer/win/Symphony-x64.aip index 9f81def6..cb16940e 100644 --- a/installer/win/Symphony-x64.aip +++ b/installer/win/Symphony-x64.aip @@ -43,14 +43,27 @@ + + + + + + + + + + + + + @@ -58,6 +71,7 @@ + @@ -100,27 +114,34 @@ + + + - + + + + + @@ -167,7 +188,10 @@ + + + @@ -180,6 +204,7 @@ + @@ -194,6 +219,10 @@ + + + + @@ -210,6 +239,8 @@ + + @@ -225,10 +256,12 @@ + + - + @@ -527,4 +560,4 @@ - + \ No newline at end of file diff --git a/js/menus/contextMenu.js b/js/menus/contextMenu.js deleted file mode 100644 index efd89b8a..00000000 --- a/js/menus/contextMenu.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; -var cm = require('electron-context-menu'); - -/** - * Creates & applies Right Click Context Menu based on - * electron-context-menu library o all windows. - * Unless activated on edittable field, Reload option is shown. - * Enabled Cut/Copy/Paste/Delete/Select all on text. - * Enabled Save Image on images - * Enabled Copy Link on href Link - * Inspect Element is not enabled. - */ -function contextMenu(browserWindow){ - cm({ - browserWindow, - - prepend: (params) => [ - { - role: 'reload', - enabled: params.isEditable === false, - visible: params.isEditable === false - }, - { - role: 'undo', - enabled: params.isEditable && params.editFlags.canUndu, - visible: params.isEditable - }, - { - role: 'redo', - enabled: params.isEditable && params.editFlags.canRedo, - visible: params.isEditable - } - ], - append: (params) => [ - { - role: 'delete', - enabled: params.isEditable && params.editFlags.canDelete, - visible: params.isEditable - }, - { - role: 'selectall', - enabled: params.isEditable && params.editFlags.canSelectAll, - visible: params.isEditable - } - ], - - showInspectElement: false - }); -} - -module.exports = contextMenu; \ No newline at end of file diff --git a/js/preload/preloadMain.js b/js/preload/preloadMain.js index 96cdef62..02977158 100644 --- a/js/preload/preloadMain.js +++ b/js/preload/preloadMain.js @@ -21,6 +21,25 @@ const getMediaSources = require('../desktopCapturer/getSources'); require('../downloadManager/downloadManager'); +// bug in electron preventing us from using spellchecker in pop outs +// https://github.com/electron/electron/issues/4025 +// so loading the spellchecker in try catch so that we don't +// block other method from loading +document.addEventListener('DOMContentLoaded', () => { + try { + /* eslint-disable global-require */ + const SpellCheckerHelper = require('../spellChecker/spellChecker').SpellCheckHelper; + /* eslint-enable global-require */ + // Method to initialize spell checker + const spellChecker = new SpellCheckerHelper(); + spellChecker.initializeSpellChecker(); + } catch (err) { + /* eslint-disable no-console */ + console.error('unable to load the spell checker module, hence, skipping the spell check feature ' + err); + /* eslint-enable no-console */ + } +}); + const nodeURL = require('url'); // hold ref so doesn't get GC'ed diff --git a/js/spellChecker/spellChecker.js b/js/spellChecker/spellChecker.js new file mode 100644 index 00000000..7af964f9 --- /dev/null +++ b/js/spellChecker/spellChecker.js @@ -0,0 +1,57 @@ +const { remote } = require('electron'); +const { MenuItem } = remote; +const { isMac } = require('./../utils/misc'); +const { SpellCheckHandler, ContextMenuListener, ContextMenuBuilder } = require('electron-spellchecker'); + +class SpellCheckHelper { + + constructor() { + this.spellCheckHandler = new SpellCheckHandler(); + } + + /** + * Method to initialize spell checker + */ + initializeSpellChecker() { + this.spellCheckHandler.attachToInput(); + + // This is only for window as in mac the + // language is switched w.r.t to the current system language. + // + // In windows we need to implement RxJS observable + // in order to switch language dynamically + if (!isMac) { + this.spellCheckHandler.switchLanguage('en-US'); + } + + const contextMenuBuilder = new ContextMenuBuilder(this.spellCheckHandler, null, false, SpellCheckHelper.processMenu); + this.contextMenuListener = new ContextMenuListener((info) => { + contextMenuBuilder.showPopupMenu(info); + }); + } + + /** + * Method to add default menu items to the + * menu that was generated by ContextMenuBuilder + * + * This method will be invoked by electron-spellchecker + * before showing the context menu + * + * @param menu + * @returns menu + */ + static processMenu(menu) { + menu.append(new MenuItem({ type: 'separator' })); + menu.append(new MenuItem({ + role: 'reload', + accelerator: 'CmdOrCtrl+R', + label: 'Reload' + })); + return menu; + } + +} + +module.exports = { + SpellCheckHelper: SpellCheckHelper +}; \ No newline at end of file diff --git a/js/windowMgr.js b/js/windowMgr.js index 00dad0c1..2ffba026 100644 --- a/js/windowMgr.js +++ b/js/windowMgr.js @@ -21,9 +21,6 @@ const throttle = require('./utils/throttle.js'); const { getConfigField, updateConfigField } = require('./config.js'); const { isMac, isNodeEnv } = require('./utils/misc'); -//context menu -const contextMenu = require('./menus/contextMenu.js'); - // show dialog when certificate errors occur require('./dialogs/showCertError.js'); @@ -319,7 +316,6 @@ function doCreateMainWindow(initialUrl, initialBounds) { } }); - contextMenu(mainWindow); } app.on('before-quit', function () { diff --git a/package.json b/package.json index f64c5ea1..f0c30cd8 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "unpacked-win": "npm run prebuild && npm run test && build --win --x64 --dir", "unpacked-win-x86": "npm run prebuild && npm run test && build --win --ia32", "prebuild": "npm run rebuild && npm run browserify-preload", - "browserify-preload": "browserify -o js/preload/_preloadMain.js -x electron --insert-global-vars=__filename,__dirname js/preload/preloadMain.js", + "browserify-preload": "browserify -o js/preload/_preloadMain.js -x electron --insert-global-vars=__filename,__dirname js/preload/preloadMain.js --exclude electron-spellchecker", "rebuild": "electron-rebuild -f", "test": "npm run lint && jest --verbose --testPathPattern test && npm run rebuild", "spectron-test": "jest --config tests/spectron/jest_spectron.json --runInBand && npm run rebuild", @@ -26,6 +26,7 @@ "transformIgnorePatterns": [] }, "build": { + "asarUnpack": ["node_modules/@paulcbetts/cld/build/Release/cld.node"], "files": [ "!coverage/*", "!installer/*", @@ -91,8 +92,8 @@ "async.map": "^0.5.2", "async.mapseries": "^0.5.2", "auto-launch": "^5.0.1", - "electron-context-menu": "^0.8.0", "electron-dl": "^1.9.0", + "electron-spellchecker": "^1.2.0", "electron-squirrel-startup": "^1.0.0", "filesize": "^3.5.10", "keymirror": "0.1.1", diff --git a/tests/spectron/spellChecker.spectron.js b/tests/spectron/spellChecker.spectron.js new file mode 100644 index 00000000..9588eb35 --- /dev/null +++ b/tests/spectron/spellChecker.spectron.js @@ -0,0 +1,122 @@ +const Application = require('./spectronSetup'); +const path = require('path'); +const {isMac} = require('../../js/utils/misc.js'); +const childProcess = require('child_process'); +let app = new Application({}); +let robot; + +describe('Tests for spellChecker', () => { + + let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; + jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut(); + + beforeAll((done) => { + childProcess.exec(`npm rebuild robotjs --target=${process.version} --build-from-source`, function () { + robot = require('robotjs'); + app.startApplication().then((startedApp) => { + app = startedApp; + done(); + }); + }); + }); + + afterAll((done) => { + if (app && app.isRunning()) { + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; + app.stop().then(() => { + done(); + }).catch((err) => { + console.log(err); + done(); + }); + } + }); + + it('should launch the app', (done) => { + return app.client.waitUntilWindowLoaded().then(() => { + return app.client.getWindowCount().then((count) => { + expect(count === 1).toBeTruthy(); + done(); + }).catch((err) => { + expect(err).toBeFalsy(); + done(); + }); + }).catch((err) => { + expect(err).toBeFalsy(); + done(); + }); + }); + + it('should check window count', () => { + return app.client.url('file:///' + path.join(__dirname, '..', '..', 'demo/index.html')); + }); + + it('should set the misspelled word', () => { + return app.client + .windowByIndex(0) + .setValue('#tag', 'comming ') + .getValue('#tag').then((value) => { + expect(value === 'comming ').toBeTruthy(); + }); + }); + + it('should bring the app to front in windows', (done) => { + if (!isMac) { + app.browserWindow.focus(); + app.browserWindow.restore(); + app.browserWindow.getBounds().then((bounds) => { + robot.setMouseDelay(100); + let x = bounds.x + 200; + let y = bounds.y + 200; + robot.moveMouseSmooth(x, y); + robot.mouseClick(); + done(); + }); + } else { + done(); + } + }); + + it('should invoke context menu ', (done) => { + if (isMac) { + app.browserWindow.getBounds().then((bounds) => { + let x = bounds.x + 45; + let y = bounds.y + 398; + + robot.moveMouseSmooth(x, y); + robot.setMouseDelay(200); + robot.mouseClick('left', true); + robot.mouseClick('right'); + robot.setKeyboardDelay(500); + robot.keyTap('down'); + robot.keyTap('down'); + robot.keyTap('enter'); + done(); + }); + } else { + app.browserWindow.getBounds().then((bounds) => { + let x = bounds.x + 55; + let y = bounds.y + 430; + + robot.moveMouseSmooth(x, y); + robot.setMouseDelay(200); + robot.mouseClick('left', true); + robot.mouseClick('right'); + robot.setKeyboardDelay(500); + robot.keyTap('down'); + robot.keyTap('down'); + robot.keyTap('enter'); + done(); + }); + } + }); + + it('should verify the text field', () => { + return app.client + .windowByIndex(0) + .getValue('#tag').then((value) => { + expect(value).toBe('coming '); + }); + }); + +}); \ No newline at end of file