mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
Typescript (Fix spellchecker issue and bump electron version) (#626)
* Typescript - Fix spellchecker issues and bump electron version to 5.x * Typescript - Update unit test cases
This commit is contained in:
parent
e8cb240b92
commit
efe15967b5
140
demo/index.html
140
demo/index.html
@ -91,10 +91,13 @@
|
||||
<br>
|
||||
<hr>
|
||||
<p>Change language:<p>
|
||||
<button id='set-locale-en-US'>Change language to English - US</button>
|
||||
<button id='set-locale-ja-JP'>Change language to Japanese</button>
|
||||
<button id='set-locale-fr-FR'>Change language to French</button>
|
||||
<br>
|
||||
<select id="locale-select" name="locale">
|
||||
<option value="en-US">en-US</option>
|
||||
<option value="ja-JP">ja-JP</option>
|
||||
<option value="fr-FR">fr-FR</option>
|
||||
</select>
|
||||
<button id="changeLocale">Submit</button>
|
||||
<br>
|
||||
<hr>
|
||||
<p>Badge Count:<p>
|
||||
<button id='inc-badge'>increment badge count</button>
|
||||
@ -307,26 +310,66 @@
|
||||
});
|
||||
});
|
||||
|
||||
var setLocaleToEn = document.getElementById('set-locale-en-US');
|
||||
setLocaleToEn.addEventListener('click', function () {
|
||||
ssf.setLocale('en-US');
|
||||
document.location.reload();
|
||||
});
|
||||
var setLocaleToJa = document.getElementById('set-locale-ja-JP');
|
||||
setLocaleToJa.addEventListener('click', function () {
|
||||
ssf.setLocale('ja-JP');
|
||||
document.location.reload();
|
||||
});
|
||||
var setLocaleToFr = document.getElementById('set-locale-fr-FR');
|
||||
setLocaleToFr.addEventListener('click', function () {
|
||||
ssf.setLocale('fr-FR');
|
||||
document.location.reload();
|
||||
/**
|
||||
* Core post message api handler
|
||||
*/
|
||||
|
||||
const postMessage = (method, data) => {
|
||||
window.postMessage({ method, data }, '*');
|
||||
};
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
const { data, method } = event.data;
|
||||
switch (method) {
|
||||
case 'activity-callback':
|
||||
activityCallback(data);
|
||||
break;
|
||||
case 'media-source-callback':
|
||||
if (data.error) {
|
||||
if (data.error.message === 'User Cancelled') {
|
||||
console.error('user canceled');
|
||||
} else {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const constraints = {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
maxWidth: screen.width > 1920 ? 1920 : screen.width,
|
||||
maxHeight: screen.height > 1080 ? 1080 : screen.height,
|
||||
chromeMediaSourceId: data.source.id
|
||||
},
|
||||
optional: []
|
||||
};
|
||||
navigator.mediaDevices.getUserMedia({ video: constraints }).then((stream) => {
|
||||
handleStream(stream, data.source.display_id);
|
||||
});
|
||||
break;
|
||||
case 'screen-sharing-indicator-callback':
|
||||
if (!data || typeof data.type !== 'string' || !requestId) {
|
||||
console.error(`screen-sharing-indicator-callback invalid args ${data}`);
|
||||
} else {
|
||||
console.log(`screen sharing will be stopped`);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log(event.data);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Protocol handler
|
||||
*/
|
||||
if (window.ssf) {
|
||||
window.ssf.registerProtocolHandler();
|
||||
} else {
|
||||
postMessage(apiCmds.registerProtocolHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity Detection
|
||||
*/
|
||||
|
||||
const activityDetection = document.getElementById('activity-detection');
|
||||
const activityStatus = document.getElementById('activity-status');
|
||||
activityDetection.addEventListener('click', () => {
|
||||
@ -408,55 +451,20 @@
|
||||
};
|
||||
|
||||
/**
|
||||
* Core post message api handler
|
||||
* Locale api handler
|
||||
*/
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
const { data, method } = event.data;
|
||||
switch (method) {
|
||||
case 'activity-callback':
|
||||
activityCallback(data);
|
||||
break;
|
||||
case 'media-source-callback':
|
||||
|
||||
if (data.error) {
|
||||
if (data.error.message === 'User Cancelled') {
|
||||
console.error('user canceled');
|
||||
} else {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const constraints = {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
maxWidth: screen.width > 1920 ? 1920 : screen.width,
|
||||
maxHeight: screen.height > 1080 ? 1080 : screen.height,
|
||||
chromeMediaSourceId: data.source.id
|
||||
},
|
||||
optional: []
|
||||
};
|
||||
navigator.mediaDevices.getUserMedia({ video: constraints }).then((stream) => {
|
||||
handleStream(stream, data.source.display_id);
|
||||
});
|
||||
break;
|
||||
case 'screen-sharing-indicator-callback':
|
||||
if (!data || typeof data.type !== 'string' || !requestId) {
|
||||
console.error(`screen-sharing-indicator-callback invalid args ${data}`);
|
||||
} else {
|
||||
console.log(`screen sharing will be stopped`);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log(event.data);
|
||||
document.getElementById('changeLocale').addEventListener('click', () => {
|
||||
const locale = document.getElementById('locale-select').value;
|
||||
if (window.ssf) {
|
||||
window.ssf.setLocale(locale);
|
||||
} else {
|
||||
postMessage(apiCmds.setLocale, locale);
|
||||
}
|
||||
});
|
||||
|
||||
const postMessage = (method, data) => {
|
||||
window.postMessage({ method, data }, '*');
|
||||
};
|
||||
|
||||
/**
|
||||
* Download Manager api handler
|
||||
*/
|
||||
const download = (filename, text) => {
|
||||
const element = document.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||
@ -471,13 +479,13 @@
|
||||
};
|
||||
|
||||
// Start file download.
|
||||
document.getElementById("download-file1").addEventListener("click", () => {
|
||||
document.getElementById('download-file1').addEventListener('click', () => {
|
||||
const filename = "hello.txt";
|
||||
const text = document.getElementById("text-val").value;
|
||||
download(filename, text);
|
||||
}, false);
|
||||
|
||||
document.getElementById("download-file2").addEventListener("click", () => {
|
||||
document.getElementById('download-file2').addEventListener('click', () => {
|
||||
const filename = "bye.txt";
|
||||
const text = document.getElementById("text-val").value;
|
||||
download(filename, text);
|
||||
|
12
package.json
12
package.json
@ -81,7 +81,8 @@
|
||||
"devDependencies": {
|
||||
"@types/auto-launch": "^5.0.0",
|
||||
"@types/enzyme": "^3.9.0",
|
||||
"@types/ffi": "0.2.1",
|
||||
"@types/ffi-napi": "2.4.1",
|
||||
"@types/ref-napi": "1.4.0",
|
||||
"@types/jest": "23.3.12",
|
||||
"@types/lodash.omit": "^4.5.4",
|
||||
"@types/node": "10.11.4",
|
||||
@ -98,7 +99,7 @@
|
||||
"chromedriver": "2.45.0",
|
||||
"cross-env": "5.2.0",
|
||||
"del": "3.0.0",
|
||||
"electron": "4.0.8",
|
||||
"electron": "5.0.0-beta.7",
|
||||
"electron-builder": "20.38.4",
|
||||
"electron-builder-squirrel-windows": "20.38.3",
|
||||
"electron-chromedriver": "4.0.0-beta.1",
|
||||
@ -129,7 +130,6 @@
|
||||
"wdio-selenium-standalone-service": "0.0.12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/ffi": "0.2.1",
|
||||
"archiver": "3.0.0",
|
||||
"async.map": "0.5.2",
|
||||
"async.mapseries": "0.5.2",
|
||||
@ -138,9 +138,9 @@
|
||||
"electron-dl": "1.12.0",
|
||||
"electron-fetch": "1.3.0",
|
||||
"electron-log": "2.2.17",
|
||||
"electron-spellchecker": "git+https://github.com/symphonyoss/electron-spellchecker.git#v1.1.5",
|
||||
"electron-spellchecker": "git+https://github.com/symphonyoss/electron-spellchecker.git#v2.0.0",
|
||||
"enzyme-to-json": "^3.3.5",
|
||||
"ffi": "git+https://github.com/symphonyoss/node-ffi.git#v1.2.9",
|
||||
"ffi-napi": "2.4.5",
|
||||
"filesize": "3.6.1",
|
||||
"jimp": "0.6.0",
|
||||
"keymirror": "0.1.1",
|
||||
@ -151,7 +151,7 @@
|
||||
"node-osascript": "2.1.0",
|
||||
"react": "16.6.3",
|
||||
"react-dom": "^16.6.0",
|
||||
"ref": "1.3.5",
|
||||
"ref-napi": "1.4.1",
|
||||
"shell-path": "2.1.0",
|
||||
"winreg": "1.2.4"
|
||||
},
|
||||
|
@ -69,7 +69,11 @@ jest.mock('../src/common/logger', () => {
|
||||
jest.mock('../src/app/config-handler', () => {
|
||||
return {
|
||||
config: {
|
||||
getConfigFields: jest.fn(() => true),
|
||||
getConfigFields: jest.fn(() => {
|
||||
return {
|
||||
bringToFront: true,
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ describe('protocol handler', () => {
|
||||
});
|
||||
|
||||
it('protocol uri should be null by default', () => {
|
||||
expect(protocolHandlerInstance.protocolUri).toBeNull();
|
||||
expect(protocolHandlerInstance.protocolUri).toBe('symphony://?userId=22222');
|
||||
});
|
||||
|
||||
it('protocol action should be called when uri is correct', () => {
|
||||
|
@ -154,15 +154,15 @@ export class AppMenu {
|
||||
label: i18n.t('Edit')(),
|
||||
submenu:
|
||||
[
|
||||
this.assignRoleOrLabel('undo', i18n.t('Undo')()),
|
||||
this.assignRoleOrLabel('redo', i18n.t('Redo')()),
|
||||
this.assignRoleOrLabel({ role: 'undo', label: i18n.t('Undo')() }),
|
||||
this.assignRoleOrLabel({ role: 'redo', label: i18n.t('Redo')() }),
|
||||
this.buildSeparator(),
|
||||
this.assignRoleOrLabel('cut', i18n.t('Cut')()),
|
||||
this.assignRoleOrLabel('copy', i18n.t('Copy')()),
|
||||
this.assignRoleOrLabel('paste', i18n.t('Paste')()),
|
||||
this.assignRoleOrLabel('pasteandmatchstyle', i18n.t('Paste and Match Style')()),
|
||||
this.assignRoleOrLabel('delete', i18n.t('Delete')()),
|
||||
this.assignRoleOrLabel('selectall', i18n.t('Select All')()),
|
||||
this.assignRoleOrLabel({ role: 'cut', label: i18n.t('Cut')() }),
|
||||
this.assignRoleOrLabel({ role: 'copy', label: i18n.t('Copy')() }),
|
||||
this.assignRoleOrLabel({ role: 'paste', label: i18n.t('Paste')() }),
|
||||
this.assignRoleOrLabel({ role: 'pasteandmatchstyle', label: i18n.t('Paste and Match Style')() }),
|
||||
this.assignRoleOrLabel({ role: 'delete', label: i18n.t('Delete')() }),
|
||||
this.assignRoleOrLabel({ role: 'selectall', label: i18n.t('Select All')() }),
|
||||
],
|
||||
};
|
||||
|
||||
@ -190,11 +190,11 @@ export class AppMenu {
|
||||
label: i18n.t('Reload')(),
|
||||
},
|
||||
this.buildSeparator(),
|
||||
this.assignRoleOrLabel('resetzoom', i18n.t('Actual Size')()),
|
||||
this.assignRoleOrLabel('zoomin', i18n.t('Zoom In')()),
|
||||
this.assignRoleOrLabel('zoomout', i18n.t('Zoom Out')()),
|
||||
this.assignRoleOrLabel({ role: 'resetzoom', label: i18n.t('Actual Size')() }),
|
||||
this.assignRoleOrLabel({ role: 'zoomin', label: i18n.t('Zoom In')() }),
|
||||
this.assignRoleOrLabel({ role: 'zoomout', label: i18n.t('Zoom Out')() }),
|
||||
this.buildSeparator(),
|
||||
this.assignRoleOrLabel('togglefullscreen', i18n.t('Toggle Full Screen')()),
|
||||
this.assignRoleOrLabel({ role: 'togglefullscreen', label: i18n.t('Toggle Full Screen')() }),
|
||||
],
|
||||
};
|
||||
}
|
||||
@ -204,8 +204,8 @@ export class AppMenu {
|
||||
*/
|
||||
private buildWindowMenu(): Electron.MenuItemConstructorOptions {
|
||||
const submenu: MenuItemConstructorOptions[] = [
|
||||
this.assignRoleOrLabel('minimize', i18n.t('Minimize')()),
|
||||
this.assignRoleOrLabel('close', i18n.t('Close')()),
|
||||
this.assignRoleOrLabel({ role: 'minimize', label: i18n.t('Minimize')() }),
|
||||
this.assignRoleOrLabel({ role: 'close', label: i18n.t('Close')() }),
|
||||
this.buildSeparator(),
|
||||
{
|
||||
checked: launchOnStartup,
|
||||
@ -348,14 +348,14 @@ export class AppMenu {
|
||||
* @return {Object}.role The action of the menu item
|
||||
* @return {Object}.accelerator keyboard shortcuts and modifiers
|
||||
*/
|
||||
private assignRoleOrLabel(role: string, label: string) {
|
||||
private assignRoleOrLabel({ role, label }: MenuItemConstructorOptions): MenuItemConstructorOptions {
|
||||
if (isMac) {
|
||||
return label ? { role, label } : { role };
|
||||
}
|
||||
|
||||
if (isWindowsOS) {
|
||||
return label ? { role, label, accelerator: windowsAccelerator[ role ] || '' }
|
||||
: { role, accelerator: windowsAccelerator[ role ] || '' };
|
||||
return label ? { role, label, accelerator: role ? windowsAccelerator[ role ] : '' }
|
||||
: { role, accelerator: role ? windowsAccelerator[ role ] : '' };
|
||||
}
|
||||
|
||||
return label ? { role, label } : { role };
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { app } from 'electron';
|
||||
import { Library } from 'ffi';
|
||||
import { Library } from 'ffi-napi';
|
||||
import * as path from 'path';
|
||||
import { refType, types } from 'ref';
|
||||
import { refType, types } from 'ref-napi';
|
||||
|
||||
const execPath = path.dirname(app.getPath('exe'));
|
||||
import { isDevEnv, isMac } from '../common/env';
|
||||
|
@ -127,6 +127,11 @@ ipcMain.on(apiName.symphonyApi, (event: Electron.Event, arg: IApiArgs) => {
|
||||
downloadManagerAction(arg.type, arg.path);
|
||||
}
|
||||
break;
|
||||
case apiCmds.isMisspelled:
|
||||
if (typeof arg.word === 'string') {
|
||||
event.returnValue = windowHandler.spellchecker ? windowHandler.spellchecker.isMisspelled(arg.word) : false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import { config } from './config-handler';
|
||||
import './dialog-handler';
|
||||
import './main-api-handler';
|
||||
import { protocolHandler } from './protocol-handler';
|
||||
import { SpellChecker } from './spell-check-handler';
|
||||
import { ICustomBrowserWindow, windowHandler } from './window-handler';
|
||||
|
||||
const allowMultiInstance: string | boolean = getCommandLineArgs(process.argv, '--multiInstance', true) || isDevEnv;
|
||||
@ -29,8 +28,6 @@ if (isMac) {
|
||||
*/
|
||||
const startApplication = async () => {
|
||||
await app.whenReady();
|
||||
const spellchecker = new SpellChecker();
|
||||
logger.info(`initialized spellchecker module with locale ${spellchecker.locale}`);
|
||||
createAppCacheFile();
|
||||
windowHandler.showLoadingScreen();
|
||||
windowHandler.createApplication();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { apiName } from '../common/api-interface';
|
||||
import { isMac, isWindowsOS } from '../common/env';
|
||||
import { isMac } from '../common/env';
|
||||
import { getCommandLineArgs } from '../common/utils';
|
||||
import { activate } from './window-actions';
|
||||
|
||||
@ -61,7 +61,7 @@ class ProtocolHandler {
|
||||
*/
|
||||
public processArgv(argv?: string[]): void {
|
||||
const protocolUriFromArgv = getCommandLineArgs(argv || process.argv, protocol.SymphonyProtocol, false);
|
||||
if (isWindowsOS && protocolUriFromArgv) {
|
||||
if (protocolUriFromArgv) {
|
||||
this.sendProtocol(protocolUriFromArgv, false);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ export class SpellChecker {
|
||||
const contextMenuListener = (_event, info) => {
|
||||
if (this.locale !== i18n.getLocale()) {
|
||||
contextMenuBuilder.setAlternateStringFormatter(this.getStringTable());
|
||||
this.spellCheckHandler.updateContextMenuLocale(i18n.t('ContextMenu')());
|
||||
this.locale = i18n.getLocale();
|
||||
}
|
||||
contextMenuBuilder.showPopupMenu(info);
|
||||
@ -44,6 +43,17 @@ export class SpellChecker {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicts if the given text is misspelled
|
||||
* @param text
|
||||
*/
|
||||
public isMisspelled(text: string): boolean {
|
||||
if (!this.spellCheckHandler) {
|
||||
return false;
|
||||
}
|
||||
return this.spellCheckHandler.isMisspelled(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the string table for context menu
|
||||
*
|
||||
|
@ -14,6 +14,7 @@ import { notification } from '../renderer/notification';
|
||||
import { AppMenu } from './app-menu';
|
||||
import { handleChildWindow } from './child-window-handler';
|
||||
import { config, IConfig } from './config-handler';
|
||||
import { SpellChecker } from './spell-check-handler';
|
||||
import { monitorWindowActions } from './window-actions';
|
||||
import {
|
||||
createComponentWindow,
|
||||
@ -175,6 +176,7 @@ export class WindowHandler {
|
||||
public isOnline: boolean;
|
||||
public url: string | undefined;
|
||||
public willQuitApp: boolean = false;
|
||||
public spellchecker: SpellChecker | undefined;
|
||||
|
||||
private readonly windowOpts: ICustomBrowserWindowConstructorOpts;
|
||||
private readonly globalConfig: IConfig;
|
||||
@ -218,6 +220,10 @@ export class WindowHandler {
|
||||
* Starting point of the app
|
||||
*/
|
||||
public createApplication() {
|
||||
|
||||
this.spellchecker = new SpellChecker();
|
||||
logger.info(`initialized spellchecker module with locale ${this.spellchecker.locale}`);
|
||||
|
||||
// set window opts with additional config
|
||||
this.mainWindow = new BrowserWindow({
|
||||
...this.windowOpts, ...getBounds(this.config.mainWinPos, DEFAULT_WIDTH, DEFAULT_HEIGHT),
|
||||
|
@ -27,6 +27,7 @@ export enum apiCmds {
|
||||
notification = 'notification',
|
||||
closeNotification = 'close-notification',
|
||||
initMainWindow = 'init-main-window',
|
||||
isMisspelled = 'is-misspelled',
|
||||
}
|
||||
|
||||
export enum apiName {
|
||||
@ -35,6 +36,7 @@ export enum apiName {
|
||||
}
|
||||
|
||||
export interface IApiArgs {
|
||||
word: string;
|
||||
cmd: apiCmds;
|
||||
isOnline: boolean;
|
||||
count: number;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { ipcRenderer, webFrame } from 'electron';
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { apiCmds, apiName } from '../common/api-interface';
|
||||
@ -58,6 +58,18 @@ ipcRenderer.on('page-load', (_event, { locale, resources, origin, enableCustomTi
|
||||
ReactDOM.render(element, div);
|
||||
}
|
||||
|
||||
webFrame.setSpellCheckProvider('en-US', {
|
||||
spellCheck(words, callback) {
|
||||
const misspelled = words.filter((word) => {
|
||||
return ipcRenderer.sendSync(apiName.symphonyApi, {
|
||||
cmd: apiCmds.isMisspelled,
|
||||
word,
|
||||
});
|
||||
});
|
||||
callback(misspelled);
|
||||
},
|
||||
});
|
||||
|
||||
// injects snack bar
|
||||
const snackBar = React.createElement(SnackBar);
|
||||
const snackBarContainer = document.createElement( 'div' );
|
||||
|
Loading…
Reference in New Issue
Block a user