diff --git a/.editorconfig b/.editorconfig
index e7066cfc7a..f2f826b09d 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,9 +8,12 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
-[*.{js,coffee,html,less,json}]
+[*.{js,coffee,html,less,css,json}]
+indent_style = tab
+
+[*.i18n.json]
indent_style = space
-indent_size = 4
+indent_size = 2
[*.md]
trim_trailing_whitespace = false
diff --git a/.eslintignore b/.eslintignore
index af602648ba..1d6cd2eeb9 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,6 +1,5 @@
-node_modules
-app
-e2e
-src/public/lib/bugsnag.js
-src/public/vendor/*
-scripts/istanbul-reporter.js
+/node_modules
+/app
+/src/public/lib/bugsnag.js
+/src/public/vendor/*
+/scripts/istanbul-reporter.js
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000000..17ad7212a5
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,9 @@
+{
+ "extends": [
+ "@rocket.chat/eslint-config"
+ ],
+ "globals": {
+ "_": false,
+ "Bugsnag": false
+ }
+}
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 03fb12fdd6..0000000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
- "parserOptions": {
- "sourceType": "module"
- },
- "env": {
- "browser": true,
- "commonjs": true,
- "es6": true,
- "node": true,
- "jquery": true
- },
- "rules": {
- "no-var": 2,
- "prefer-const": 2,
- "no-multi-spaces": 2,
- "no-eval": 2,
- "no-extend-native": 2,
- "no-multi-str": 2,
- "no-use-before-define": 2,
- "no-const-assign": 2,
- "no-cond-assign": 2,
- "no-constant-condition": 2,
- "no-control-regex": 2,
- "no-debugger": 2,
- "no-delete-var": 2,
- "no-dupe-keys": 2,
- "no-dupe-args": 2,
- "no-duplicate-case": 2,
- "no-empty": 2,
- "no-empty-character-class": 2,
- "no-ex-assign": 2,
- "no-extra-boolean-cast": 2,
- "no-extra-semi": 2,
- "no-fallthrough": 2,
- "no-func-assign": 2,
- "no-inner-declarations": [2, "functions"],
- "no-invalid-regexp": 2,
- "no-irregular-whitespace": 2,
- "no-mixed-spaces-and-tabs": 2,
- "no-sparse-arrays": 2,
- "no-negated-in-lhs": 2,
- "no-obj-calls": 2,
- "no-octal": 2,
- "no-redeclare": 2,
- "no-regex-spaces": 2,
- "no-undef": 2,
- "no-unreachable": 2,
- "no-unused-vars": [2, {
- "vars": "all",
- "args": "after-used"
- }],
- "no-lonely-if": 2,
- "no-trailing-spaces": 2,
- "complexity": [1, 31],
- "space-in-parens": [2, "never"],
- "space-before-function-paren": [2, "always"],
- "space-before-blocks": [2, "always"],
- "indent": [2, 4, {"SwitchCase": 1}],
- "keyword-spacing": 2,
- "block-spacing": 2,
- "brace-style": [2, "1tbs", { "allowSingleLine": true }],
- "computed-property-spacing": 2,
- "comma-spacing": 2,
- "comma-style": 2,
- "guard-for-in": 2,
- "wrap-iife": 2,
- "block-scoped-var": 2,
- "curly": [2, "all"],
- "eqeqeq": [2, "allow-null"],
- "new-cap": [2, {
- "capIsNewExceptions": ["Match.Optional", "Match.Maybe", "Match.ObjectIncluding"]
- }],
- "use-isnan": 2,
- "valid-typeof": 2,
- "linebreak-style": [2, "unix"],
- "semi": [2, "always"]
- },
- "globals": {
- "_" : false,
- "Bugsnag" : false
- }
-}
diff --git a/README.md b/README.md
index 678749fd64..6fac334a0b 100644
--- a/README.md
+++ b/README.md
@@ -127,7 +127,8 @@ Using [electron-mocha](https://github.com/jprichardson/electron-mocha) test runn
yarn e2e
```
-Using [mocha](https://mochajs.org/) test runner and [spectron](http://electron.atom.io/spectron/). This task searches for all files in `e2e` directory which respect pattern `*.e2e.js`.
+Using [mocha](https://mochajs.org/) test runner and [spectron](http://electron.atom.io/spectron/).
+This task searches for all files in `src/e2e` directory which respect pattern `*.e2e.js`.
### Code coverage
diff --git a/e2e/app.e2e.js b/e2e/app.e2e.js
deleted file mode 100644
index fcacec9847..0000000000
--- a/e2e/app.e2e.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { expect } from 'chai';
-import { app, startApp, stopApp } from './utils';
-
-import packageJson from '../package.json';
-
-describe('application', function () {
- before(startApp);
- after(stopApp);
-
- it('shows the main window', async function () {
- expect(await app.browserWindow.isVisible()).to.be.true;
- expect(await app.browserWindow.getTitle()).to.be.equal(packageJson.productName);
- });
-});
diff --git a/e2e/utils.js b/e2e/utils.js
deleted file mode 100644
index 5a7bed54cb..0000000000
--- a/e2e/utils.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import path from 'path';
-import electron from 'electron';
-import { Application } from 'spectron';
-
-export let app = null;
-let logFetchInterval = null;
-
-export async function startApp () {
- this.timeout(10000);
-
- app = new Application({
- path: electron,
- cwd: process.cwd(),
- args: [path.join(__dirname, '..')],
- quitTimeout: 5000,
- startTimeout: 5000,
- waitTimeout: 5000,
- });
-
- await app.start();
- await app.client.waitUntilWindowLoaded();
-
- logFetchInterval = setInterval(fetchLogs, 100);
-};
-
-export async function stopApp () {
- this.timeout(10000);
-
- if (app && app.isRunning()) {
- clearInterval(logFetchInterval);
- fetchLogs();
- await app.stop();
- app = null;
- }
-};
-
-const fetchLogs = async () => {
- const logs = await app.client.getMainProcessLogs();
- logs.forEach(log => console.log(log));
-};
-
-export const menuItem = (menuId, cb) => ({
- get exists() {
- return app.client.execute((menuId) => {
- const { Menu } = require('electron').remote;
- const appMenu = Menu.getApplicationMenu();
- const menuItem = appMenu.getMenuItemById(menuId);
- return !!menuItem;
- }, menuId).then(({ value }) => value);
- },
-
- get enabled() {
- return app.client.execute((menuId) => {
- const { Menu } = require('electron').remote;
- const appMenu = Menu.getApplicationMenu();
- const menuItem = appMenu.getMenuItemById(menuId);
- return menuItem.enabled;
- }, menuId).then(({ value }) => value);
- },
-
- get visible() {
- return app.client.execute((menuId) => {
- const { Menu } = require('electron').remote;
- const appMenu = Menu.getApplicationMenu();
- const menuItem = appMenu.getMenuItemById(menuId);
- return menuItem.visible;
- }, menuId).then(({ value }) => value);
- },
-
- get label() {
- return app.client.execute((menuId) => {
- const { Menu } = require('electron').remote;
- const appMenu = Menu.getApplicationMenu();
- const menuItem = appMenu.getMenuItemById(menuId);
- return menuItem.label;
- }, menuId).then(({ value }) => value);
- },
-
- click() {
- return app.client.execute((menuId) => {
- const { Menu } = require('electron').remote;
- const appMenu = Menu.getApplicationMenu();
- const menuItem = appMenu.getMenuItemById(menuId);
- menuItem.click();
- }, menuId);
- }
-});
diff --git a/package.json b/package.json
index f8c915dbac..bb842bab55 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,7 @@
"release": "gulp release --env=production",
"release-dev": "gulp release --env=development",
"release-mas-dev": "build --publish never --mac mas-dev --c.mac.provisioningProfile=Development.provisionprofile",
- "lint": "eslint .",
+ "lint": "eslint src",
"pretest": "gulp build-unit-tests --env=test",
"test": "electron-mocha app/specs.js.autogenerated --renderer --require source-map-support/register",
"coverage": "npm test -- -R scripts/istanbul-reporter",
@@ -38,6 +38,7 @@
"node-mac-notifier": "^1.1.0"
},
"devDependencies": {
+ "@rocket.chat/eslint-config": "^0.1.2",
"chai": "^4.1.2",
"conventional-changelog-cli": "^2.0.5",
"electron": "^2.0.9",
diff --git a/src/app.js b/src/app.js
index c165252b62..118ae5dbbe 100644
--- a/src/app.js
+++ b/src/app.js
@@ -1,15 +1,15 @@
import './branding/branding.js';
import { start } from './scripts/start';
import { remote } from 'electron';
-const app = remote.app;
+const { app } = remote;
Bugsnag.metaData = {
- // platformId: app.process.platform,
- // platformArch: app.process.arch,
- // electronVersion: app.process.versions.electron,
- version: app.getVersion()
- // platformVersion: cordova.platformVersion
- // build: appInfo.build
+ // platformId: app.process.platform,
+ // platformArch: app.process.arch,
+ // electronVersion: app.process.versions.electron,
+ version: app.getVersion(),
+ // platformVersion: cordova.platformVersion
+ // build: appInfo.build
};
Bugsnag.appVersion = app.getVersion();
diff --git a/src/background.js b/src/background.js
index 30db8bf544..3bbc5beecb 100644
--- a/src/background.js
+++ b/src/background.js
@@ -21,90 +21,90 @@ process.env.GOOGLE_API_KEY = 'AIzaSyADqUh_c1Qhji3Cp1NE43YrcpuPkmhXD-c';
const isMacOS = process.platform === 'darwin';
const unsetDefaultApplicationMenu = () => {
- if (!isMacOS) {
- Menu.setApplicationMenu(null);
- return;
- }
-
- const emptyMenuTemplate = [{
- submenu: [
- {
- label: i18n.__('Quit_App', app.getName()),
- accelerator: 'CommandOrControl+Q',
- click () {
- app.quit();
- }
- }
- ]
- }];
- Menu.setApplicationMenu(Menu.buildFromTemplate(emptyMenuTemplate));
+ if (!isMacOS) {
+ Menu.setApplicationMenu(null);
+ return;
+ }
+
+ const emptyMenuTemplate = [{
+ submenu: [
+ {
+ label: i18n.__('Quit_App', app.getName()),
+ accelerator: 'CommandOrControl+Q',
+ click() {
+ app.quit();
+ },
+ },
+ ],
+ }];
+ Menu.setApplicationMenu(Menu.buildFromTemplate(emptyMenuTemplate));
};
const setUserDataPath = () => {
- const appName = app.getName();
- const dirName = env.name === 'production' ? appName : `${ appName } (${ env.name })`;
+ const appName = app.getName();
+ const dirName = env.name === 'production' ? appName : `${ appName } (${ env.name })`;
- app.setPath('userData', path.join(app.getPath('appData'), dirName));
+ app.setPath('userData', path.join(app.getPath('appData'), dirName));
};
const migrateOlderVersionUserData = () => {
- const olderAppName = 'Rocket.Chat+';
- const dirName = env.name === 'production' ? olderAppName : `${ olderAppName } (${ env.name })`;
- const olderUserDataPath = path.join(app.getPath('appData'), dirName);
-
- try {
- jetpack.copy(olderUserDataPath, app.getPath('userData'), { overwrite: true });
- jetpack.remove(olderUserDataPath);
- } catch (e) {
- return;
- }
+ const olderAppName = 'Rocket.Chat+';
+ const dirName = env.name === 'production' ? olderAppName : `${ olderAppName } (${ env.name })`;
+ const olderUserDataPath = path.join(app.getPath('appData'), dirName);
+
+ try {
+ jetpack.copy(olderUserDataPath, app.getPath('userData'), { overwrite: true });
+ jetpack.remove(olderUserDataPath);
+ } catch (e) {
+ return;
+ }
};
const parseProtocolUrls = (args) =>
- args.filter(arg => /^rocketchat:\/\/./.test(arg))
- .map(uri => url.parse(uri))
- .map(({ hostname, pathname, query }) => {
- const { insecure } = querystring.parse(query);
- return `${ insecure === 'true' ? 'http' : 'https' }://${ hostname }${ pathname || '' }`;
- });
+ args.filter((arg) => /^rocketchat:\/\/./.test(arg))
+ .map((uri) => url.parse(uri))
+ .map(({ hostname, pathname, query }) => {
+ const { insecure } = querystring.parse(query);
+ return `${ insecure === 'true' ? 'http' : 'https' }://${ hostname }${ pathname || '' }`;
+ });
const addServers = (protocolUrls) => parseProtocolUrls(protocolUrls)
- .forEach(serverUrl => addServer(serverUrl));
+ .forEach((serverUrl) => addServer(serverUrl));
const isSecondInstance = app.makeSingleInstance((argv) => {
- addServers(argv.slice(2));
+ addServers(argv.slice(2));
});
if (isSecondInstance && !process.mas) {
- app.quit();
+ app.quit();
}
// macOS only
app.on('open-url', (event, url) => {
- event.preventDefault();
- addServers([ url ]);
+ event.preventDefault();
+ addServers([url]);
});
app.on('ready', () => {
- unsetDefaultApplicationMenu();
- setUserDataPath();
- migrateOlderVersionUserData();
+ unsetDefaultApplicationMenu();
+ setUserDataPath();
+ migrateOlderVersionUserData();
- if (!app.isDefaultProtocolClient('rocketchat')) {
- app.setAsDefaultProtocolClient('rocketchat');
- }
+ if (!app.isDefaultProtocolClient('rocketchat')) {
+ app.setAsDefaultProtocolClient('rocketchat');
+ }
- createMainWindow();
+ createMainWindow();
- getMainWindow().then(mainWindow => certificate.initWindow(mainWindow));
+ getMainWindow().then((mainWindow) => certificate.initWindow(mainWindow));
- autoUpdate();
+ autoUpdate();
});
app.on('window-all-closed', () => {
- app.quit();
+ app.quit();
});
ipcMain.on('getSystemIdleTime', (event) => {
- event.returnValue = idle.getIdleTime();
+ event.returnValue = idle.getIdleTime();
});
diff --git a/src/background/autoUpdate.js b/src/background/autoUpdate.js
index 63accbfcf5..f2e0ef9f16 100644
--- a/src/background/autoUpdate.js
+++ b/src/background/autoUpdate.js
@@ -8,127 +8,127 @@ const userDataDir = jetpack.cwd(app.getPath('userData'));
const updateSettingsFileName = 'update.json';
const loadUpdateSettings = (dir) => {
- try {
- return dir.read(updateSettingsFileName, 'json') || {};
- } catch (error) {
- console.error(error);
- return {};
- }
+ try {
+ return dir.read(updateSettingsFileName, 'json') || {};
+ } catch (error) {
+ console.error(error);
+ return {};
+ }
};
const appUpdateSettings = loadUpdateSettings(appDir);
const userUpdateSettings = loadUpdateSettings(userDataDir);
const updateSettings = (() => {
- const defaultUpdateSettings = { autoUpdate: true };
+ const defaultUpdateSettings = { autoUpdate: true };
- if (appUpdateSettings.forced) {
- return Object.assign({}, defaultUpdateSettings, appUpdateSettings);
- } else {
- return Object.assign({}, defaultUpdateSettings, appUpdateSettings, userUpdateSettings);
- }
+ if (appUpdateSettings.forced) {
+ return Object.assign({}, defaultUpdateSettings, appUpdateSettings);
+ } else {
+ return Object.assign({}, defaultUpdateSettings, appUpdateSettings, userUpdateSettings);
+ }
})();
delete updateSettings.forced;
const saveUpdateSettings = () => {
- if (appUpdateSettings.forced) {
- return;
- }
+ if (appUpdateSettings.forced) {
+ return;
+ }
- userDataDir.write(updateSettingsFileName, userUpdateSettings, { atomic: true });
+ userDataDir.write(updateSettingsFileName, userUpdateSettings, { atomic: true });
};
let checkForUpdatesEvent;
-function updateDownloaded () {
- dialog.showMessageBox({
- title: i18n.__('Update_ready'),
- message: i18n.__('Update_ready_message'),
- buttons: [
- i18n.__('Update_Install_Later'),
- i18n.__('Update_Install_Now')
- ],
- defaultId: 1
- }, (response) => {
- if (response === 0) {
- dialog.showMessageBox({
- title: i18n.__('Update_installing_later'),
- message: i18n.__('Update_installing_later_message')
- });
- } else {
- autoUpdater.quitAndInstall();
- setTimeout(() => app.quit(), 1000);
- }
- });
+function updateDownloaded() {
+ dialog.showMessageBox({
+ title: i18n.__('Update_ready'),
+ message: i18n.__('Update_ready_message'),
+ buttons: [
+ i18n.__('Update_Install_Later'),
+ i18n.__('Update_Install_Now'),
+ ],
+ defaultId: 1,
+ }, (response) => {
+ if (response === 0) {
+ dialog.showMessageBox({
+ title: i18n.__('Update_installing_later'),
+ message: i18n.__('Update_installing_later_message'),
+ });
+ } else {
+ autoUpdater.quitAndInstall();
+ setTimeout(() => app.quit(), 1000);
+ }
+ });
}
-function updateNotAvailable () {
- if (checkForUpdatesEvent) {
- checkForUpdatesEvent.sender.send('update-result', false);
- checkForUpdatesEvent = null;
- }
+function updateNotAvailable() {
+ if (checkForUpdatesEvent) {
+ checkForUpdatesEvent.sender.send('update-result', false);
+ checkForUpdatesEvent = null;
+ }
}
-function updateAvailable ({version}) {
- if (checkForUpdatesEvent) {
- checkForUpdatesEvent.sender.send('update-result', true);
- checkForUpdatesEvent = null;
- } else if (updateSettings.skip === version) {
- return;
- }
-
- let window = new BrowserWindow({
- title: i18n.__('Update_Available'),
- width: 600,
- height: 330,
- show : false,
- center: true,
- resizable: false,
- maximizable: false,
- minimizable: false
- });
-
- window.loadURL(`file://${__dirname}/public/update.html`);
- window.setMenuBarVisibility(false);
-
- window.webContents.on('did-finish-load', () => {
- window.webContents.send('new-version', version);
- window.show();
- });
-
- ipcMain.once('update-response', (e, type) => {
- switch (type) {
- case 'skip':
- userUpdateSettings.skip = version;
- saveUpdateSettings();
- dialog.showMessageBox({
- title: i18n.__('Update_skip'),
- message: i18n.__('Update_skip_message')
- }, () => window.close());
- break;
- case 'remind':
- dialog.showMessageBox({
- title: i18n.__('Update_remind'),
- message: i18n.__('Update_remind_message')
- }, () => window.close());
- break;
- case 'update':
- dialog.showMessageBox({
- title: i18n.__('Update_downloading'),
- message: i18n.__('Update_downloading_message')
- }, () => window.close());
- autoUpdater.downloadUpdate();
- break;
- }
- });
-
- window.on('closed', () => {
- window = null;
- ipcMain.removeAllListeners('update-response');
- });
+function updateAvailable({ version }) {
+ if (checkForUpdatesEvent) {
+ checkForUpdatesEvent.sender.send('update-result', true);
+ checkForUpdatesEvent = null;
+ } else if (updateSettings.skip === version) {
+ return;
+ }
+
+ let window = new BrowserWindow({
+ title: i18n.__('Update_Available'),
+ width: 600,
+ height: 330,
+ show : false,
+ center: true,
+ resizable: false,
+ maximizable: false,
+ minimizable: false,
+ });
+
+ window.loadURL(`file://${ __dirname }/public/update.html`);
+ window.setMenuBarVisibility(false);
+
+ window.webContents.on('did-finish-load', () => {
+ window.webContents.send('new-version', version);
+ window.show();
+ });
+
+ ipcMain.once('update-response', (e, type) => {
+ switch (type) {
+ case 'skip':
+ userUpdateSettings.skip = version;
+ saveUpdateSettings();
+ dialog.showMessageBox({
+ title: i18n.__('Update_skip'),
+ message: i18n.__('Update_skip_message'),
+ }, () => window.close());
+ break;
+ case 'remind':
+ dialog.showMessageBox({
+ title: i18n.__('Update_remind'),
+ message: i18n.__('Update_remind_message'),
+ }, () => window.close());
+ break;
+ case 'update':
+ dialog.showMessageBox({
+ title: i18n.__('Update_downloading'),
+ message: i18n.__('Update_downloading_message'),
+ }, () => window.close());
+ autoUpdater.downloadUpdate();
+ break;
+ }
+ });
+
+ window.on('closed', () => {
+ window = null;
+ ipcMain.removeAllListeners('update-response');
+ });
}
export const canUpdate = () =>
- (process.platform === 'linux' && Boolean(process.env.APPIMAGE)) ||
+ (process.platform === 'linux' && Boolean(process.env.APPIMAGE)) ||
(process.platform === 'win32' && !process.windowsStore) ||
(process.platform === 'darwin' && !process.mas);
@@ -137,28 +137,28 @@ export const canAutoUpdate = () => updateSettings.autoUpdate !== false;
export const canSetAutoUpdate = () => !appUpdateSettings.forced || appUpdateSettings.autoUpdate !== false;
export const setAutoUpdate = (canAutoUpdate) => {
- if (!canSetAutoUpdate()) {
- return;
- }
+ if (!canSetAutoUpdate()) {
+ return;
+ }
- updateSettings.autoUpdate = userUpdateSettings.autoUpdate = Boolean(canAutoUpdate);
- saveUpdateSettings();
+ updateSettings.autoUpdate = userUpdateSettings.autoUpdate = Boolean(canAutoUpdate);
+ saveUpdateSettings();
};
ipcMain.on('can-update', (event) => {
- event.returnValue = canUpdate();
+ event.returnValue = canUpdate();
});
ipcMain.on('can-auto-update', (event) => {
- event.returnValue = canAutoUpdate();
+ event.returnValue = canAutoUpdate();
});
ipcMain.on('can-set-auto-update', (event) => {
- event.returnValue = canSetAutoUpdate();
+ event.returnValue = canSetAutoUpdate();
});
ipcMain.on('set-auto-update', (event, canAutoUpdate) => {
- setAutoUpdate(canAutoUpdate);
+ setAutoUpdate(canAutoUpdate);
});
autoUpdater.autoDownload = false;
@@ -167,14 +167,14 @@ autoUpdater.on('update-not-available', updateNotAvailable);
autoUpdater.on('update-downloaded', updateDownloaded);
ipcMain.on('check-for-updates', (event) => {
- if (canAutoUpdate() && canUpdate()) {
- checkForUpdatesEvent = event;
- autoUpdater.checkForUpdates();
- }
+ if (canAutoUpdate() && canUpdate()) {
+ checkForUpdatesEvent = event;
+ autoUpdater.checkForUpdates();
+ }
});
export default () => {
- if (canAutoUpdate() && canUpdate()) {
- autoUpdater.checkForUpdates();
- }
+ if (canAutoUpdate() && canUpdate()) {
+ autoUpdater.checkForUpdates();
+ }
};
diff --git a/src/background/certificate.js b/src/background/certificate.js
index 3380ab5f87..85afe67d4e 100644
--- a/src/background/certificate.js
+++ b/src/background/certificate.js
@@ -4,108 +4,108 @@ import url from 'url';
import i18n from '../i18n/index.js';
class CertificateStore {
- initWindow (win) {
- this.storeFileName = 'certificate.json';
- this.userDataDir = jetpack.cwd(app.getPath('userData'));
-
- this.load();
-
- // Don't ask twice for same cert if loading multiple urls
- this.queued = {};
-
- this.window = win;
- app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
- event.preventDefault();
- if (this.isTrusted(url, certificate)) {
- callback(true);
- return;
- }
-
- if (this.queued[certificate.fingerprint]) {
- this.queued[certificate.fingerprint].push(callback);
- // Call the callback after approved/rejected
- return;
- } else {
- this.queued[certificate.fingerprint] = [callback];
- }
-
- let detail = `URL: ${url}\nError: ${error}`;
- if (this.isExisting(url)) {
- detail = i18n.__('Certificate_error_different', detail);
- }
-
- dialog.showMessageBox(this.window, {
- title: i18n.__('Certificate_error'),
- message: i18n.__('Certificate_error_message', certificate.issuerName),
- detail: detail,
- type: 'warning',
- buttons: [
- i18n.__('Yes'),
- i18n.__('No')
- ],
- cancelId: 1
- }, (response) => {
- if (response === 0) {
- this.add(url, certificate);
- this.save();
- if (webContents.getURL().indexOf('file://') === 0) {
- webContents.send('certificate-reload', url);
- }
- }
- //Call all queued callbacks with result
- this.queued[certificate.fingerprint].forEach(cb => cb(response === 0));
- delete this.queued[certificate.fingerprint];
- });
- });
- }
-
- load () {
- try {
- this.data = this.userDataDir.read(this.storeFileName, 'json');
- } catch (e) {
- console.error(e);
- this.data = {};
- }
-
- if (this.data === undefined) {
- this.clear();
- }
- }
-
- clear () {
- this.data = {};
- this.save();
- }
-
- save () {
- this.userDataDir.write(this.storeFileName, this.data, { atomic: true });
- }
-
- parseCertificate (certificate) {
- return certificate.issuerName + '\n' + certificate.data.toString();
- }
-
- getHost (certUrl) {
- return url.parse(certUrl).host;
- }
-
- add (certUrl, certificate) {
- const host = this.getHost(certUrl);
- this.data[host] = this.parseCertificate(certificate);
- }
-
- isExisting (certUrl) {
- const host = this.getHost(certUrl);
- return this.data.hasOwnProperty(host);
- }
-
- isTrusted (certUrl, certificate) {
- const host = this.getHost(certUrl);
- if (!this.isExisting(certUrl)) {
- return false;
- }
- return this.data[host] === this.parseCertificate(certificate);
- }
+ initWindow(win) {
+ this.storeFileName = 'certificate.json';
+ this.userDataDir = jetpack.cwd(app.getPath('userData'));
+
+ this.load();
+
+ // Don't ask twice for same cert if loading multiple urls
+ this.queued = {};
+
+ this.window = win;
+ app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
+ event.preventDefault();
+ if (this.isTrusted(url, certificate)) {
+ callback(true);
+ return;
+ }
+
+ if (this.queued[certificate.fingerprint]) {
+ this.queued[certificate.fingerprint].push(callback);
+ // Call the callback after approved/rejected
+ return;
+ } else {
+ this.queued[certificate.fingerprint] = [callback];
+ }
+
+ let detail = `URL: ${ url }\nError: ${ error }`;
+ if (this.isExisting(url)) {
+ detail = i18n.__('Certificate_error_different', detail);
+ }
+
+ dialog.showMessageBox(this.window, {
+ title: i18n.__('Certificate_error'),
+ message: i18n.__('Certificate_error_message', certificate.issuerName),
+ detail,
+ type: 'warning',
+ buttons: [
+ i18n.__('Yes'),
+ i18n.__('No'),
+ ],
+ cancelId: 1,
+ }, (response) => {
+ if (response === 0) {
+ this.add(url, certificate);
+ this.save();
+ if (webContents.getURL().indexOf('file://') === 0) {
+ webContents.send('certificate-reload', url);
+ }
+ }
+ // Call all queued callbacks with result
+ this.queued[certificate.fingerprint].forEach((cb) => cb(response === 0));
+ delete this.queued[certificate.fingerprint];
+ });
+ });
+ }
+
+ load() {
+ try {
+ this.data = this.userDataDir.read(this.storeFileName, 'json');
+ } catch (e) {
+ console.error(e);
+ this.data = {};
+ }
+
+ if (this.data === undefined) {
+ this.clear();
+ }
+ }
+
+ clear() {
+ this.data = {};
+ this.save();
+ }
+
+ save() {
+ this.userDataDir.write(this.storeFileName, this.data, { atomic: true });
+ }
+
+ parseCertificate(certificate) {
+ return `${ certificate.issuerName }\n${ certificate.data.toString() }`;
+ }
+
+ getHost(certUrl) {
+ return url.parse(certUrl).host;
+ }
+
+ add(certUrl, certificate) {
+ const host = this.getHost(certUrl);
+ this.data[host] = this.parseCertificate(certificate);
+ }
+
+ isExisting(certUrl) {
+ const host = this.getHost(certUrl);
+ return this.data.hasOwnProperty(host);
+ }
+
+ isTrusted(certUrl, certificate) {
+ const host = this.getHost(certUrl);
+ if (!this.isExisting(certUrl)) {
+ return false;
+ }
+ return this.data[host] === this.parseCertificate(certificate);
+ }
}
const certificateStore = new CertificateStore();
diff --git a/src/background/mainWindow.js b/src/background/mainWindow.js
index 145f490eb2..0412e5ad41 100644
--- a/src/background/mainWindow.js
+++ b/src/background/mainWindow.js
@@ -13,115 +13,115 @@ import env from '../env';
let mainWindow = null;
const mainWindowOptions = {
- width: 1000,
- height: 600,
- minWidth: 600,
- minHeight: 400,
- titleBarStyle: 'hidden',
- show: false
+ width: 1000,
+ height: 600,
+ minWidth: 600,
+ minHeight: 400,
+ titleBarStyle: 'hidden',
+ show: false,
};
const attachWindowStateHandling = (mainWindow) => {
- const mainWindowState = windowStateKeeper('main', mainWindowOptions);
-
- mainWindow.once('ready-to-show', () => mainWindowState.loadState(mainWindow));
-
- // macOS only
- app.on('activate', () => {
- mainWindow.show();
- });
-
- app.on('before-quit', () => {
- mainWindowState.saveState(mainWindow);
- mainWindowState.saveState.flush();
- mainWindow = null;
- });
-
- mainWindow.on('show', () => {
- mainWindowState.saveState(mainWindow);
- });
-
- mainWindow.on('close', function (event) {
- if (!mainWindow) {
- return;
- }
-
- event.preventDefault();
- if (mainWindow.isFullScreen()) {
- mainWindow.once('leave-full-screen', () => {
- mainWindow.hide();
- });
- mainWindow.setFullScreen(false);
- } else {
- mainWindow.hide();
- }
- mainWindowState.saveState(mainWindow);
- });
-
- mainWindow.on('resize', () => {
- mainWindowState.saveState(mainWindow);
- });
-
- mainWindow.on('move', () => {
- mainWindowState.saveState(mainWindow);
- });
+ const mainWindowState = windowStateKeeper('main', mainWindowOptions);
+
+ mainWindow.once('ready-to-show', () => mainWindowState.loadState(mainWindow));
+
+ // macOS only
+ app.on('activate', () => {
+ mainWindow.show();
+ });
+
+ app.on('before-quit', () => {
+ mainWindowState.saveState(mainWindow);
+ mainWindowState.saveState.flush();
+ mainWindow = null;
+ });
+
+ mainWindow.on('show', () => {
+ mainWindowState.saveState(mainWindow);
+ });
+
+ mainWindow.on('close', function(event) {
+ if (!mainWindow) {
+ return;
+ }
+
+ event.preventDefault();
+ if (mainWindow.isFullScreen()) {
+ mainWindow.once('leave-full-screen', () => {
+ mainWindow.hide();
+ });
+ mainWindow.setFullScreen(false);
+ } else {
+ mainWindow.hide();
+ }
+ mainWindowState.saveState(mainWindow);
+ });
+
+ mainWindow.on('resize', () => {
+ mainWindowState.saveState(mainWindow);
+ });
+
+ mainWindow.on('move', () => {
+ mainWindowState.saveState(mainWindow);
+ });
};
const attachIpcMessageHandling = (mainWindow) => {
- ipcMain.on('focus', () => {
- mainWindow.show();
- });
-
- ipcMain.on('update-taskbar-icon', (event, data, text) => {
- const img = nativeImage.createFromDataURL(data);
- mainWindow.setOverlayIcon(img, text);
- });
+ ipcMain.on('focus', () => {
+ mainWindow.show();
+ });
+
+ ipcMain.on('update-taskbar-icon', (event, data, text) => {
+ const img = nativeImage.createFromDataURL(data);
+ mainWindow.setOverlayIcon(img, text);
+ });
};
export const createMainWindow = (cb) => {
- if (mainWindow) {
- cb && cb(mainWindow);
- return;
- }
+ if (mainWindow) {
+ cb && cb(mainWindow);
+ return;
+ }
- mainWindow = new BrowserWindow(mainWindowOptions);
- attachWindowStateHandling(mainWindow);
- attachIpcMessageHandling(mainWindow);
+ mainWindow = new BrowserWindow(mainWindowOptions);
+ attachWindowStateHandling(mainWindow);
+ attachIpcMessageHandling(mainWindow);
- mainWindow.webContents.on('will-navigate', (event) => {
- event.preventDefault();
- });
+ mainWindow.webContents.on('will-navigate', (event) => {
+ event.preventDefault();
+ });
- const appUrl = url.format({
- pathname: path.join(__dirname, 'public', 'app.html'),
- protocol: 'file:',
- slashes: true
- });
+ const appUrl = url.format({
+ pathname: path.join(__dirname, 'public', 'app.html'),
+ protocol: 'file:',
+ slashes: true,
+ });
- mainWindow.loadURL(appUrl);
+ mainWindow.loadURL(appUrl);
- if (env.name === 'development') {
- mainWindow.openDevTools();
- }
+ if (env.name === 'development') {
+ mainWindow.openDevTools();
+ }
- cb && cb(mainWindow);
+ cb && cb(mainWindow);
};
export const getMainWindow = () => new Promise((resolve) => {
- if (app.isReady()) {
- createMainWindow(resolve);
- return;
- }
+ if (app.isReady()) {
+ createMainWindow(resolve);
+ return;
+ }
- app.on('ready', () => createMainWindow(resolve));
+ app.on('ready', () => createMainWindow(resolve));
});
export const addServer = (serverUrl) => getMainWindow().then((mainWindow) => {
- mainWindow.send('add-host', serverUrl);
+ mainWindow.send('add-host', serverUrl);
- mainWindow.show();
+ mainWindow.show();
- if (mainWindow.isMinimized()) {
- mainWindow.restore();
- }
+ if (mainWindow.isMinimized()) {
+ mainWindow.restore();
+ }
});
diff --git a/src/background/screenshare.js b/src/background/screenshare.js
index db99d4d856..db73809c7d 100644
--- a/src/background/screenshare.js
+++ b/src/background/screenshare.js
@@ -2,34 +2,34 @@ import { BrowserWindow, ipcMain } from 'electron';
let screenshareEvent;
ipcMain.on('screenshare', (event, sources) => {
- screenshareEvent = event;
- let mainWindow = new BrowserWindow({
- width: 776,
- height: 600,
- show : false,
- skipTaskbar: false
- });
+ screenshareEvent = event;
+ let mainWindow = new BrowserWindow({
+ width: 776,
+ height: 600,
+ show : false,
+ skipTaskbar: false,
+ });
- mainWindow.loadURL('file://'+__dirname+'/../public/screenshare.html');
+ mainWindow.loadURL(`file://${ __dirname }/../public/screenshare.html`);
- //window.openDevTools();
- mainWindow.webContents.on('did-finish-load', () => {
- mainWindow.webContents.send('sources', sources);
- mainWindow.show();
- });
+ // window.openDevTools();
+ mainWindow.webContents.on('did-finish-load', () => {
+ mainWindow.webContents.send('sources', sources);
+ mainWindow.show();
+ });
- mainWindow.on('closed', () => {
- mainWindow = null;
- if (screenshareEvent) {
- screenshareEvent.sender.send('screenshare-result', 'PermissionDeniedError');
- screenshareEvent = null;
- }
- });
+ mainWindow.on('closed', () => {
+ mainWindow = null;
+ if (screenshareEvent) {
+ screenshareEvent.sender.send('screenshare-result', 'PermissionDeniedError');
+ screenshareEvent = null;
+ }
+ });
});
ipcMain.on('source-result', (e, sourceId) => {
- if (screenshareEvent) {
- screenshareEvent.sender.send('screenshare-result', sourceId);
- screenshareEvent = null;
- }
+ if (screenshareEvent) {
+ screenshareEvent.sender.send('screenshare-result', sourceId);
+ screenshareEvent = null;
+ }
});
diff --git a/src/background/servers.js b/src/background/servers.js
index 66675a7b4c..3aeb07152d 100644
--- a/src/background/servers.js
+++ b/src/background/servers.js
@@ -3,21 +3,21 @@ import { app } from 'electron';
let servers = {};
export default {
- loadServers (s) {
- servers = s;
- },
+ loadServers(s) {
+ servers = s;
+ },
- getServers () {
- return servers;
- }
+ getServers() {
+ return servers;
+ },
};
-app.on('login', function (event, webContents, request, authInfo, callback) {
- for (const url of Object.keys(servers)) {
- const server = servers[url];
- if (request.url.indexOf(url) === 0 && server.username) {
- callback(server.username, server.password);
- break;
- }
- }
+app.on('login', function(event, webContents, request, authInfo, callback) {
+ for (const url of Object.keys(servers)) {
+ const server = servers[url];
+ if (request.url.indexOf(url) === 0 && server.username) {
+ callback(server.username, server.password);
+ break;
+ }
+ }
});
diff --git a/src/background/windowState.js b/src/background/windowState.js
index a1e77d1f38..0e9c974b82 100644
--- a/src/background/windowState.js
+++ b/src/background/windowState.js
@@ -6,63 +6,63 @@ import { app } from 'electron';
import jetpack from 'fs-jetpack';
import { debounce } from 'lodash';
-export default function (name, defaults) {
+export default function(name, defaults) {
- let state = {
- width: defaults.width,
- height: defaults.height
- };
+ let state = {
+ width: defaults.width,
+ height: defaults.height,
+ };
- const userDataDir = jetpack.cwd(app.getPath('userData'));
- const stateStoreFile = `window-state-${name}.json`;
+ const userDataDir = jetpack.cwd(app.getPath('userData'));
+ const stateStoreFile = `window-state-${ name }.json`;
- try {
- state = userDataDir.read(stateStoreFile, 'json') || state;
- } catch (err) {
- console.error(`Failed to load "${ name }" window state`);
- console.error(err);
- }
+ try {
+ state = userDataDir.read(stateStoreFile, 'json') || state;
+ } catch (err) {
+ console.error(`Failed to load "${ name }" window state`);
+ console.error(err);
+ }
- const saveState = function (window) {
- if (window.isDestroyed()) {
- return;
- }
+ const saveState = function(window) {
+ if (window.isDestroyed()) {
+ return;
+ }
- state.isMaximized = window.isMaximized();
- state.isMinimized = window.isMinimized();
- state.isHidden = !window.isMinimized() && !window.isVisible();
+ state.isMaximized = window.isMaximized();
+ state.isMinimized = window.isMinimized();
+ state.isHidden = !window.isMinimized() && !window.isVisible();
- if (!state.isMaximized && !state.isHidden) {
- [ state.x, state.y ] = window.getPosition();
- [ state.width, state.height ] = window.getSize();
- }
+ if (!state.isMaximized && !state.isHidden) {
+ [state.x, state.y] = window.getPosition();
+ [state.width, state.height] = window.getSize();
+ }
- userDataDir.write(stateStoreFile, state, { atomic: true });
- };
+ userDataDir.write(stateStoreFile, state, { atomic: true });
+ };
- const loadState = function (window) {
- if (this.x !== undefined && this.y !== undefined) {
- window.setPosition(this.x, this.y, false);
- }
+ const loadState = function(window) {
+ if (this.x !== undefined && this.y !== undefined) {
+ window.setPosition(this.x, this.y, false);
+ }
- if (this.width !== undefined && this.height !== undefined) {
- window.setSize(this.width, this.height, false);
- }
+ if (this.width !== undefined && this.height !== undefined) {
+ window.setSize(this.width, this.height, false);
+ }
- this.isMaximized ? window.maximize() : window.unmaximize();
- this.isMinimized ? window.minimize() : window.restore();
- this.isHidden ? window.hide() : window.show();
- };
+ this.isMaximized ? window.maximize() : window.unmaximize();
+ this.isMinimized ? window.minimize() : window.restore();
+ this.isHidden ? window.hide() : window.show();
+ };
- return {
- get x () { return state.x && Math.floor(state.x); },
- get y () { return state.y && Math.floor(state.y); },
- get width () { return state.width && Math.floor(state.width); },
- get height () { return state.height && Math.floor(state.height); },
- get isMaximized () { return state.isMaximized; },
- get isMinimized () { return state.isMinimized; },
- get isHidden () { return state.isHidden; },
- saveState: debounce(saveState, 1000), // see https://github.com/RocketChat/Rocket.Chat.Electron/issues/181
- loadState
- };
+ return {
+ get x() { return state.x && Math.floor(state.x); },
+ get y() { return state.y && Math.floor(state.y); },
+ get width() { return state.width && Math.floor(state.width); },
+ get height() { return state.height && Math.floor(state.height); },
+ get isMaximized() { return state.isMaximized; },
+ get isMinimized() { return state.isMinimized; },
+ get isHidden() { return state.isHidden; },
+ saveState: debounce(saveState, 1000), // see https://github.com/RocketChat/Rocket.Chat.Electron/issues/181
+ loadState,
+ };
}
diff --git a/src/e2e/.eslintrc b/src/e2e/.eslintrc
new file mode 100644
index 0000000000..22cafb1ac6
--- /dev/null
+++ b/src/e2e/.eslintrc
@@ -0,0 +1,8 @@
+{
+ "extends": [
+ "@rocket.chat/eslint-config"
+ ],
+ "env": {
+ "mocha": true
+ }
+}
diff --git a/src/e2e/app.e2e.js b/src/e2e/app.e2e.js
new file mode 100644
index 0000000000..dd7abc8d15
--- /dev/null
+++ b/src/e2e/app.e2e.js
@@ -0,0 +1,14 @@
+import { expect } from 'chai';
+import { app, startApp, stopApp } from './utils';
+
+import appManifest from '../../package.json';
+
+describe('application', function() {
+ before(startApp);
+ after(stopApp);
+
+ it('shows the main window', async function() {
+ expect(await app.browserWindow.isVisible()).to.be.true;
+ expect(await app.browserWindow.getTitle()).to.be.equal(appManifest.productName);
+ });
+});
diff --git a/src/e2e/utils.js b/src/e2e/utils.js
new file mode 100644
index 0000000000..60b40d410f
--- /dev/null
+++ b/src/e2e/utils.js
@@ -0,0 +1,87 @@
+import path from 'path';
+import electron from 'electron';
+import { Application } from 'spectron';
+
+export let app = null;
+let logFetchInterval = null;
+
+const fetchLogs = async() => {
+ const logs = await app.client.getMainProcessLogs();
+ logs.forEach((log) => console.log(log));
+};
+
+export async function startApp() {
+ this.timeout(10000);
+
+ app = new Application({
+ path: electron,
+ cwd: process.cwd(),
+ args: [path.join(__dirname, '..')],
+ quitTimeout: 5000,
+ startTimeout: 5000,
+ waitTimeout: 5000,
+ });
+
+ await app.start();
+ await app.client.waitUntilWindowLoaded();
+
+ logFetchInterval = setInterval(fetchLogs, 100);
+}
+
+export async function stopApp() {
+ this.timeout(10000);
+
+ if (app && app.isRunning()) {
+ clearInterval(logFetchInterval);
+ fetchLogs();
+ await app.stop();
+ app = null;
+ }
+}
+
+export const menuItem = (menuId) => ({
+ get exists() {
+ return app.client.execute((menuId) => {
+ const { Menu } = require('electron').remote;
+ const appMenu = Menu.getApplicationMenu();
+ const menuItem = appMenu.getMenuItemById(menuId);
+ return !!menuItem;
+ }, menuId).then(({ value }) => value);
+ },
+
+ get enabled() {
+ return app.client.execute((menuId) => {
+ const { Menu } = require('electron').remote;
+ const appMenu = Menu.getApplicationMenu();
+ const menuItem = appMenu.getMenuItemById(menuId);
+ return menuItem.enabled;
+ }, menuId).then(({ value }) => value);
+ },
+
+ get visible() {
+ return app.client.execute((menuId) => {
+ const { Menu } = require('electron').remote;
+ const appMenu = Menu.getApplicationMenu();
+ const menuItem = appMenu.getMenuItemById(menuId);
+ return menuItem.visible;
+ }, menuId).then(({ value }) => value);
+ },
+
+ get label() {
+ return app.client.execute((menuId) => {
+ const { Menu } = require('electron').remote;
+ const appMenu = Menu.getApplicationMenu();
+ const menuItem = appMenu.getMenuItemById(menuId);
+ return menuItem.label;
+ }, menuId).then(({ value }) => value);
+ },
+
+ click() {
+ return app.client.execute((menuId) => {
+ const { Menu } = require('electron').remote;
+ const appMenu = Menu.getApplicationMenu();
+ const menuItem = appMenu.getMenuItemById(menuId);
+ menuItem.click();
+ }, menuId);
+ },
+});
diff --git a/src/helpers/window.js b/src/helpers/window.js
index c9d242e59a..cb2c581dce 100644
--- a/src/helpers/window.js
+++ b/src/helpers/window.js
@@ -6,75 +6,75 @@
import { app, BrowserWindow, screen } from 'electron';
import jetpack from 'fs-jetpack';
-export default function (name, options) {
- const userDataDir = jetpack.cwd(app.getPath('userData'));
- const stateStoreFile = 'window-state-' + name +'.json';
- const defaultSize = {
- width: options.width,
- height: options.height
- };
- let state = {};
- const win = new BrowserWindow(Object.assign({}, options, state));
+export default function(name, options) {
+ const userDataDir = jetpack.cwd(app.getPath('userData'));
+ const stateStoreFile = `window-state-${ name }.json`;
+ const defaultSize = {
+ width: options.width,
+ height: options.height,
+ };
+ let state = {};
+ const win = new BrowserWindow(Object.assign({}, options, state));
- const restore = function () {
- let restoredState = {};
- try {
- restoredState = userDataDir.read(stateStoreFile, 'json');
- } catch (err) {
- // For some reason json can't be read (might be corrupted).
- // No worries, we have defaults.
- }
- return Object.assign({}, defaultSize, restoredState);
- };
+ const restore = function() {
+ let restoredState = {};
+ try {
+ restoredState = userDataDir.read(stateStoreFile, 'json');
+ } catch (err) {
+ // For some reason json can't be read (might be corrupted).
+ // No worries, we have defaults.
+ }
+ return Object.assign({}, defaultSize, restoredState);
+ };
- const getCurrentPosition = function () {
- const position = win.getPosition();
- const size = win.getSize();
- return {
- x: Math.floor(position[0]),
- y: Math.floor(position[1]),
- width: Math.floor(size[0]),
- height: Math.floor(size[1])
- };
- };
+ const getCurrentPosition = function() {
+ const position = win.getPosition();
+ const size = win.getSize();
+ return {
+ x: Math.floor(position[0]),
+ y: Math.floor(position[1]),
+ width: Math.floor(size[0]),
+ height: Math.floor(size[1]),
+ };
+ };
- const windowWithinBounds = function (windowState, bounds) {
- return windowState.x >= bounds.x &&
+ const windowWithinBounds = function(windowState, bounds) {
+ return windowState.x >= bounds.x &&
windowState.y >= bounds.y &&
windowState.x + windowState.width <= bounds.x + bounds.width &&
windowState.y + windowState.height <= bounds.y + bounds.height;
- };
+ };
- const resetToDefaults = function (/*windowState*/) {
- const bounds = screen.getPrimaryDisplay().bounds;
- return Object.assign({}, defaultSize, {
- x: (bounds.width - defaultSize.width) / 2,
- y: (bounds.height - defaultSize.height) / 2
- });
- };
+ const resetToDefaults = function(/* windowState*/) {
+ const { bounds } = screen.getPrimaryDisplay();
+ return Object.assign({}, defaultSize, {
+ x: (bounds.width - defaultSize.width) / 2,
+ y: (bounds.height - defaultSize.height) / 2,
+ });
+ };
- const ensureVisibleOnSomeDisplay = function (windowState) {
- const visible = screen.getAllDisplays().some(function (display) {
- return windowWithinBounds(windowState, display.bounds);
- });
- if (!visible) {
- // Window is partially or fully not visible now.
- // Reset it to safe defaults.
- return resetToDefaults(windowState);
- }
- return windowState;
- };
+ const ensureVisibleOnSomeDisplay = function(windowState) {
+ const visible = screen.getAllDisplays().some(function(display) {
+ return windowWithinBounds(windowState, display.bounds);
+ });
+ if (!visible) {
+ // Window is partially or fully not visible now.
+ // Reset it to safe defaults.
+ return resetToDefaults(windowState);
+ }
+ return windowState;
+ };
- const saveState = function () {
- if (!win.isMinimized() && !win.isMaximized()) {
- Object.assign(state, getCurrentPosition());
- }
- userDataDir.write(stateStoreFile, state, { atomic: true });
- };
+ const saveState = function() {
+ if (!win.isMinimized() && !win.isMaximized()) {
+ Object.assign(state, getCurrentPosition());
+ }
+ userDataDir.write(stateStoreFile, state, { atomic: true });
+ };
- state = ensureVisibleOnSomeDisplay(restore());
+ state = ensureVisibleOnSomeDisplay(restore());
- win.on('close', saveState);
+ win.on('close', saveState);
- return win;
+ return win;
}
diff --git a/src/i18n/index.js b/src/i18n/index.js
index d0800010ca..853b653434 100644
--- a/src/i18n/index.js
+++ b/src/i18n/index.js
@@ -13,61 +13,61 @@ let loadedLanguage = [];
* @param {number} chount Count to check for singular / plural (0-1,2-n)
* @returns {string} Translation in user language
*/
-function loadTranslation (phrase = '', count) {
- const loadedLanguageTranslation = loadedLanguage[phrase];
- let translation = loadedLanguageTranslation;
- if (loadedLanguageTranslation === undefined) {
- translation = phrase;
- } else if (loadedLanguageTranslation instanceof Object) {
- translation = loadedLanguageTranslation['one'];
- if (count > 1) {
- translation = loadedLanguageTranslation['multi'];
- }
- }
- return translation;
+function loadTranslation(phrase = '', count) {
+ const loadedLanguageTranslation = loadedLanguage[phrase];
+ let translation = loadedLanguageTranslation;
+ if (loadedLanguageTranslation === undefined) {
+ translation = phrase;
+ } else if (loadedLanguageTranslation instanceof Object) {
+ translation = loadedLanguageTranslation.one;
+ if (count > 1) {
+ translation = loadedLanguageTranslation.multi;
+ }
+ }
+ return translation;
}
class I18n {
- /**
+ /**
* Load users language if available, and fallback to english for any missing strings
* @constructor
*/
- constructor () {
- let dir = path.join(__dirname, '../i18n/lang');
- if (!fs.existsSync(dir)) {
- dir = path.join(__dirname, 'i18n/lang');
- }
- const defaultLocale = path.join(dir, 'en.i18n.json');
- loadedLanguage = JSON.parse(fs.readFileSync(defaultLocale, 'utf8'));
- const locale = path.join(dir, `${eApp.getLocale()}.i18n.json`);
- if (fs.existsSync(locale)) {
- const lang = JSON.parse(fs.readFileSync(locale, 'utf8'));
- loadedLanguage = Object.assign(loadedLanguage, lang);
- }
- }
+ constructor() {
+ let dir = path.join(__dirname, '../i18n/lang');
+ if (!fs.existsSync(dir)) {
+ dir = path.join(__dirname, 'i18n/lang');
+ }
+ const defaultLocale = path.join(dir, 'en.i18n.json');
+ loadedLanguage = JSON.parse(fs.readFileSync(defaultLocale, 'utf8'));
+ const locale = path.join(dir, `${ eApp.getLocale() }.i18n.json`);
+ if (fs.existsSync(locale)) {
+ const lang = JSON.parse(fs.readFileSync(locale, 'utf8'));
+ loadedLanguage = Object.assign(loadedLanguage, lang);
+ }
+ }
- /**
+ /**
* Get translation string
* @param {string} phrase The key for the translation string
* @param {...string|number} replacements List of replacements in template strings
* @return {string} Translation in users language
*/
- __ (phrase, ...replacements) {
- const translation = loadTranslation(phrase, 0);
- return util.format(translation, ...replacements);
- }
+ __(phrase, ...replacements) {
+ const translation = loadTranslation(phrase, 0);
+ return util.format(translation, ...replacements);
+ }
- /**
+ /**
* Get translation string
* @param {string} phrase The key for the translation string
* @param {number} count Count to check for singular / plural (0-1,2-n)
* @param {...string|number} replacements List of replacements in template strings
* @return {string} Translation in users language
*/
- pluralize (phrase, count, ...replacements) {
- const translation = loadTranslation(phrase, count);
- return util.format(translation, ...replacements);
- }
+ pluralize(phrase, count, ...replacements) {
+ const translation = loadTranslation(phrase, count);
+ return util.format(translation, ...replacements);
+ }
}
export default new I18n();
diff --git a/src/public/helpers/context_menu.js b/src/public/helpers/context_menu.js
index 02e2f8208b..8d025e03f0 100644
--- a/src/public/helpers/context_menu.js
+++ b/src/public/helpers/context_menu.js
@@ -2,59 +2,58 @@
// in all input fields and textareas across your app.
const i18n = require('../../i18n');
-(function () {
- 'use strict';
-
- const remote = require('electron').remote;
- const Menu = remote.Menu;
- const MenuItem = remote.MenuItem;
-
- const isAnyTextSelected = function () {
- return window.getSelection().toString() !== '';
- };
-
- const cut = new MenuItem({
- label: i18n.__('Cut'),
- click: function () {
- document.execCommand("cut");
- }
- });
-
- const copy = new MenuItem({
- label: i18n.__('Copy'),
- click: function () {
- document.execCommand("copy");
- }
- });
-
- const paste = new MenuItem({
- label: i18n.__('Paste'),
- click: function () {
- document.execCommand("paste");
- }
- });
-
- const normalMenu = new Menu();
- normalMenu.append(copy);
-
- const textEditingMenu = new Menu();
- textEditingMenu.append(cut);
- textEditingMenu.append(copy);
- textEditingMenu.append(paste);
-
- document.addEventListener('contextmenu', function (e) {
- switch (e.target.nodeName) {
- case 'TEXTAREA':
- case 'INPUT':
- e.preventDefault();
- textEditingMenu.popup(remote.getCurrentWindow());
- break;
- default:
- if (isAnyTextSelected()) {
- e.preventDefault();
- normalMenu.popup(remote.getCurrentWindow());
- }
- }
- }, false);
+(function() {
+ 'use strict';
+
+ const { remote } = require('electron');
+ const { Menu, MenuItem } = remote;
+
+ const isAnyTextSelected = function() {
+ return window.getSelection().toString() !== '';
+ };
+
+ const cut = new MenuItem({
+ label: i18n.__('Cut'),
+ click() {
+ document.execCommand('cut');
+ },
+ });
+
+ const copy = new MenuItem({
+ label: i18n.__('Copy'),
+ click() {
+ document.execCommand('copy');
+ },
+ });
+
+ const paste = new MenuItem({
+ label: i18n.__('Paste'),
+ click() {
+ document.execCommand('paste');
+ },
+ });
+
+ const normalMenu = new Menu();
+ normalMenu.append(copy);
+
+ const textEditingMenu = new Menu();
+ textEditingMenu.append(cut);
+ textEditingMenu.append(copy);
+ textEditingMenu.append(paste);
+
+ document.addEventListener('contextmenu', function(e) {
+ switch (e.target.nodeName) {
+ case 'TEXTAREA':
+ case 'INPUT':
+ e.preventDefault();
+ textEditingMenu.popup(remote.getCurrentWindow());
+ break;
+ default:
+ if (isAnyTextSelected()) {
+ e.preventDefault();
+ normalMenu.popup(remote.getCurrentWindow());
+ }
+ }
+ }, false);
}());
diff --git a/src/public/jitsi-preload.js b/src/public/jitsi-preload.js
index 6a2a31e45e..22a2d5d67d 100644
--- a/src/public/jitsi-preload.js
+++ b/src/public/jitsi-preload.js
@@ -5,8 +5,8 @@ const { remote } = require('electron');
const selfBrowserWindow = remote.getCurrentWindow();
selfBrowserWindow.webContents.once('dom-ready', () => {
- window.JitsiMeetElectron = {
- /**
+ window.JitsiMeetElectron = {
+ /**
* Get sources available for screensharing. The callback is invoked
* with an array of DesktopCapturerSources.
*
@@ -21,16 +21,16 @@ selfBrowserWindow.webContents.once('dom-ready', () => {
* default electron will return images with height and width of
* 150px.
*/
- obtainDesktopStreams (callback, errorCallback, options = {}) {
- electron.desktopCapturer.getSources(options,
- (error, sources) => {
- if (error) {
- errorCallback(error);
- return;
- }
+ obtainDesktopStreams(callback, errorCallback, options = {}) {
+ electron.desktopCapturer.getSources(options,
+ (error, sources) => {
+ if (error) {
+ errorCallback(error);
+ return;
+ }
- callback(sources);
- });
- }
- };
+ callback(sources);
+ });
+ },
+ };
});
diff --git a/src/public/lib/Notification.js b/src/public/lib/Notification.js
index 797c6dea5e..81fba05945 100644
--- a/src/public/lib/Notification.js
+++ b/src/public/lib/Notification.js
@@ -1,39 +1,39 @@
const { ipcRenderer, remote } = require('electron');
if (process.platform === 'darwin') {
- const NodeNotification = require('node-mac-notifier');
- window.Notification = class Notification extends NodeNotification {
- constructor (title, options) {
- options.bundleId = `chat.rocket`;
- super(title, options);
- this.addEventListener('click', (/*notification*/) => this.onclick());
- }
+ const NodeNotification = require('node-mac-notifier');
+ window.Notification = class Notification extends NodeNotification {
+ constructor(title, options) {
+ options.bundleId = 'chat.rocket';
+ super(title, options);
+ this.addEventListener('click', (/* notification*/) => this.onclick());
+ }
- static requestPermission () {
- return;
- }
+ static requestPermission() {
+ return;
+ }
- static get permission () {
- return 'granted';
- }
- };
+ static get permission() {
+ return 'granted';
+ }
+ };
}
class Notification extends window.Notification {
- constructor (title, options) {
- super(title, options);
- ipcRenderer.send('notification-shim', title, options);
+ constructor(title, options) {
+ super(title, options);
+ ipcRenderer.send('notification-shim', title, options);
- // Handle correct notification using unique tag
- ipcRenderer.once(`clicked-${options.tag}`, () => this.onclick());
- }
+ // Handle correct notification using unique tag
+ ipcRenderer.once(`clicked-${ options.tag }`, () => this.onclick());
+ }
- get onclick () {
- return super.onclick;
- }
+ get onclick() {
+ return super.onclick;
+ }
- /*
+ /*
set onclick (fn) {
const result = super.onclick = () => {
ipcRenderer.send('focus');
@@ -44,28 +44,28 @@ class Notification extends window.Notification {
}
*/
- set onclick (fn) {
- const result = super.onclick = () => {
- const currentWindow = remote.getCurrentWindow();
- if (process.platform === 'win32') {
- if (currentWindow.isVisible()) {
- currentWindow.focus();
- } else if (currentWindow.isMinimized()) {
- currentWindow.restore();
- } else {
- currentWindow.show();
- }
- } else if (currentWindow.isMinimized()) {
- currentWindow.restore();
- } else {
- currentWindow.show();
- }
+ set onclick(fn) {
+ const result = super.onclick = (...args) => {
+ const currentWindow = remote.getCurrentWindow();
+ if (process.platform === 'win32') {
+ if (currentWindow.isVisible()) {
+ currentWindow.focus();
+ } else if (currentWindow.isMinimized()) {
+ currentWindow.restore();
+ } else {
+ currentWindow.show();
+ }
+ } else if (currentWindow.isMinimized()) {
+ currentWindow.restore();
+ } else {
+ currentWindow.show();
+ }
- ipcRenderer.sendToHost('focus');
- fn.apply(this, arguments);
- };
- return result;
- }
+ ipcRenderer.sendToHost('focus');
+ fn.apply(this, args);
+ };
+ return result;
+ }
}
module.exports = Notification;
diff --git a/src/public/lib/SpellCheck.js b/src/public/lib/SpellCheck.js
index e8e7d707fe..0e79708b98 100644
--- a/src/public/lib/SpellCheck.js
+++ b/src/public/lib/SpellCheck.js
@@ -13,371 +13,375 @@ const isWindows = ['win32', 'win64'].indexOf(os.platform()) !== -1;
class SpellCheck {
- get userLanguage () {
- const lang = localStorage.getItem('userLanguage');
- if (lang) {
- return lang.replace('-', '_');
- }
- }
-
- get dictionaries () {
- const dictionaries = localStorage.getItem('spellcheckerDictionaries');
- if (dictionaries) {
- const result = JSON.parse(dictionaries);
- if (Array.isArray(result)) {
- return result;
- }
- }
- }
-
- constructor () {
- this.enabledDictionaries = [];
- this.contractions = this.getContractions();
- this.loadAvailableDictionaries();
- this.setEnabledDictionaries();
-
- this.languagesMenu = {
- label: i18n.__('Spelling_languages'),
- submenu: this.availableDictionaries.map((dictionary) => {
- const menu = {
- label: dictionary,
- type: 'checkbox',
- checked: this.enabledDictionaries.includes(dictionary),
- click: (menuItem) => {
- menu.checked = menuItem.checked;
- // If not using os dictionary then limit to only 1 language
- if (!this.multiLanguage && this.languagesMenu.submenu) {
- this.languagesMenu.submenu.forEach((m) => {
- if (m.label !== menuItem.label) {
- m.checked = false;
- }
- });
- }
- if (menuItem.checked) {
- this.setEnabled(dictionary);
- } else {
- this.disable(dictionary);
- }
- this.saveEnabledDictionaries();
- }
- };
- return menu;
- })
- };
-
- this.browseForLanguageMenu = new MenuItem({
- label: i18n.__('Browse_for_language'),
- click: () => {
- dialog.showOpenDialog({
- title: i18n.__('Open_Language_Dictionary'),
- defaultPath: this.dictionariesPath,
- filters: {name: 'Dictionaries', extensions: ['aff', 'dic']},
- properties: ['openFile', 'multiSelections']
- },
- (filePaths) => { this.installDictionariesFromPaths(filePaths); }
- );
- }
- });
- }
-
- /**
+ get userLanguage() {
+ const lang = localStorage.getItem('userLanguage');
+ if (lang) {
+ return lang.replace('-', '_');
+ }
+
+ return undefined;
+ }
+
+ get dictionaries() {
+ const dictionaries = localStorage.getItem('spellcheckerDictionaries');
+ if (dictionaries) {
+ const result = JSON.parse(dictionaries);
+ if (Array.isArray(result)) {
+ return result;
+ }
+ }
+
+ return undefined;
+ }
+
+ constructor() {
+ this.enabledDictionaries = [];
+ this.contractions = this.getContractions();
+ this.loadAvailableDictionaries();
+ this.setEnabledDictionaries();
+
+ this.languagesMenu = {
+ label: i18n.__('Spelling_languages'),
+ submenu: this.availableDictionaries.map((dictionary) => {
+ const menu = {
+ label: dictionary,
+ type: 'checkbox',
+ checked: this.enabledDictionaries.includes(dictionary),
+ click: (menuItem) => {
+ menu.checked = menuItem.checked;
+ // If not using os dictionary then limit to only 1 language
+ if (!this.multiLanguage && this.languagesMenu.submenu) {
+ this.languagesMenu.submenu.forEach((m) => {
+ if (m.label !== menuItem.label) {
+ m.checked = false;
+ }
+ });
+ }
+ if (menuItem.checked) {
+ this.setEnabled(dictionary);
+ } else {
+ this.disable(dictionary);
+ }
+ this.saveEnabledDictionaries();
+ },
+ };
+ return menu;
+ }),
+ };
+
+ this.browseForLanguageMenu = new MenuItem({
+ label: i18n.__('Browse_for_language'),
+ click: () => {
+ dialog.showOpenDialog({
+ title: i18n.__('Open_Language_Dictionary'),
+ defaultPath: this.dictionariesPath,
+ filters: { name: 'Dictionaries', extensions: ['aff', 'dic'] },
+ properties: ['openFile', 'multiSelections'],
+ },
+ (filePaths) => { this.installDictionariesFromPaths(filePaths); }
+ );
+ },
+ });
+ }
+
+ /**
* Set enabled dictionaries on load
* Either sets enabled dictionaries to saved preferences, or enables the first
* dictionary that is valid based on system (defaults to en_US)
*/
- setEnabledDictionaries () {
- const dictionaries = this.dictionaries;
- if (dictionaries) {
- // Dictionary disabled
- if (dictionaries.length === 0) {
- return;
- }
- if (this.setEnabled(dictionaries)) {
- return;
- }
- }
-
- if (this.userLanguage) {
- if (this.setEnabled(this.userLanguage)) {
- return;
- }
- if (this.userLanguage.includes('_') && this.setEnabled(this.userLanguage.split('_')[0])) {
- return;
- }
- }
-
- const navigatorLanguage = navigator.language.replace('-', '_');
- if (this.setEnabled(navigatorLanguage)) {
- return;
- }
-
- if (navigatorLanguage.includes('_') && this.setEnabled(navigatorLanguage.split('_')[0])) {
- return;
- }
-
- if (this.setEnabled('en_US')) {
- return;
- }
-
- if (!this.setEnabled('en')) {
- console.info('Unable to set a language for the spell checker - Spell checker is disabled');
- }
-
- }
-
- loadAvailableDictionaries () {
- this.availableDictionaries = checker.getAvailableDictionaries().sort();
- if (this.availableDictionaries.length === 0) {
- this.multiLanguage = false;
- // Dictionaries path is correct for build
- this.dictionariesPath = path.join(remote.app.getAppPath(), '../dictionaries');
- this.getDictionariesFromInstallDirectory();
- } else {
- this.multiLanguage = !isWindows;
- this.availableDictionaries = this.availableDictionaries.map((dict) => dict.replace('-', '_'));
- }
- }
-
- /**
+ setEnabledDictionaries() {
+ const { dictionaries } = this;
+ if (dictionaries) {
+ // Dictionary disabled
+ if (dictionaries.length === 0) {
+ return;
+ }
+ if (this.setEnabled(dictionaries)) {
+ return;
+ }
+ }
+
+ if (this.userLanguage) {
+ if (this.setEnabled(this.userLanguage)) {
+ return;
+ }
+ if (this.userLanguage.includes('_') && this.setEnabled(this.userLanguage.split('_')[0])) {
+ return;
+ }
+ }
+
+ const navigatorLanguage = navigator.language.replace('-', '_');
+ if (this.setEnabled(navigatorLanguage)) {
+ return;
+ }
+
+ if (navigatorLanguage.includes('_') && this.setEnabled(navigatorLanguage.split('_')[0])) {
+ return;
+ }
+
+ if (this.setEnabled('en_US')) {
+ return;
+ }
+
+ if (!this.setEnabled('en')) {
+ console.info('Unable to set a language for the spell checker - Spell checker is disabled');
+ }
+
+ }
+
+ loadAvailableDictionaries() {
+ this.availableDictionaries = checker.getAvailableDictionaries().sort();
+ if (this.availableDictionaries.length === 0) {
+ this.multiLanguage = false;
+ // Dictionaries path is correct for build
+ this.dictionariesPath = path.join(remote.app.getAppPath(), '../dictionaries');
+ this.getDictionariesFromInstallDirectory();
+ } else {
+ this.multiLanguage = !isWindows;
+ this.availableDictionaries = this.availableDictionaries.map((dict) => dict.replace('-', '_'));
+ }
+ }
+
+ /**
* Installs all of the dictionaries specified in filePaths
* Copies dicts into our dictionary path and adds them to availableDictionaries
*/
- installDictionariesFromPaths (dictionaryPaths) {
- for (const dictionaryPath of dictionaryPaths) {
- const dictionaryFileName = dictionaryPath.split(path.sep).pop();
- const dictionaryName = dictionaryFileName.slice(0, -4);
- const newDictionaryPath = path.join(this.dictionariesPath, dictionaryFileName);
-
- this.copyDictionaryToInstallDirectory(dictionaryName, dictionaryPath, newDictionaryPath);
- }
- }
-
- copyDictionaryToInstallDirectory (dictionaryName, oldPath, newPath) {
- fs.createReadStream(oldPath).pipe(fs.createWriteStream(newPath)
- .on('error', (errorMessage) => {
- dialog.showErrorBox(i18n.__('Error'), i18n.__('Error copying dictionary file') + `: ${dictionaryName}`);
- console.error(errorMessage);
- })
- .on('finish', () => {
- if (!this.availableDictionaries.includes(dictionaryName)) {
- this.availableDictionaries.push(dictionaryName);
- }
- }));
- }
-
- getDictionariesFromInstallDirectory () {
- if (this.dictionariesPath) {
- const fileNames = fs.readdirSync(this.dictionariesPath);
- for (const fileName of fileNames) {
- const dictionaryExtension = fileName.slice(-3);
- const dictionaryName = fileName.slice(0, -4);
- if (!this.availableDictionaries.includes(dictionaryName)
+ installDictionariesFromPaths(dictionaryPaths) {
+ for (const dictionaryPath of dictionaryPaths) {
+ const dictionaryFileName = dictionaryPath.split(path.sep).pop();
+ const dictionaryName = dictionaryFileName.slice(0, -4);
+ const newDictionaryPath = path.join(this.dictionariesPath, dictionaryFileName);
+
+ this.copyDictionaryToInstallDirectory(dictionaryName, dictionaryPath, newDictionaryPath);
+ }
+ }
+
+ copyDictionaryToInstallDirectory(dictionaryName, oldPath, newPath) {
+ fs.createReadStream(oldPath).pipe(fs.createWriteStream(newPath)
+ .on('error', (errorMessage) => {
+ dialog.showErrorBox(i18n.__('Error'), `${ i18n.__('Error copying dictionary file') }: ${ dictionaryName }`);
+ console.error(errorMessage);
+ })
+ .on('finish', () => {
+ if (!this.availableDictionaries.includes(dictionaryName)) {
+ this.availableDictionaries.push(dictionaryName);
+ }
+ }));
+ }
+
+ getDictionariesFromInstallDirectory() {
+ if (this.dictionariesPath) {
+ const fileNames = fs.readdirSync(this.dictionariesPath);
+ for (const fileName of fileNames) {
+ const dictionaryExtension = fileName.slice(-3);
+ const dictionaryName = fileName.slice(0, -4);
+ if (!this.availableDictionaries.includes(dictionaryName)
&& (dictionaryExtension === 'aff' || dictionaryExtension === 'dic')) {
- this.availableDictionaries.push(dictionaryName);
- }
- }
- }
- }
-
- setEnabled (dictionaries) {
- dictionaries = [].concat(dictionaries);
- let result = false;
- for (let i = 0; i < dictionaries.length; i++) {
- if (this.availableDictionaries.includes(dictionaries[i])) {
- result = true;
- this.enabledDictionaries.push(dictionaries[i]);
- // If using Hunspell or Windows then only allow 1 language for performance reasons
- if (!this.multiLanguage) {
- this.enabledDictionaries = [dictionaries[i]];
- checker.setDictionary(dictionaries[i], this.dictionariesPath);
- return true;
- }
- }
- }
- return result;
- }
-
- disable (dictionary) {
- const pos = this.enabledDictionaries.indexOf(dictionary);
- if (pos !== -1) {
- this.enabledDictionaries.splice(pos, 1);
- }
- }
-
- getContractions () {
- const contractions = [
- "ain't", "aren't", "can't", "could've", "couldn't", "couldn't've", "didn't", "doesn't", "don't", "hadn't",
- "hadn't've", "hasn't", "haven't", "he'd", "he'd've", "he'll", "he's", "how'd", "how'll", "how's", "I'd",
- "I'd've", "I'll", "I'm", "I've", "isn't", "it'd", "it'd've", "it'll", "it's", "let's", "ma'am", "mightn't",
- "mightn't've", "might've", "mustn't", "must've", "needn't", "not've", "o'clock", "shan't", "she'd", "she'd've",
- "she'll", "she's", "should've", "shouldn't", "shouldn't've", "that'll", "that's", "there'd", "there'd've",
- "there're", "there's", "they'd", "they'd've", "they'll", "they're", "they've", "wasn't", "we'd", "we'd've",
- "we'll", "we're", "we've", "weren't", "what'll", "what're", "what's", "what've", "when's", "where'd",
- "where's", "where've", "who'd", "who'll", "who're", "who's", "who've", "why'll", "why're", "why's", "won't",
- "would've", "wouldn't", "wouldn't've", "y'all", "y'all'd've", "you'd", "you'd've", "you'll", "you're", "you've"
- ];
-
- const contractionMap = contractions.reduce((acc, word) => {
- acc[word.replace(/'.*/, '')] = true;
- return acc;
- }, {});
-
- return contractionMap;
- }
-
- enable () {
- webFrame.setSpellCheckProvider('', false, {
- spellCheck: (text) => this.isCorrect(text)
- });
-
- this.setupContextMenuListener();
- }
-
- getMenu () {
- return [
- {
- label: i18n.__('Undo'),
- role: 'undo'
- },
- {
- label: i18n.__('Redo'),
- role: 'redo'
- },
- {
- type: 'separator'
- },
- {
- label: i18n.__('Cut'),
- role: 'cut',
- accelerator: 'CommandOrControl+X',
- },
- {
- label: i18n.__('Copy'),
- role: 'copy',
- accelerator: 'CommandOrControl+C',
- },
- {
- label: i18n.__('Paste'),
- role: 'paste',
- accelerator: 'CommandOrControl+V',
- },
- {
- label: i18n.__('Select_All'),
- role: 'selectall',
- accelerator: 'CommandOrControl+A',
- }
- ];
- }
-
- saveEnabledDictionaries () {
- localStorage.setItem('spellcheckerDictionaries', JSON.stringify(this.enabledDictionaries));
- }
-
- isCorrect (text) {
- if (!this.enabledDictionaries.length || this.contractions[text.toLocaleLowerCase()]) {
- return true;
- }
-
- if (this.multiLanguage) {
- for (let i = 0; i < this.enabledDictionaries.length; i++) {
- checker.setDictionary(this.enabledDictionaries[i]);
- if (!checker.isMisspelled(text)) {
- return true;
- }
- }
- } else {
- return !checker.isMisspelled(text);
- }
- return false;
- }
-
- getCorrections (text) {
- if (!this.multiLanguage) {
- return checker.getCorrectionsForMisspelling(text);
- }
-
- const allCorrections = this.enabledDictionaries.map((dictionary) => {
- checker.setDictionary(dictionary);
- return checker.getCorrectionsForMisspelling(text);
- }).filter((c) => c.length > 0);
-
- const length = Math.max(...allCorrections.map((a) => a.length));
-
- // Get the best suggestions of each language first
- const corrections = [];
- for (let i = 0; i < length; i++) {
- corrections.push(...allCorrections.map((c) => c[i]).filter((c) => c));
- }
-
- // Remove duplicates
- return [...new Set(corrections)];
- }
-
- setupContextMenuListener () {
- window.addEventListener('contextmenu', (event) => {
- event.preventDefault();
-
- const template = this.getMenu();
-
- if (this.languagesMenu && this.browseForLanguageMenu) {
- template.unshift({ type: 'separator' });
- if (this.dictionariesPath) {
- template.unshift(this.browseForLanguageMenu);
- }
- template.unshift(this.languagesMenu);
- }
-
- setTimeout(() => {
- if (event.target.nodeName === 'A') {
- const targetLink = event.target.href;
-
- template.unshift({
- label: i18n.__('Open_Link'),
- click: () => {
- shell.openExternal(targetLink);
- }
- });
- }
-
- if (['TEXTAREA', 'INPUT'].indexOf(event.target.nodeName) > -1) {
- const text = window.getSelection().toString().trim();
- if (text !== '' && !this.isCorrect(text)) {
- const options = this.getCorrections(text);
- const maxItems = Math.min(options.length, 6);
-
- if (maxItems > 0) {
- const suggestions = [];
- const onClick = function (menuItem) {
- webContents.replaceMisspelling(menuItem.label);
- };
-
- for (let i = 0; i < options.length; i++) {
- const item = options[i];
- suggestions.push({ label: item, click: onClick });
- }
-
- template.unshift({ type: 'separator' });
-
- if (suggestions.length > maxItems) {
- const moreSuggestions = {
- label: i18n.__('More_spelling_suggestions'),
- submenu: suggestions.slice(maxItems)
- };
- template.unshift(moreSuggestions);
- }
-
- template.unshift.apply(template, suggestions.slice(0, maxItems));
- } else {
- template.unshift({ label: i18n.__('No_suggestions'), enabled: false });
- }
- }
- }
-
- menu = remote.Menu.buildFromTemplate(template);
- menu.popup(remote.getCurrentWindow(), undefined, undefined, 5);
- }, 0);
- }, false);
- }
+ this.availableDictionaries.push(dictionaryName);
+ }
+ }
+ }
+ }
+
+ setEnabled(dictionaries) {
+ dictionaries = [].concat(dictionaries);
+ let result = false;
+ for (let i = 0; i < dictionaries.length; i++) {
+ if (this.availableDictionaries.includes(dictionaries[i])) {
+ result = true;
+ this.enabledDictionaries.push(dictionaries[i]);
+ // If using Hunspell or Windows then only allow 1 language for performance reasons
+ if (!this.multiLanguage) {
+ this.enabledDictionaries = [dictionaries[i]];
+ checker.setDictionary(dictionaries[i], this.dictionariesPath);
+ return true;
+ }
+ }
+ }
+ return result;
+ }
+
+ disable(dictionary) {
+ const pos = this.enabledDictionaries.indexOf(dictionary);
+ if (pos !== -1) {
+ this.enabledDictionaries.splice(pos, 1);
+ }
+ }
+
+ getContractions() {
+ const contractions = [
+ "ain't", "aren't", "can't", "could've", "couldn't", "couldn't've", "didn't", "doesn't", "don't", "hadn't",
+ "hadn't've", "hasn't", "haven't", "he'd", "he'd've", "he'll", "he's", "how'd", "how'll", "how's", "I'd",
+ "I'd've", "I'll", "I'm", "I've", "isn't", "it'd", "it'd've", "it'll", "it's", "let's", "ma'am", "mightn't",
+ "mightn't've", "might've", "mustn't", "must've", "needn't", "not've", "o'clock", "shan't", "she'd", "she'd've",
+ "she'll", "she's", "should've", "shouldn't", "shouldn't've", "that'll", "that's", "there'd", "there'd've",
+ "there're", "there's", "they'd", "they'd've", "they'll", "they're", "they've", "wasn't", "we'd", "we'd've",
+ "we'll", "we're", "we've", "weren't", "what'll", "what're", "what's", "what've", "when's", "where'd",
+ "where's", "where've", "who'd", "who'll", "who're", "who's", "who've", "why'll", "why're", "why's", "won't",
+ "would've", "wouldn't", "wouldn't've", "y'all", "y'all'd've", "you'd", "you'd've", "you'll", "you're", "you've",
+ ];
+
+ const contractionMap = contractions.reduce((acc, word) => {
+ acc[word.replace(/'.*/, '')] = true;
+ return acc;
+ }, {});
+
+ return contractionMap;
+ }
+
+ enable() {
+ webFrame.setSpellCheckProvider('', false, {
+ spellCheck: (text) => this.isCorrect(text),
+ });
+
+ this.setupContextMenuListener();
+ }
+
+ getMenu() {
+ return [
+ {
+ label: i18n.__('Undo'),
+ role: 'undo',
+ },
+ {
+ label: i18n.__('Redo'),
+ role: 'redo',
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: i18n.__('Cut'),
+ role: 'cut',
+ accelerator: 'CommandOrControl+X',
+ },
+ {
+ label: i18n.__('Copy'),
+ role: 'copy',
+ accelerator: 'CommandOrControl+C',
+ },
+ {
+ label: i18n.__('Paste'),
+ role: 'paste',
+ accelerator: 'CommandOrControl+V',
+ },
+ {
+ label: i18n.__('Select_All'),
+ role: 'selectall',
+ accelerator: 'CommandOrControl+A',
+ },
+ ];
+ }
+
+ saveEnabledDictionaries() {
+ localStorage.setItem('spellcheckerDictionaries', JSON.stringify(this.enabledDictionaries));
+ }
+
+ isCorrect(text) {
+ if (!this.enabledDictionaries.length || this.contractions[text.toLocaleLowerCase()]) {
+ return true;
+ }
+
+ if (this.multiLanguage) {
+ for (let i = 0; i < this.enabledDictionaries.length; i++) {
+ checker.setDictionary(this.enabledDictionaries[i]);
+ if (!checker.isMisspelled(text)) {
+ return true;
+ }
+ }
+ } else {
+ return !checker.isMisspelled(text);
+ }
+ return false;
+ }
+
+ getCorrections(text) {
+ if (!this.multiLanguage) {
+ return checker.getCorrectionsForMisspelling(text);
+ }
+
+ const allCorrections = this.enabledDictionaries.map((dictionary) => {
+ checker.setDictionary(dictionary);
+ return checker.getCorrectionsForMisspelling(text);
+ }).filter((c) => c.length > 0);
+
+ const length = Math.max(...allCorrections.map((a) => a.length));
+
+ // Get the best suggestions of each language first
+ const corrections = [];
+ for (let i = 0; i < length; i++) {
+ corrections.push(...allCorrections.map((c) => c[i]).filter((c) => c));
+ }
+
+ // Remove duplicates
+ return [...new Set(corrections)];
+ }
+
+ setupContextMenuListener() {
+ window.addEventListener('contextmenu', (event) => {
+ event.preventDefault();
+
+ const template = this.getMenu();
+
+ if (this.languagesMenu && this.browseForLanguageMenu) {
+ template.unshift({ type: 'separator' });
+ if (this.dictionariesPath) {
+ template.unshift(this.browseForLanguageMenu);
+ }
+ template.unshift(this.languagesMenu);
+ }
+
+ setTimeout(() => {
+ if (event.target.nodeName === 'A') {
+ const targetLink = event.target.href;
+
+ template.unshift({
+ label: i18n.__('Open_Link'),
+ click: () => {
+ shell.openExternal(targetLink);
+ },
+ });
+ }
+
+ if (['TEXTAREA', 'INPUT'].indexOf(event.target.nodeName) > -1) {
+ const text = window.getSelection().toString().trim();
+ if (text !== '' && !this.isCorrect(text)) {
+ const options = this.getCorrections(text);
+ const maxItems = Math.min(options.length, 6);
+
+ if (maxItems > 0) {
+ const suggestions = [];
+ const onClick = function(menuItem) {
+ webContents.replaceMisspelling(menuItem.label);
+ };
+
+ for (let i = 0; i < options.length; i++) {
+ const item = options[i];
+ suggestions.push({ label: item, click: onClick });
+ }
+
+ template.unshift({ type: 'separator' });
+
+ if (suggestions.length > maxItems) {
+ const moreSuggestions = {
+ label: i18n.__('More_spelling_suggestions'),
+ submenu: suggestions.slice(maxItems),
+ };
+ template.unshift(moreSuggestions);
+ }
+
+ template.unshift.apply(template, suggestions.slice(0, maxItems));
+ } else {
+ template.unshift({ label: i18n.__('No_suggestions'), enabled: false });
+ }
+ }
+ }
+
+ menu = remote.Menu.buildFromTemplate(template);
+ menu.popup(remote.getCurrentWindow(), undefined, undefined, 5);
+ }, 0);
+ }, false);
+ }
}
module.exports = SpellCheck;
diff --git a/src/public/preload.js b/src/public/preload.js
index 546fffd48b..98e4a065cf 100644
--- a/src/public/preload.js
+++ b/src/public/preload.js
@@ -12,119 +12,119 @@ window.i18n = i18n;
const defaultWindowOpen = window.open;
-function customWindowOpen (url, frameName, features) {
- const jitsiDomain = RocketChat.settings.get('Jitsi_Domain');
- if (jitsiDomain && url.indexOf(jitsiDomain) !== -1) {
- features = ((features) ? (features + ",") : "") +
- "nodeIntegration=true,preload=" + path.join(__dirname, 'jitsi-preload.js');
- return defaultWindowOpen(url, frameName, features);
- } else {
- return defaultWindowOpen(url, frameName, features);
- }
+function customWindowOpen(url, frameName, features) {
+ const jitsiDomain = RocketChat.settings.get('Jitsi_Domain');
+ if (jitsiDomain && url.indexOf(jitsiDomain) !== -1) {
+ features = `${ (features) ? (`${ features },`) : ''
+ }nodeIntegration=true,preload=${ path.join(__dirname, 'jitsi-preload.js') }`;
+ return defaultWindowOpen(url, frameName, features);
+ } else {
+ return defaultWindowOpen(url, frameName, features);
+ }
}
window.open = customWindowOpen;
const events = ['unread-changed', 'get-sourceId', 'user-status-manually-set'];
-events.forEach(function (e) {
- window.addEventListener(e, function (event) {
- ipcRenderer.sendToHost(e, event.detail);
- });
+events.forEach(function(e) {
+ window.addEventListener(e, function(event) {
+ ipcRenderer.sendToHost(e, event.detail);
+ });
});
const userPresenceControl = () => {
- const INTERVAL = 10000; // 10s
- setInterval(() => {
- try {
- const idleTime = ipcRenderer.sendSync('getSystemIdleTime');
- if (idleTime < INTERVAL) {
- UserPresence.setOnline();
- }
- } catch (e) {
- console.error(`Error getting system idle time: ${e}`);
- }
- }, INTERVAL);
+ const INTERVAL = 10000; // 10s
+ setInterval(() => {
+ try {
+ const idleTime = ipcRenderer.sendSync('getSystemIdleTime');
+ if (idleTime < INTERVAL) {
+ UserPresence.setOnline();
+ }
+ } catch (e) {
+ console.error(`Error getting system idle time: ${ e }`);
+ }
+ }, INTERVAL);
};
const changeSidebarColor = () => {
- const sidebar = document.querySelector('.sidebar');
- const fullpage = document.querySelector('.full-page');
- if (sidebar) {
- const sidebarItem = sidebar.querySelector('.sidebar-item');
- let itemColor;
- if (sidebarItem) {
- itemColor = window.getComputedStyle(sidebarItem);
- }
- const { color, background } = window.getComputedStyle(sidebar);
- ipcRenderer.sendToHost('sidebar-background', {color: itemColor || color, background: background});
- } else if (fullpage) {
- const { color, background } = window.getComputedStyle(fullpage);
- ipcRenderer.sendToHost('sidebar-background', {color: color, background: background});
- } else {
- window.requestAnimationFrame(changeSidebarColor);
-
- }
+ const sidebar = document.querySelector('.sidebar');
+ const fullpage = document.querySelector('.full-page');
+ if (sidebar) {
+ const sidebarItem = sidebar.querySelector('.sidebar-item');
+ let itemColor;
+ if (sidebarItem) {
+ itemColor = window.getComputedStyle(sidebarItem);
+ }
+ const { color, background } = window.getComputedStyle(sidebar);
+ ipcRenderer.sendToHost('sidebar-background', { color: itemColor || color, background });
+ } else if (fullpage) {
+ const { color, background } = window.getComputedStyle(fullpage);
+ ipcRenderer.sendToHost('sidebar-background', { color, background });
+ } else {
+ window.requestAnimationFrame(changeSidebarColor);
+
+ }
};
ipcRenderer.on('request-sidebar-color', () => {
- changeSidebarColor();
+ changeSidebarColor();
});
-window.addEventListener('load', function () {
- Meteor.startup(function () {
- Tracker.autorun(function () {
- const siteName = RocketChat.settings.get('Site_Name');
- if (siteName) {
- ipcRenderer.sendToHost('title-changed', siteName);
- }
- });
- });
- userPresenceControl();
+window.addEventListener('load', function() {
+ Meteor.startup(function() {
+ Tracker.autorun(function() {
+ const siteName = RocketChat.settings.get('Site_Name');
+ if (siteName) {
+ ipcRenderer.sendToHost('title-changed', siteName);
+ }
+ });
+ });
+ userPresenceControl();
});
-window.onload = function () {
- const $ = require('./vendor/jquery-3.1.1');
- function checkExternalUrl (e) {
- const href = $(this).attr('href');
- // Check href matching current domain
- if (RegExp(`^${location.protocol}\/\/${location.host}`).test(href)) {
- return;
- }
-
- // Check if is file upload link
- if (/^\/file-upload\//.test(href) && !this.hasAttribute('download')) {
- this.setAttribute('download', '');
- this.click();
- }
-
- // Check href matching relative URL
- if (!/^([a-z]+:)?\/\//.test(href)) {
- return;
- }
-
- if (/^file:\/\/.+/.test(href)) {
- const item = href.slice(6);
- shell.showItemInFolder(item);
- e.preventDefault();
- } else {
- shell.openExternal(href);
- e.preventDefault();
- }
- }
-
- $(document).on('click', 'a', checkExternalUrl);
-
- $('#reload').click(function () {
- ipcRenderer.sendToHost('reload-server');
- $(this).hide();
- $(this).parent().find('.loading-animation').show();
- });
+window.onload = function() {
+ const $ = require('./vendor/jquery-3.1.1');
+ function checkExternalUrl(e) {
+ const href = $(this).attr('href');
+ // Check href matching current domain
+ if (RegExp(`^${ location.protocol }\/\/${ location.host }`).test(href)) {
+ return;
+ }
+
+ // Check if is file upload link
+ if (/^\/file-upload\//.test(href) && !this.hasAttribute('download')) {
+ this.setAttribute('download', '');
+ this.click();
+ }
+
+ // Check href matching relative URL
+ if (!/^([a-z]+:)?\/\//.test(href)) {
+ return;
+ }
+
+ if (/^file:\/\/.+/.test(href)) {
+ const item = href.slice(6);
+ shell.showItemInFolder(item);
+ e.preventDefault();
+ } else {
+ shell.openExternal(href);
+ e.preventDefault();
+ }
+ }
+
+ $(document).on('click', 'a', checkExternalUrl);
+
+ $('#reload').click(function() {
+ ipcRenderer.sendToHost('reload-server');
+ $(this).hide();
+ $(this).parent().find('.loading-animation').show();
+ });
};
// Prevent redirect to url when dragging in
-document.addEventListener('dragover', e => e.preventDefault());
-document.addEventListener('drop', e => e.preventDefault());
+document.addEventListener('dragover', (e) => e.preventDefault());
+document.addEventListener('drop', (e) => e.preventDefault());
const spellChecker = new SpellCheck();
spellChecker.enable();
diff --git a/src/scripts/bugsnag_apikey.js b/src/scripts/bugsnag_apikey.js
index 296b8084a2..bf52f6a144 100644
--- a/src/scripts/bugsnag_apikey.js
+++ b/src/scripts/bugsnag_apikey.js
@@ -1 +1 @@
-Bugsnag.apiKey = "2fa5f5a7b728b84ae273015995b42a6e";
+Bugsnag.apiKey = '2fa5f5a7b728b84ae273015995b42a6e';
diff --git a/src/scripts/menus.js b/src/scripts/menus.js
index d0092c1b81..e6a7762386 100644
--- a/src/scripts/menus.js
+++ b/src/scripts/menus.js
@@ -10,85 +10,85 @@ import historyMenu from './menus/history';
import windowMenu from './menus/window';
import helpMenu from './menus/help';
-const Menu = remote.Menu;
+const { Menu } = remote;
const APP_NAME = remote.app.getName();
const isMac = process.platform === 'darwin';
document.title = APP_NAME;
const menuTemplate = [
- {
- label: '&' + APP_NAME,
- submenu: appMenu
- },
- {
- label: '&' + i18n.__('Edit'),
- submenu: editMenu
- },
- {
- label: '&' + i18n.__('View'),
- submenu: viewMenu
- },
- {
- label: '&' + i18n.__('History'),
- submenu: historyMenu
- },
- {
- label: '&' + i18n.__('Window'),
- id: 'window',
- role: 'window',
- submenu: windowMenu
- },
- {
- label: '&' + i18n.__('Help'),
- role: 'help',
- submenu: helpMenu
- }
+ {
+ label: `&${ APP_NAME }`,
+ submenu: appMenu,
+ },
+ {
+ label: `&${ i18n.__('Edit') }`,
+ submenu: editMenu,
+ },
+ {
+ label: `&${ i18n.__('View') }`,
+ submenu: viewMenu,
+ },
+ {
+ label: `&${ i18n.__('History') }`,
+ submenu: historyMenu,
+ },
+ {
+ label: `&${ i18n.__('Window') }`,
+ id: 'window',
+ role: 'window',
+ submenu: windowMenu,
+ },
+ {
+ label: `&${ i18n.__('Help') }`,
+ role: 'help',
+ submenu: helpMenu,
+ },
];
-function createMenu () {
- const menu = Menu.buildFromTemplate(menuTemplate);
- Menu.setApplicationMenu(menu);
+function createMenu() {
+ const menu = Menu.buildFromTemplate(menuTemplate);
+ Menu.setApplicationMenu(menu);
}
-function addServer (host, position) {
- const index = windowMenu.findIndex((i) => i.id === 'server-list-separator');
- windowMenu[index].visible = true;
+function addServer(host, position) {
+ const index = windowMenu.findIndex((i) => i.id === 'server-list-separator');
+ windowMenu[index].visible = true;
- const menuItem = {
- label: '&' + host.title,
- accelerator: `CmdOrCtrl+ ${position}`,
- position: 'before=server-list-separator',
- id: host.url,
- click: () => {
- const mainWindow = remote.getCurrentWindow();
- mainWindow.show();
- servers.setActive(host.url);
- }
- };
+ const menuItem = {
+ label: `&${ host.title }`,
+ accelerator: `CmdOrCtrl+ ${ position }`,
+ position: 'before=server-list-separator',
+ id: host.url,
+ click: () => {
+ const mainWindow = remote.getCurrentWindow();
+ mainWindow.show();
+ servers.setActive(host.url);
+ },
+ };
- windowMenu.push(menuItem);
+ windowMenu.push(menuItem);
- createMenu();
+ createMenu();
}
-function removeServer (server) {
- const index = windowMenu.findIndex((i) => i.id === server);
- windowMenu.splice(index, 1);
- createMenu();
+function removeServer(server) {
+ const index = windowMenu.findIndex((i) => i.id === server);
+ windowMenu.splice(index, 1);
+ createMenu();
}
-function autoHideMenu () {
- remote.getCurrentWindow().setAutoHideMenuBar(true);
+function autoHideMenu() {
+ remote.getCurrentWindow().setAutoHideMenuBar(true);
}
if (!isMac && localStorage.getItem('autohideMenu') === 'true') {
- autoHideMenu();
+ autoHideMenu();
}
createMenu();
export {
- addServer,
- removeServer
+ addServer,
+ removeServer,
};
diff --git a/src/scripts/menus/app.js b/src/scripts/menus/app.js
index 263cc6641d..f48163914f 100644
--- a/src/scripts/menus/app.js
+++ b/src/scripts/menus/app.js
@@ -5,63 +5,63 @@ const APP_NAME = remote.app.getName();
const isMac = process.platform === 'darwin';
const appTemplate = [
- {
- label: i18n.__('About', APP_NAME),
- click: function () {
- const win = new remote.BrowserWindow({
- width: 310,
- height: 240,
- resizable: false,
- show: false,
- center: true,
- maximizable: false,
- minimizable: false,
- title: 'About Rocket.Chat'
- });
- win.loadURL('file://' + __dirname + '/about.html');
- win.setMenuBarVisibility(false);
- win.show();
- }
- },
- {
- type: 'separator',
- id: 'about-sep'
- },
- {
- label: i18n.__('Quit_App', APP_NAME),
- accelerator: 'CommandOrControl+Q',
- click: function () {
- remote.app.quit();
- }
- }
+ {
+ label: i18n.__('About', APP_NAME),
+ click() {
+ const win = new remote.BrowserWindow({
+ width: 310,
+ height: 240,
+ resizable: false,
+ show: false,
+ center: true,
+ maximizable: false,
+ minimizable: false,
+ title: 'About Rocket.Chat',
+ });
+ win.loadURL(`file://${ __dirname }/about.html`);
+ win.setMenuBarVisibility(false);
+ win.show();
+ },
+ },
+ {
+ type: 'separator',
+ id: 'about-sep',
+ },
+ {
+ label: i18n.__('Quit_App', APP_NAME),
+ accelerator: 'CommandOrControl+Q',
+ click() {
+ remote.app.quit();
+ },
+ },
];
if (isMac) {
- const macAppExtraTemplate = [
- {
- role: 'services',
- submenu: [],
- position: 'after=about-sep'
- },
- {
- type: 'separator'
- },
- {
- accelerator: 'Command+H',
- role: 'hide'
- },
- {
- accelerator: 'Command+Alt+H',
- role: 'hideothers'
- },
- {
- role: 'unhide'
- },
- {
- type: 'separator'
- }
- ];
- appTemplate.push(...macAppExtraTemplate);
+ const macAppExtraTemplate = [
+ {
+ role: 'services',
+ submenu: [],
+ position: 'after=about-sep',
+ },
+ {
+ type: 'separator',
+ },
+ {
+ accelerator: 'Command+H',
+ role: 'hide',
+ },
+ {
+ accelerator: 'Command+Alt+H',
+ role: 'hideothers',
+ },
+ {
+ role: 'unhide',
+ },
+ {
+ type: 'separator',
+ },
+ ];
+ appTemplate.push(...macAppExtraTemplate);
}
export default appTemplate;
diff --git a/src/scripts/menus/edit.js b/src/scripts/menus/edit.js
index b9b7588d73..6f650e9686 100644
--- a/src/scripts/menus/edit.js
+++ b/src/scripts/menus/edit.js
@@ -1,39 +1,39 @@
import i18n from '../../i18n/index.js';
const editTemplate = [
- {
- label: i18n.__('Undo'),
- accelerator: 'CommandOrControl+Z',
- role: 'undo'
- },
- {
- label: i18n.__('Redo'),
- accelerator: 'CommandOrControl+Shift+Z',
- role: 'redo'
- },
- {
- type: 'separator'
- },
- {
- label: i18n.__('Cut'),
- accelerator: 'CommandOrControl+X',
- role: 'cut'
- },
- {
- label: i18n.__('Copy'),
- accelerator: 'CommandOrControl+C',
- role: 'copy'
- },
- {
- label: i18n.__('Paste'),
- accelerator: 'CommandOrControl+V',
- role: 'paste'
- },
- {
- label: i18n.__('Select_All'),
- accelerator: 'CommandOrControl+A',
- role: 'selectall'
- }
+ {
+ label: i18n.__('Undo'),
+ accelerator: 'CommandOrControl+Z',
+ role: 'undo',
+ },
+ {
+ label: i18n.__('Redo'),
+ accelerator: 'CommandOrControl+Shift+Z',
+ role: 'redo',
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: i18n.__('Cut'),
+ accelerator: 'CommandOrControl+X',
+ role: 'cut',
+ },
+ {
+ label: i18n.__('Copy'),
+ accelerator: 'CommandOrControl+C',
+ role: 'copy',
+ },
+ {
+ label: i18n.__('Paste'),
+ accelerator: 'CommandOrControl+V',
+ role: 'paste',
+ },
+ {
+ label: i18n.__('Select_All'),
+ accelerator: 'CommandOrControl+A',
+ role: 'selectall',
+ },
];
export default editTemplate;
diff --git a/src/scripts/menus/help.js b/src/scripts/menus/help.js
index 676c338162..9b860f6c7f 100644
--- a/src/scripts/menus/help.js
+++ b/src/scripts/menus/help.js
@@ -4,28 +4,28 @@ import i18n from '../../i18n/index.js';
const APP_NAME = remote.app.getName();
const helpTemplate = [
- {
- label: i18n.__('Help_Name', APP_NAME),
- click: () => remote.shell.openExternal('https://rocket.chat/docs')
- },
- {
- type: 'separator'
- },
- {
- label: i18n.__('Report_Issue'),
- click: () => remote.shell.openExternal('https://github.com/RocketChat/Rocket.Chat/issues')
- },
- {
- label: i18n.__('Reset_App_Data'),
- click: () => servers.resetAppData()
- },
- {
- type: 'separator'
- },
- {
- label: i18n.__('Learn_More'),
- click: () => remote.shell.openExternal('https://rocket.chat')
- }
+ {
+ label: i18n.__('Help_Name', APP_NAME),
+ click: () => remote.shell.openExternal('https://rocket.chat/docs'),
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: i18n.__('Report_Issue'),
+ click: () => remote.shell.openExternal('https://github.com/RocketChat/Rocket.Chat/issues'),
+ },
+ {
+ label: i18n.__('Reset_App_Data'),
+ click: () => servers.resetAppData(),
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: i18n.__('Learn_More'),
+ click: () => remote.shell.openExternal('https://rocket.chat'),
+ },
];
export default helpTemplate;
diff --git a/src/scripts/menus/history.js b/src/scripts/menus/history.js
index ce47a238df..7f3ce1e6f9 100644
--- a/src/scripts/menus/history.js
+++ b/src/scripts/menus/history.js
@@ -3,29 +3,29 @@ import i18n from '../../i18n/index.js';
const isMac = process.platform === 'darwin';
const macWindowTemplate = [
- {
- label: i18n.__('Back'),
- accelerator: 'Command+left',
- click: () => { webview.goBack(); }
- },
- {
- label: i18n.__('Forward'),
- accelerator: 'Command+right',
- click: () => { webview.goForward(); }
- }
+ {
+ label: i18n.__('Back'),
+ accelerator: 'Command+left',
+ click: () => { webview.goBack(); },
+ },
+ {
+ label: i18n.__('Forward'),
+ accelerator: 'Command+right',
+ click: () => { webview.goForward(); },
+ },
];
const windowTemplate = [
- {
- label: i18n.__('Back'),
- accelerator: 'Alt+Left',
- click: () => { webview.goBack(); }
- },
- {
- label: i18n.__('Forward'),
- accelerator: 'Alt+Right',
- click: () => { webview.goForward(); }
- },
+ {
+ label: i18n.__('Back'),
+ accelerator: 'Alt+Left',
+ click: () => { webview.goBack(); },
+ },
+ {
+ label: i18n.__('Forward'),
+ accelerator: 'Alt+Right',
+ click: () => { webview.goForward(); },
+ },
];
export default isMac ? macWindowTemplate : windowTemplate;
diff --git a/src/scripts/menus/view.js b/src/scripts/menus/view.js
index c149d0ffb9..c924292b62 100644
--- a/src/scripts/menus/view.js
+++ b/src/scripts/menus/view.js
@@ -5,119 +5,119 @@ import sidebar from '../sidebar';
import tray from '../tray';
const isMac = process.platform === 'darwin';
-const certificate = remote.require('./background').certificate;
+const { certificate } = remote.require('./background');
const viewTemplate = [
- {
- label: i18n.__('Original_Zoom'),
- accelerator: 'CommandOrControl+0',
- role: 'resetzoom'
- },
- {
- label: i18n.__('Zoom_In'),
- accelerator: 'CommandOrControl+Plus',
- role: 'zoomin'
- },
- {
- label: i18n.__('Zoom_Out'),
- accelerator: 'CommandOrControl+-',
- role: 'zoomout'
- },
- {
- type: 'separator'
- },
- {
- label: i18n.__('Current_Server_Reload'),
- accelerator: 'CommandOrControl+R',
- click: function () {
- const activeWebview = webview.getActive();
- if (activeWebview) {
- activeWebview.reload();
- }
- }
- },
- {
- label: i18n.__('Current_Server_Toggle_DevTools'),
- accelerator: isMac ? 'Command+Alt+I' : 'Ctrl+Shift+I',
- click: function () {
- const activeWebview = webview.getActive();
- if (activeWebview) {
- activeWebview.openDevTools();
- }
- }
- },
- {
- type: 'separator'
- },
- {
- label: i18n.__('Application_Reload'),
- accelerator: 'CommandOrControl+Shift+R',
- click: function () {
- const mainWindow = remote.getCurrentWindow();
- if (mainWindow.destroyTray) {
- mainWindow.destroyTray();
- }
- mainWindow.reload();
- }
- },
- {
- label: i18n.__('Application_Toggle_DevTools'),
- click: function () {
- remote.getCurrentWindow().toggleDevTools();
- }
- },
- {
- type: 'separator',
- id: 'toggle'
- },
- {
- label: i18n.__('Toggle_Server_List'),
- click: function () {
- sidebar.toggle();
- }
- },
- {
- type: 'separator'
- },
- {
- label: i18n.__('Clear'),
- submenu: [
- {
- label: i18n.__('Clear_Trusted_Certificates'),
- click: function () {
- certificate.clear();
- }
- }
- ]
- }
+ {
+ label: i18n.__('Original_Zoom'),
+ accelerator: 'CommandOrControl+0',
+ role: 'resetzoom',
+ },
+ {
+ label: i18n.__('Zoom_In'),
+ accelerator: 'CommandOrControl+Plus',
+ role: 'zoomin',
+ },
+ {
+ label: i18n.__('Zoom_Out'),
+ accelerator: 'CommandOrControl+-',
+ role: 'zoomout',
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: i18n.__('Current_Server_Reload'),
+ accelerator: 'CommandOrControl+R',
+ click() {
+ const activeWebview = webview.getActive();
+ if (activeWebview) {
+ activeWebview.reload();
+ }
+ },
+ },
+ {
+ label: i18n.__('Current_Server_Toggle_DevTools'),
+ accelerator: isMac ? 'Command+Alt+I' : 'Ctrl+Shift+I',
+ click() {
+ const activeWebview = webview.getActive();
+ if (activeWebview) {
+ activeWebview.openDevTools();
+ }
+ },
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: i18n.__('Application_Reload'),
+ accelerator: 'CommandOrControl+Shift+R',
+ click() {
+ const mainWindow = remote.getCurrentWindow();
+ if (mainWindow.destroyTray) {
+ mainWindow.destroyTray();
+ }
+ mainWindow.reload();
+ },
+ },
+ {
+ label: i18n.__('Application_Toggle_DevTools'),
+ click() {
+ remote.getCurrentWindow().toggleDevTools();
+ },
+ },
+ {
+ type: 'separator',
+ id: 'toggle',
+ },
+ {
+ label: i18n.__('Toggle_Server_List'),
+ click() {
+ sidebar.toggle();
+ },
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: i18n.__('Clear'),
+ submenu: [
+ {
+ label: i18n.__('Clear_Trusted_Certificates'),
+ click() {
+ certificate.clear();
+ },
+ },
+ ],
+ },
];
if (isMac) {
- viewTemplate.push({
- label: i18n.__('Toggle_Tray_Icon'),
- click: function () {
- tray.toggle();
- },
- position: 'after=toggle'
- }, {
- label: i18n.__('Toggle_Full_Screen'),
- accelerator: 'Control+Command+F',
- click: function () {
- const mainWindow = remote.getCurrentWindow();
- mainWindow.setFullScreen(!mainWindow.isFullScreen());
- },
- position: 'after=toggle'
- });
+ viewTemplate.push({
+ label: i18n.__('Toggle_Tray_Icon'),
+ click() {
+ tray.toggle();
+ },
+ position: 'after=toggle',
+ }, {
+ label: i18n.__('Toggle_Full_Screen'),
+ accelerator: 'Control+Command+F',
+ click() {
+ const mainWindow = remote.getCurrentWindow();
+ mainWindow.setFullScreen(!mainWindow.isFullScreen());
+ },
+ position: 'after=toggle',
+ });
} else {
- viewTemplate.push({
- label: i18n.__('Toggle_Menu_Bar'),
- click: function () {
- const current = localStorage.getItem('autohideMenu') === 'true';
- remote.getCurrentWindow().setAutoHideMenuBar(!current);
- localStorage.setItem('autohideMenu', JSON.stringify(!current));
- },
- position: 'after=toggle'
- });
+ viewTemplate.push({
+ label: i18n.__('Toggle_Menu_Bar'),
+ click() {
+ const current = localStorage.getItem('autohideMenu') === 'true';
+ remote.getCurrentWindow().setAutoHideMenuBar(!current);
+ localStorage.setItem('autohideMenu', JSON.stringify(!current));
+ },
+ position: 'after=toggle',
+ });
}
export default viewTemplate;
diff --git a/src/scripts/menus/window.js b/src/scripts/menus/window.js
index 9c9f239474..2f5b42ae52 100644
--- a/src/scripts/menus/window.js
+++ b/src/scripts/menus/window.js
@@ -5,70 +5,70 @@ import servers from '../servers';
const isMac = process.platform === 'darwin';
const macWindowTemplate = [
- {
- label: i18n.__('Minimize'),
- accelerator: 'Command+M',
- role: 'minimize'
- },
- {
- label: i18n.__('Close'),
- accelerator: 'Command+W',
- role: 'close'
- },
- {
- type: 'separator'
- },
- {
- type: 'separator',
- id: 'server-list-separator',
- visible: false
- },
- {
- label: i18n.__('Add_new_server'),
- accelerator: 'Command+N',
- click: function () {
- const mainWindow = remote.getCurrentWindow();
- mainWindow.show();
- servers.clearActive();
- webview.showLanding();
- }
- },
- {
- type: 'separator'
- },
- {
- label: i18n.__('Bring_All_to_Front'),
- click: function () {
- const mainWindow = remote.getCurrentWindow();
- mainWindow.show();
- }
- }
+ {
+ label: i18n.__('Minimize'),
+ accelerator: 'Command+M',
+ role: 'minimize',
+ },
+ {
+ label: i18n.__('Close'),
+ accelerator: 'Command+W',
+ role: 'close',
+ },
+ {
+ type: 'separator',
+ },
+ {
+ type: 'separator',
+ id: 'server-list-separator',
+ visible: false,
+ },
+ {
+ label: i18n.__('Add_new_server'),
+ accelerator: 'Command+N',
+ click() {
+ const mainWindow = remote.getCurrentWindow();
+ mainWindow.show();
+ servers.clearActive();
+ webview.showLanding();
+ },
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: i18n.__('Bring_All_to_Front'),
+ click() {
+ const mainWindow = remote.getCurrentWindow();
+ mainWindow.show();
+ },
+ },
];
const windowTemplate = [
- {
- type: 'separator',
- id: 'server-list-separator',
- visible: false
- },
- {
- label: i18n.__('Add_new_server'),
- accelerator: 'Ctrl+N',
- click: function () {
- servers.clearActive();
- webview.showLanding();
- }
- },
- {
- type: 'separator'
- },
- {
- label: i18n.__('Close'),
- accelerator: 'Ctrl+W',
- click: function () {
- remote.getCurrentWindow().close();
- }
- }
+ {
+ type: 'separator',
+ id: 'server-list-separator',
+ visible: false,
+ },
+ {
+ label: i18n.__('Add_new_server'),
+ accelerator: 'Ctrl+N',
+ click() {
+ servers.clearActive();
+ webview.showLanding();
+ },
+ },
+ {
+ type: 'separator',
+ },
+ {
+ label: i18n.__('Close'),
+ accelerator: 'Ctrl+W',
+ click() {
+ remote.getCurrentWindow().close();
+ },
+ },
];
export default isMac ? macWindowTemplate : windowTemplate;
diff --git a/src/scripts/servers.js b/src/scripts/servers.js
index fa8beb3bf0..ca1c2b3803 100644
--- a/src/scripts/servers.js
+++ b/src/scripts/servers.js
@@ -4,310 +4,310 @@ import jetpack from 'fs-jetpack';
import { EventEmitter } from 'events';
import { remote, ipcRenderer } from 'electron';
import i18n from '../i18n/index.js';
-const remoteServers = remote.require('./background').remoteServers;
+const { remoteServers } = remote.require('./background');
class Servers extends EventEmitter {
- constructor () {
- super();
- this.load();
- const processProtocol = this.getProtocolUrlFromProcess(remote.process.argv);
- if (processProtocol) {
- this.showHostConfirmation(processProtocol);
- }
- ipcRenderer.on('add-host', (e, host) => {
- if (this.hostExists(host)) {
- this.setActive(host);
- } else {
- this.showHostConfirmation(host);
- }
- });
- }
-
- get hosts () {
- return this._hosts;
- }
-
- set hosts (hosts) {
- this._hosts = hosts;
- this.save();
- return true;
- }
-
- get hostsKey () {
- return 'rocket.chat.hosts';
- }
-
- get activeKey () {
- return 'rocket.chat.currentHost';
- }
-
- load () {
- let hosts = localStorage.getItem(this.hostsKey);
-
- try {
- hosts = JSON.parse(hosts);
- } catch (e) {
- if (typeof hosts === 'string' && hosts.match(/^https?:\/\//)) {
- hosts = {};
- hosts[hosts] = {
- title: hosts,
- url: hosts
- };
- }
-
- localStorage.setItem(this.hostsKey, JSON.stringify(hosts));
- }
-
- if (hosts === null) {
- hosts = {};
- }
-
- if (Array.isArray(hosts)) {
- const oldHosts = hosts;
- hosts = {};
- oldHosts.forEach(function (item) {
- item = item.replace(/\/$/, '');
- hosts[item] = {
- title: item,
- url: item
- };
- });
- localStorage.setItem(this.hostsKey, JSON.stringify(hosts));
- }
-
- // Load server info from server config file
- if (Object.keys(hosts).length === 0) {
- const path = jetpack.find(remote.app.getPath('userData'), { matching: 'servers.json'})[0] ||
- jetpack.find(jetpack.path(remote.app.getAppPath(), '..'), { matching: 'servers.json'})[0];
-
- if (path) {
- const pathToServerJson = jetpack.path(path);
-
- try {
- const result = jetpack.read(pathToServerJson, 'json');
- if (result) {
- hosts = {};
- Object.keys(result).forEach((title) => {
- const url = result[title];
- hosts[url] = { title, url };
- });
- localStorage.setItem(this.hostsKey, JSON.stringify(hosts));
- // Assume user doesn't want sidebar if they only have one server
- if (Object.keys(hosts).length === 1) {
- localStorage.setItem('sidebar-closed', 'true');
- }
- }
-
- } catch (e) {
- console.error('Server file invalid');
- }
- }
- }
-
- this._hosts = hosts;
- remoteServers.loadServers(this._hosts);
- this.emit('loaded');
- }
-
- save () {
- localStorage.setItem(this.hostsKey, JSON.stringify(this._hosts));
- this.emit('saved');
- }
-
- get (hostUrl) {
- return this.hosts[hostUrl];
- }
-
- forEach (cb) {
- for (const host in this.hosts) {
- if (this.hosts.hasOwnProperty(host)) {
- cb(this.hosts[host]);
- }
- }
- }
-
- validateHost (hostUrl, timeout) {
- timeout = timeout || 5000;
- return new Promise(function (resolve, reject) {
- let resolved = false;
- $.getJSON(`${hostUrl}/api/info`).then(function () {
- if (resolved) {
- return;
- }
- resolved = true;
- resolve();
- }, function (request) {
- if (request.status === 401) {
- const authHeader = request.getResponseHeader('www-authenticate');
- if (authHeader && authHeader.toLowerCase().indexOf('basic ') === 0) {
- resolved = true;
- reject('basic-auth');
- }
- }
- if (resolved) {
- return;
- }
- resolved = true;
- reject('invalid');
- });
- if (timeout) {
- setTimeout(function () {
- if (resolved) {
- return;
- }
- resolved = true;
- reject('timeout');
- }, timeout);
- }
- });
- }
-
- hostExists (hostUrl) {
- const hosts = this.hosts;
-
- return !!hosts[hostUrl];
- }
-
- addHost (hostUrl) {
- const hosts = this.hosts;
-
- const match = hostUrl.match(/^(https?:\/\/)([^:]+):([^@]+)@(.+)$/);
- let username;
- let password;
- let authUrl;
- if (match) {
- authUrl = hostUrl;
- hostUrl = match[1] + match[4];
- username = match[2];
- password = match[3];
- }
-
- if (this.hostExists(hostUrl) === true) {
- this.setActive(hostUrl);
- return false;
- }
-
- hosts[hostUrl] = {
- title: hostUrl,
- url: hostUrl,
- authUrl: authUrl,
- username: username,
- password: password
- };
- this.hosts = hosts;
-
- remoteServers.loadServers(this.hosts);
-
- this.emit('host-added', hostUrl);
-
- return hostUrl;
- }
-
- removeHost (hostUrl) {
- const hosts = this.hosts;
- if (hosts[hostUrl]) {
- delete hosts[hostUrl];
- this.hosts = hosts;
-
- remoteServers.loadServers(this.hosts);
-
- if (this.active === hostUrl) {
- this.clearActive();
- }
- this.emit('host-removed', hostUrl);
- }
- }
-
- get active () {
- return localStorage.getItem(this.activeKey);
- }
-
- setActive (hostUrl) {
- let url;
- if (this.hostExists(hostUrl)) {
- url = hostUrl;
- } else if (Object.keys(this._hosts).length > 0) {
- url = Object.keys(this._hosts)[0];
- }
-
- if (url) {
- localStorage.setItem(this.activeKey, hostUrl);
- this.emit('active-setted', url);
- return true;
- }
- this.emit('loaded');
- return false;
- }
-
- restoreActive () {
- this.setActive(this.active);
- }
-
- clearActive () {
- localStorage.removeItem(this.activeKey);
- this.emit('active-cleared');
- return true;
- }
-
- setHostTitle (hostUrl, title) {
- if (title === 'Rocket.Chat' && /https?:\/\/open\.rocket\.chat/.test(hostUrl) === false) {
- title += ' - ' + hostUrl;
- }
- const hosts = this.hosts;
- hosts[hostUrl].title = title;
- this.hosts = hosts;
- this.emit('title-setted', hostUrl, title);
- }
- getProtocolUrlFromProcess (args) {
- let site = null;
- if (args.length > 1) {
- const protocolURI = args.find(arg => arg.startsWith('rocketchat://'));
- if (protocolURI) {
- site = protocolURI.split(/\/|\?/)[2];
- if (site) {
- let scheme = 'https://';
- if (protocolURI.includes('insecure=true')) {
- scheme = 'http://';
- }
- site = scheme + site;
- }
- }
- }
- return site;
- }
- showHostConfirmation (host) {
- return remote.dialog.showMessageBox({
- type: 'question',
- buttons: [i18n.__('Add'), i18n.__('Cancel')],
- defaultId: 0,
- title: i18n.__('Add_Server'),
- message: i18n.__('Add_host_to_servers', host)
- }, (response) => {
- if (response === 0) {
- this.validateHost(host)
- .then(() => this.addHost(host))
- .then(() => this.setActive(host))
- .catch(() => remote.dialog.showErrorBox(i18n.__('Invalid_Host'), i18n.__('Host_not_validated', host)));
- }
- });
- }
-
- resetAppData () {
- return remote.dialog.showMessageBox({
- type: 'question',
- buttons: ['Yes', 'Cancel'],
- defaultId: 1,
- title: 'Reset App Data',
- message: 'This will sign you out from all your teams and reset the app back to its original settings. This cannot be undone.'
- }, (response) => {
- if (response === 0) {
- const dataDir = remote.app.getPath('userData');
- jetpack.remove(dataDir);
- remote.app.relaunch();
- remote.app.quit();
- }
- });
- }
+ constructor() {
+ super();
+ this.load();
+ const processProtocol = this.getProtocolUrlFromProcess(remote.process.argv);
+ if (processProtocol) {
+ this.showHostConfirmation(processProtocol);
+ }
+ ipcRenderer.on('add-host', (e, host) => {
+ if (this.hostExists(host)) {
+ this.setActive(host);
+ } else {
+ this.showHostConfirmation(host);
+ }
+ });
+ }
+
+ get hosts() {
+ return this._hosts;
+ }
+
+ set hosts(hosts) {
+ this._hosts = hosts;
+ this.save();
+ return true;
+ }
+
+ get hostsKey() {
+ return 'rocket.chat.hosts';
+ }
+
+ get activeKey() {
+ return 'rocket.chat.currentHost';
+ }
+
+ load() {
+ let hosts = localStorage.getItem(this.hostsKey);
+
+ try {
+ hosts = JSON.parse(hosts);
+ } catch (e) {
+ if (typeof hosts === 'string' && hosts.match(/^https?:\/\//)) {
+ hosts = {};
+ hosts[hosts] = {
+ title: hosts,
+ url: hosts,
+ };
+ }
+
+ localStorage.setItem(this.hostsKey, JSON.stringify(hosts));
+ }
+
+ if (hosts === null) {
+ hosts = {};
+ }
+
+ if (Array.isArray(hosts)) {
+ const oldHosts = hosts;
+ hosts = {};
+ oldHosts.forEach(function(item) {
+ item = item.replace(/\/$/, '');
+ hosts[item] = {
+ title: item,
+ url: item,
+ };
+ });
+ localStorage.setItem(this.hostsKey, JSON.stringify(hosts));
+ }
+
+ // Load server info from server config file
+ if (Object.keys(hosts).length === 0) {
+ const path = jetpack.find(remote.app.getPath('userData'), { matching: 'servers.json' })[0] ||
+ jetpack.find(jetpack.path(remote.app.getAppPath(), '..'), { matching: 'servers.json' })[0];
+
+ if (path) {
+ const pathToServerJson = jetpack.path(path);
+
+ try {
+ const result = jetpack.read(pathToServerJson, 'json');
+ if (result) {
+ hosts = {};
+ Object.keys(result).forEach((title) => {
+ const url = result[title];
+ hosts[url] = { title, url };
+ });
+ localStorage.setItem(this.hostsKey, JSON.stringify(hosts));
+ // Assume user doesn't want sidebar if they only have one server
+ if (Object.keys(hosts).length === 1) {
+ localStorage.setItem('sidebar-closed', 'true');
+ }
+ }
+
+ } catch (e) {
+ console.error('Server file invalid');
+ }
+ }
+ }
+
+ this._hosts = hosts;
+ remoteServers.loadServers(this._hosts);
+ this.emit('loaded');
+ }
+
+ save() {
+ localStorage.setItem(this.hostsKey, JSON.stringify(this._hosts));
+ this.emit('saved');
+ }
+
+ get(hostUrl) {
+ return this.hosts[hostUrl];
+ }
+
+ forEach(cb) {
+ for (const host in this.hosts) {
+ if (this.hosts.hasOwnProperty(host)) {
+ cb(this.hosts[host]);
+ }
+ }
+ }
+
+ validateHost(hostUrl, timeout) {
+ timeout = timeout || 5000;
+ return new Promise(function(resolve, reject) {
+ let resolved = false;
+ $.getJSON(`${ hostUrl }/api/info`).then(function() {
+ if (resolved) {
+ return;
+ }
+ resolved = true;
+ resolve();
+ }, function(request) {
+ if (request.status === 401) {
+ const authHeader = request.getResponseHeader('www-authenticate');
+ if (authHeader && authHeader.toLowerCase().indexOf('basic ') === 0) {
+ resolved = true;
+ reject('basic-auth');
+ }
+ }
+ if (resolved) {
+ return;
+ }
+ resolved = true;
+ reject('invalid');
+ });
+ if (timeout) {
+ setTimeout(function() {
+ if (resolved) {
+ return;
+ }
+ resolved = true;
+ reject('timeout');
+ }, timeout);
+ }
+ });
+ }
+
+ hostExists(hostUrl) {
+ const { hosts } = this;
+
+ return !!hosts[hostUrl];
+ }
+
+ addHost(hostUrl) {
+ const { hosts } = this;
+
+ const match = hostUrl.match(/^(https?:\/\/)([^:]+):([^@]+)@(.+)$/);
+ let username;
+ let password;
+ let authUrl;
+ if (match) {
+ authUrl = hostUrl;
+ hostUrl = match[1] + match[4];
+ username = match[2];
+ password = match[3];
+ }
+
+ if (this.hostExists(hostUrl) === true) {
+ this.setActive(hostUrl);
+ return false;
+ }
+
+ hosts[hostUrl] = {
+ title: hostUrl,
+ url: hostUrl,
+ authUrl,
+ username,
+ password,
+ };
+ this.hosts = hosts;
+
+ remoteServers.loadServers(this.hosts);
+
+ this.emit('host-added', hostUrl);
+
+ return hostUrl;
+ }
+
+ removeHost(hostUrl) {
+ const { hosts } = this;
+ if (hosts[hostUrl]) {
+ delete hosts[hostUrl];
+ this.hosts = hosts;
+
+ remoteServers.loadServers(this.hosts);
+
+ if (this.active === hostUrl) {
+ this.clearActive();
+ }
+ this.emit('host-removed', hostUrl);
+ }
+ }
+
+ get active() {
+ return localStorage.getItem(this.activeKey);
+ }
+
+ setActive(hostUrl) {
+ let url;
+ if (this.hostExists(hostUrl)) {
+ url = hostUrl;
+ } else if (Object.keys(this._hosts).length > 0) {
+ url = Object.keys(this._hosts)[0];
+ }
+
+ if (url) {
+ localStorage.setItem(this.activeKey, hostUrl);
+ this.emit('active-setted', url);
+ return true;
+ }
+ this.emit('loaded');
+ return false;
+ }
+
+ restoreActive() {
+ this.setActive(this.active);
+ }
+
+ clearActive() {
+ localStorage.removeItem(this.activeKey);
+ this.emit('active-cleared');
+ return true;
+ }
+
+ setHostTitle(hostUrl, title) {
+ if (title === 'Rocket.Chat' && /https?:\/\/open\.rocket\.chat/.test(hostUrl) === false) {
+ title += ` - ${ hostUrl }`;
+ }
+ const { hosts } = this;
+ hosts[hostUrl].title = title;
+ this.hosts = hosts;
+ this.emit('title-setted', hostUrl, title);
+ }
+ getProtocolUrlFromProcess(args) {
+ let site = null;
+ if (args.length > 1) {
+ const protocolURI = args.find((arg) => arg.startsWith('rocketchat://'));
+ if (protocolURI) {
+ site = protocolURI.split(/\/|\?/)[2];
+ if (site) {
+ let scheme = 'https://';
+ if (protocolURI.includes('insecure=true')) {
+ scheme = 'http://';
+ }
+ site = scheme + site;
+ }
+ }
+ }
+ return site;
+ }
+ showHostConfirmation(host) {
+ return remote.dialog.showMessageBox({
+ type: 'question',
+ buttons: [i18n.__('Add'), i18n.__('Cancel')],
+ defaultId: 0,
+ title: i18n.__('Add_Server'),
+ message: i18n.__('Add_host_to_servers', host),
+ }, (response) => {
+ if (response === 0) {
+ this.validateHost(host)
+ .then(() => this.addHost(host))
+ .then(() => this.setActive(host))
+ .catch(() => remote.dialog.showErrorBox(i18n.__('Invalid_Host'), i18n.__('Host_not_validated', host)));
+ }
+ });
+ }
+
+ resetAppData() {
+ return remote.dialog.showMessageBox({
+ type: 'question',
+ buttons: ['Yes', 'Cancel'],
+ defaultId: 1,
+ title: 'Reset App Data',
+ message: 'This will sign you out from all your teams and reset the app back to its original settings. This cannot be undone.',
+ }, (response) => {
+ if (response === 0) {
+ const dataDir = remote.app.getPath('userData');
+ jetpack.remove(dataDir);
+ remote.app.relaunch();
+ remote.app.quit();
+ }
+ });
+ }
}
diff --git a/src/scripts/sidebar.js b/src/scripts/sidebar.js
index 5d084122cf..3cf7fac97e 100644
--- a/src/scripts/sidebar.js
+++ b/src/scripts/sidebar.js
@@ -6,309 +6,309 @@ import webview from './webview';
import * as menus from './menus';
class SideBar extends EventEmitter {
- constructor () {
- super();
-
- this.sortOrder = JSON.parse(localStorage.getItem(this.sortOrderKey)) || [];
- localStorage.setItem(this.sortOrderKey, JSON.stringify(this.sortOrder));
-
- this.listElement = document.getElementById('serverList');
-
- Object.values(servers.hosts)
- .sort((a, b) => this.sortOrder.indexOf(a.url) - this.sortOrder.indexOf(b.url))
- .forEach((host) => {
- this.add(host);
- });
-
- servers.on('host-added', (hostUrl) => {
- this.add(servers.get(hostUrl));
- });
-
- servers.on('host-removed', (hostUrl) => {
- this.remove(hostUrl);
- });
-
- servers.on('active-setted', (hostUrl) => {
- this.setActive(hostUrl);
- });
-
- servers.on('active-cleared', (hostUrl) => {
- this.deactiveAll(hostUrl);
- });
-
- servers.on('title-setted', (hostUrl, title) => {
- this.setLabel(hostUrl, title);
- });
-
- webview.on('dom-ready', (hostUrl) => {
- this.setActive(localStorage.getItem(servers.activeKey));
- webview.getActive().send('request-sidebar-color');
- this.setImage(hostUrl);
- if (this.isHidden()) {
- this.hide();
- } else {
- this.show();
- }
- });
-
- }
-
- get sortOrderKey () {
- return 'rocket.chat.sortOrder';
- }
-
- add (host) {
- let name = host.title.replace(/^https?:\/\/(?:www\.)?([^\/]+)(.*)/, '$1');
- name = name.split('.');
- name = name[0][0] + (name[1] ? name[1][0] : '');
- name = name.toUpperCase();
-
- const initials = document.createElement('span');
- initials.innerHTML = name;
-
- const tooltip = document.createElement('div');
- tooltip.classList.add('tooltip');
- tooltip.innerHTML = host.title;
-
- const badge = document.createElement('div');
- badge.classList.add('badge');
-
- const img = document.createElement('img');
- img.onload = function () {
- img.style.display = 'initial';
- initials.style.display = 'none';
- };
-
- let hostOrder = 0;
- if (this.sortOrder.includes(host.url)) {
- hostOrder = this.sortOrder.indexOf(host.url) + 1;
- } else {
- hostOrder = this.sortOrder.length + 1;
- this.sortOrder.push(host.url);
- }
-
- const hotkey = document.createElement('div');
- hotkey.classList.add('name');
- if (process.platform === 'darwin') {
- hotkey.innerHTML = `⌘${hostOrder}`;
- } else {
- hotkey.innerHTML = `^${hostOrder}`;
- }
-
- const item = document.createElement('li');
- item.appendChild(initials);
- item.appendChild(tooltip);
- item.appendChild(badge);
- item.appendChild(img);
- item.appendChild(hotkey);
-
- item.dataset.host = host.url;
- item.dataset.sortOrder = hostOrder;
- item.setAttribute('server', host.url);
- item.classList.add('instance');
-
- item.setAttribute('draggable', true);
-
- item.ondragstart = (event) => {
- window.dragged = event.target.nodeName !== 'LI' ? event.target.closest('li') : event.target;
- event.dataTransfer.effectAllowed = 'move';
- event.dataTransfer.dropEffect = 'move';
- event.target.style.opacity = .5;
- };
-
- item.ondragover = (event) => {
- event.preventDefault();
- };
-
- item.ondragenter = (event) => {
- if (this.isBefore(window.dragged, event.target)) {
- event.currentTarget.parentNode.insertBefore(window.dragged, event.currentTarget);
- } else if (event.currentTarget !== event.currentTarget.parentNode.lastChild) {
- event.currentTarget.parentNode.insertBefore(window.dragged, event.currentTarget.nextSibling);
- } else {
- event.currentTarget.parentNode.appendChild(window.dragged);
- }
- };
-
- item.ondragend = (event) => {
- event.target.style.opacity = '';
- };
-
- item.ondrop = (event) => {
- event.preventDefault();
-
- const newSortOrder = [];
- Array.from(event.currentTarget.parentNode.children)
- .map((sideBarElement) => {
- const url = sideBarElement.dataset.host;
- newSortOrder.push(url);
- this.remove(url);
-
- return sideBarElement;
- })
- .map((sideBarElement) => {
- this.sortOrder = newSortOrder;
- localStorage.setItem(this.sortOrderKey, JSON.stringify(this.sortOrder));
-
- const url = sideBarElement.dataset.host;
- const host = { url, title: sideBarElement.querySelector('div.tooltip').innerHTML };
- this.add(host);
- this.setImage(url);
- });
-
- this.setActive(window.dragged.dataset.host);
- };
-
- item.onclick = () => {
- servers.setActive(host.url);
- };
-
- this.listElement.appendChild(item);
- menus.addServer(host, hostOrder);
- }
-
- setImage (hostUrl) {
- const img = this.getByUrl(hostUrl).querySelector('img');
- img.src = `${hostUrl}/assets/favicon.svg?v=${Math.round(Math.random()*10000)}`;
- }
-
- remove (hostUrl) {
- const el = this.getByUrl(hostUrl);
- if (el) {
- el.remove();
- menus.removeServer(hostUrl);
- }
- }
-
- getByUrl (hostUrl) {
- return this.listElement.querySelector(`.instance[server="${hostUrl}"]`);
- }
-
- getActive () {
- return this.listElement.querySelector('.instance.active');
- }
-
- isActive (hostUrl) {
- return !!this.listElement.querySelector(`.instance.active[server="${hostUrl}"]`);
- }
-
- changeSidebarColor ({color, background}) {
- const sidebar = document.querySelector('.server-list');
- if (sidebar) {
- sidebar.style.background = background;
- sidebar.style.color = color;
- }
- }
-
- setActive (hostUrl) {
- if (this.isActive(hostUrl)) {
- return;
- }
-
- this.deactiveAll();
- const item = this.getByUrl(hostUrl);
- if (item) {
- item.classList.add('active');
- }
- webview.getActive().send && webview.getActive().send('request-sidebar-color');
- }
-
- deactiveAll () {
- let item;
- while (!(item = this.getActive()) === false) {
- item.classList.remove('active');
- }
- }
-
- setLabel (hostUrl, label) {
- this.listElement.querySelector(`.instance[server="${hostUrl}"] .tooltip`).innerHTML = label;
- }
-
- setBadge (hostUrl, badge) {
- const item = this.getByUrl(hostUrl);
- const badgeEl = item.querySelector('.badge');
-
- if (badge !== null && badge !== undefined && badge !== '') {
- item.classList.add('unread');
- if (isNaN(parseInt(badge))) {
- badgeEl.innerHTML = '';
- } else {
- badgeEl.innerHTML = badge;
- }
- } else {
- badge = undefined;
- item.classList.remove('unread');
- badgeEl.innerHTML = '';
- }
- this.emit('badge-setted', hostUrl, badge);
- }
-
- getGlobalBadge () {
- let count = 0;
- let title = '';
- const instanceEls = this.listElement.querySelectorAll('li.instance');
- for (let i = instanceEls.length - 1; i >= 0; i--) {
- const instanceEl = instanceEls[i];
- const text = instanceEl.querySelector('.badge').innerHTML;
- if (!isNaN(parseInt(text))) {
- count += parseInt(text);
- }
- if (title === '' && instanceEl.classList.contains('unread') === true) {
- title = '•';
- }
- }
- if (count > 0) {
- title = count.toString();
- }
- return {
- count: count,
- title: title,
- showAlert: (title !== '')
- };
- }
-
- hide () {
- document.body.classList.add('hide-server-list');
- localStorage.setItem('sidebar-closed', 'true');
- this.emit('hide');
- if (process.platform === 'darwin') {
- document.querySelectorAll('webview').forEach(
- (webviewObj) => { if (webviewObj.insertCSS) { webviewObj.insertCSS('aside.side-nav{margin-top:15px;overflow:hidden; transition: margin .5s ease-in-out; } .sidebar{padding-top:10px;transition: margin .5s ease-in-out;}'); } });
- }
- }
-
- show () {
- document.body.classList.remove('hide-server-list');
- localStorage.setItem('sidebar-closed', 'false');
- this.emit('show');
- if (process.platform === 'darwin') {
- document.querySelectorAll('webview').forEach(
- (webviewObj) => { if (webviewObj.insertCSS) { webviewObj.insertCSS('aside.side-nav{margin-top:0; overflow:hidden; transition: margin .5s ease-in-out;} .sidebar{padding-top:0;transition: margin .5s ease-in-out;}'); } });
- }
- }
-
- toggle () {
- if (this.isHidden()) {
- this.show();
- } else {
- this.hide();
- }
- }
-
- isHidden () {
- return localStorage.getItem('sidebar-closed') === 'true';
- }
-
- isBefore (a, b) {
- if (a.parentNode === b.parentNode) {
- for (let cur = a; cur; cur = cur.previousSibling) {
- if (cur === b) {
- return true;
- }
- }
- }
- return false;
- }
+ constructor() {
+ super();
+
+ this.sortOrder = JSON.parse(localStorage.getItem(this.sortOrderKey)) || [];
+ localStorage.setItem(this.sortOrderKey, JSON.stringify(this.sortOrder));
+
+ this.listElement = document.getElementById('serverList');
+
+ Object.values(servers.hosts)
+ .sort((a, b) => this.sortOrder.indexOf(a.url) - this.sortOrder.indexOf(b.url))
+ .forEach((host) => {
+ this.add(host);
+ });
+
+ servers.on('host-added', (hostUrl) => {
+ this.add(servers.get(hostUrl));
+ });
+
+ servers.on('host-removed', (hostUrl) => {
+ this.remove(hostUrl);
+ });
+
+ servers.on('active-setted', (hostUrl) => {
+ this.setActive(hostUrl);
+ });
+
+ servers.on('active-cleared', (hostUrl) => {
+ this.deactiveAll(hostUrl);
+ });
+
+ servers.on('title-setted', (hostUrl, title) => {
+ this.setLabel(hostUrl, title);
+ });
+
+ webview.on('dom-ready', (hostUrl) => {
+ this.setActive(localStorage.getItem(servers.activeKey));
+ webview.getActive().send('request-sidebar-color');
+ this.setImage(hostUrl);
+ if (this.isHidden()) {
+ this.hide();
+ } else {
+ this.show();
+ }
+ });
+
+ }
+
+ get sortOrderKey() {
+ return 'rocket.chat.sortOrder';
+ }
+
+ add(host) {
+ let name = host.title.replace(/^https?:\/\/(?:www\.)?([^\/]+)(.*)/, '$1');
+ name = name.split('.');
+ name = name[0][0] + (name[1] ? name[1][0] : '');
+ name = name.toUpperCase();
+
+ const initials = document.createElement('span');
+ initials.innerHTML = name;
+
+ const tooltip = document.createElement('div');
+ tooltip.classList.add('tooltip');
+ tooltip.innerHTML = host.title;
+
+ const badge = document.createElement('div');
+ badge.classList.add('badge');
+
+ const img = document.createElement('img');
+ img.onload = function() {
+ img.style.display = 'initial';
+ initials.style.display = 'none';
+ };
+
+ let hostOrder = 0;
+ if (this.sortOrder.includes(host.url)) {
+ hostOrder = this.sortOrder.indexOf(host.url) + 1;
+ } else {
+ hostOrder = this.sortOrder.length + 1;
+ this.sortOrder.push(host.url);
+ }
+
+ const hotkey = document.createElement('div');
+ hotkey.classList.add('name');
+ if (process.platform === 'darwin') {
+ hotkey.innerHTML = `⌘${ hostOrder }`;
+ } else {
+ hotkey.innerHTML = `^${ hostOrder }`;
+ }
+
+ const item = document.createElement('li');
+ item.appendChild(initials);
+ item.appendChild(tooltip);
+ item.appendChild(badge);
+ item.appendChild(img);
+ item.appendChild(hotkey);
+
+ item.dataset.host = host.url;
+ item.dataset.sortOrder = hostOrder;
+ item.setAttribute('server', host.url);
+ item.classList.add('instance');
+
+ item.setAttribute('draggable', true);
+
+ item.ondragstart = (event) => {
+ window.dragged = event.target.nodeName !== 'LI' ? event.target.closest('li') : event.target;
+ event.dataTransfer.effectAllowed = 'move';
+ event.dataTransfer.dropEffect = 'move';
+ event.target.style.opacity = .5;
+ };
+
+ item.ondragover = (event) => {
+ event.preventDefault();
+ };
+
+ item.ondragenter = (event) => {
+ if (this.isBefore(window.dragged, event.target)) {
+ event.currentTarget.parentNode.insertBefore(window.dragged, event.currentTarget);
+ } else if (event.currentTarget !== event.currentTarget.parentNode.lastChild) {
+ event.currentTarget.parentNode.insertBefore(window.dragged, event.currentTarget.nextSibling);
+ } else {
+ event.currentTarget.parentNode.appendChild(window.dragged);
+ }
+ };
+
+ item.ondragend = (event) => {
+ event.target.style.opacity = '';
+ };
+
+ item.ondrop = (event) => {
+ event.preventDefault();
+
+ const newSortOrder = [];
+ Array.from(event.currentTarget.parentNode.children)
+ .map((sideBarElement) => {
+ const url = sideBarElement.dataset.host;
+ newSortOrder.push(url);
+ this.remove(url);
+
+ return sideBarElement;
+ })
+ .forEach((sideBarElement) => {
+ this.sortOrder = newSortOrder;
+ localStorage.setItem(this.sortOrderKey, JSON.stringify(this.sortOrder));
+
+ const url = sideBarElement.dataset.host;
+ const host = { url, title: sideBarElement.querySelector('div.tooltip').innerHTML };
+ this.add(host);
+ this.setImage(url);
+ });
+
+ this.setActive(window.dragged.dataset.host);
+ };
+
+ item.onclick = () => {
+ servers.setActive(host.url);
+ };
+
+ this.listElement.appendChild(item);
+ menus.addServer(host, hostOrder);
+ }
+
+ setImage(hostUrl) {
+ const img = this.getByUrl(hostUrl).querySelector('img');
+ img.src = `${ hostUrl }/assets/favicon.svg?v=${ Math.round(Math.random() * 10000) }`;
+ }
+
+ remove(hostUrl) {
+ const el = this.getByUrl(hostUrl);
+ if (el) {
+ el.remove();
+ menus.removeServer(hostUrl);
+ }
+ }
+
+ getByUrl(hostUrl) {
+ return this.listElement.querySelector(`.instance[server="${ hostUrl }"]`);
+ }
+
+ getActive() {
+ return this.listElement.querySelector('.instance.active');
+ }
+
+ isActive(hostUrl) {
+ return !!this.listElement.querySelector(`.instance.active[server="${ hostUrl }"]`);
+ }
+
+ changeSidebarColor({ color, background }) {
+ const sidebar = document.querySelector('.server-list');
+ if (sidebar) {
+ sidebar.style.background = background;
+ sidebar.style.color = color;
+ }
+ }
+
+ setActive(hostUrl) {
+ if (this.isActive(hostUrl)) {
+ return;
+ }
+
+ this.deactiveAll();
+ const item = this.getByUrl(hostUrl);
+ if (item) {
+ item.classList.add('active');
+ }
+ webview.getActive().send && webview.getActive().send('request-sidebar-color');
+ }
+
+ deactiveAll() {
+ let item;
+ while (!(item = this.getActive()) === false) {
+ item.classList.remove('active');
+ }
+ }
+
+ setLabel(hostUrl, label) {
+ this.listElement.querySelector(`.instance[server="${ hostUrl }"] .tooltip`).innerHTML = label;
+ }
+
+ setBadge(hostUrl, badge) {
+ const item = this.getByUrl(hostUrl);
+ const badgeEl = item.querySelector('.badge');
+
+ if (badge !== null && badge !== undefined && badge !== '') {
+ item.classList.add('unread');
+ if (isNaN(parseInt(badge))) {
+ badgeEl.innerHTML = '';
+ } else {
+ badgeEl.innerHTML = badge;
+ }
+ } else {
+ badge = undefined;
+ item.classList.remove('unread');
+ badgeEl.innerHTML = '';
+ }
+ this.emit('badge-setted', hostUrl, badge);
+ }
+
+ getGlobalBadge() {
+ let count = 0;
+ let title = '';
+ const instanceEls = this.listElement.querySelectorAll('li.instance');
+ for (let i = instanceEls.length - 1; i >= 0; i--) {
+ const instanceEl = instanceEls[i];
+ const text = instanceEl.querySelector('.badge').innerHTML;
+ if (!isNaN(parseInt(text))) {
+ count += parseInt(text);
+ }
+ if (title === '' && instanceEl.classList.contains('unread') === true) {
+ title = '•';
+ }
+ }
+ if (count > 0) {
+ title = count.toString();
+ }
+ return {
+ count,
+ title,
+ showAlert: (title !== ''),
+ };
+ }
+
+ hide() {
+ document.body.classList.add('hide-server-list');
+ localStorage.setItem('sidebar-closed', 'true');
+ this.emit('hide');
+ if (process.platform === 'darwin') {
+ document.querySelectorAll('webview').forEach(
+ (webviewObj) => { if (webviewObj.insertCSS) { webviewObj.insertCSS('aside.side-nav{margin-top:15px;overflow:hidden; transition: margin .5s ease-in-out; } .sidebar{padding-top:10px;transition: margin .5s ease-in-out;}'); } });
+ }
+ }
+
+ show() {
+ document.body.classList.remove('hide-server-list');
+ localStorage.setItem('sidebar-closed', 'false');
+ this.emit('show');
+ if (process.platform === 'darwin') {
+ document.querySelectorAll('webview').forEach(
+ (webviewObj) => { if (webviewObj.insertCSS) { webviewObj.insertCSS('aside.side-nav{margin-top:0; overflow:hidden; transition: margin .5s ease-in-out;} .sidebar{padding-top:0;transition: margin .5s ease-in-out;}'); } });
+ }
+ }
+
+ toggle() {
+ if (this.isHidden()) {
+ this.show();
+ } else {
+ this.hide();
+ }
+ }
+
+ isHidden() {
+ return localStorage.getItem('sidebar-closed') === 'true';
+ }
+
+ isBefore(a, b) {
+ if (a.parentNode === b.parentNode) {
+ for (let cur = a; cur; cur = cur.previousSibling) {
+ if (cur === b) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
export default new SideBar();
@@ -316,57 +316,57 @@ export default new SideBar();
let selectedInstance = null;
const instanceMenu = remote.Menu.buildFromTemplate([{
- label: i18n.__('Reload_server'),
- click: function () {
- webview.getByUrl(selectedInstance.dataset.host).reload();
- }
+ label: i18n.__('Reload_server'),
+ click() {
+ webview.getByUrl(selectedInstance.dataset.host).reload();
+ },
}, {
- label: i18n.__('Remove_server'),
- click: function () {
- servers.removeHost(selectedInstance.dataset.host);
- }
+ label: i18n.__('Remove_server'),
+ click() {
+ servers.removeHost(selectedInstance.dataset.host);
+ },
}, {
- label: i18n.__('Open_DevTools'),
- click: function () {
- webview.getByUrl(selectedInstance.dataset.host).openDevTools();
- }
+ label: i18n.__('Open_DevTools'),
+ click() {
+ webview.getByUrl(selectedInstance.dataset.host).openDevTools();
+ },
}]);
-window.addEventListener('contextmenu', function (e) {
- if (e.target.classList.contains('instance') || e.target.parentNode.classList.contains('instance')) {
- e.preventDefault();
- if (e.target.classList.contains('instance')) {
- selectedInstance = e.target;
- } else {
- selectedInstance = e.target.parentNode;
- }
-
- instanceMenu.popup(remote.getCurrentWindow());
- }
+window.addEventListener('contextmenu', function(e) {
+ if (e.target.classList.contains('instance') || e.target.parentNode.classList.contains('instance')) {
+ e.preventDefault();
+ if (e.target.classList.contains('instance')) {
+ selectedInstance = e.target;
+ } else {
+ selectedInstance = e.target.parentNode;
+ }
+
+ instanceMenu.popup(remote.getCurrentWindow());
+ }
}, false);
if (process.platform === 'darwin') {
- window.addEventListener('keydown', function (e) {
- if (e.key === 'Meta') {
- document.getElementsByClassName('server-list')[0].classList.add('command-pressed');
- }
- });
-
- window.addEventListener('keyup', function (e) {
- if (e.key === 'Meta') {
- document.getElementsByClassName('server-list')[0].classList.remove('command-pressed');
- }
- });
+ window.addEventListener('keydown', function(e) {
+ if (e.key === 'Meta') {
+ document.getElementsByClassName('server-list')[0].classList.add('command-pressed');
+ }
+ });
+
+ window.addEventListener('keyup', function(e) {
+ if (e.key === 'Meta') {
+ document.getElementsByClassName('server-list')[0].classList.remove('command-pressed');
+ }
+ });
} else {
- window.addEventListener('keydown', function (e) {
- if (e.key === 'ctrlKey') {
- document.getElementsByClassName('server-list')[0].classList.add('command-pressed');
- }
- });
-
- window.addEventListener('keyup', function (e) {
- if (e.key === 'ctrlKey') {
- document.getElementsByClassName('server-list')[0].classList.remove('command-pressed');
- }
- });
+ window.addEventListener('keydown', function(e) {
+ if (e.key === 'ctrlKey') {
+ document.getElementsByClassName('server-list')[0].classList.add('command-pressed');
+ }
+ });
+
+ window.addEventListener('keyup', function(e) {
+ if (e.key === 'ctrlKey') {
+ document.getElementsByClassName('server-list')[0].classList.remove('command-pressed');
+ }
+ });
}
diff --git a/src/scripts/start.js b/src/scripts/start.js
index ecf3cc1bfe..ee7f6aa776 100644
--- a/src/scripts/start.js
+++ b/src/scripts/start.js
@@ -8,183 +8,183 @@ import webview from './webview';
import tray from './tray';
import './menus';
-sidebar.on('badge-setted', function () {
- const badge = sidebar.getGlobalBadge();
- tray.showTrayAlert(badge);
+sidebar.on('badge-setted', function() {
+ const badge = sidebar.getGlobalBadge();
+ tray.showTrayAlert(badge);
});
-export const start = function () {
- const defaultInstance = 'https://open.rocket.chat';
-
- // connection check
- function online () {
- document.body.classList.remove('offline');
- }
-
- function offline () {
- document.body.classList.add('offline');
- }
-
- if (!navigator.onLine) {
- offline();
- }
- window.addEventListener('online', online);
- window.addEventListener('offline', offline);
- // end connection check
-
- const form = document.querySelector('form');
- const hostField = form.querySelector('[name="host"]');
- const button = form.querySelector('[type="submit"]');
- const invalidUrl = form.querySelector('#invalidUrl');
-
- window.addEventListener('load', function () {
- hostField.focus();
- });
-
- function validateHost () {
- return new Promise(function (resolve, reject) {
- const execValidation = function () {
- invalidUrl.style.display = 'none';
- hostField.classList.remove('wrong');
-
- const host = hostField.value.trim();
- hostField.value = host;
-
- if (host.length === 0) {
- button.value = i18n.__('Connect');
- button.disabled = false;
- resolve();
- return;
- }
-
- button.value = i18n.__('Validating');
- button.disabled = true;
-
- servers.validateHost(host, 2000).then(function () {
- button.value = i18n.__('Connect');
- button.disabled = false;
- resolve();
- }, function (status) {
- // If the url begins with HTTP, mark as invalid
- if (/^https?:\/\/.+/.test(host) || status === 'basic-auth') {
- button.value = i18n.__('Invalid_url');
- invalidUrl.style.display = 'block';
- switch (status) {
- case 'basic-auth':
- invalidUrl.innerHTML = i18n.__('Auth_needed_try', 'username:password@host');
- break;
- case 'invalid':
- invalidUrl.innerHTML = i18n.__('No_valid_server_found');
- break;
- case 'timeout':
- invalidUrl.innerHTML = i18n.__('Timeout_trying_to_connect');
- break;
- }
- hostField.classList.add('wrong');
- reject();
- return;
- }
-
- // // If the url begins with HTTPS, fallback to HTTP
- // if (/^https:\/\/.+/.test(host)) {
- // hostField.value = host.replace('https://', 'http://');
- // return execValidation();
- // }
-
- // If the url isn't localhost, don't have dots and don't have protocol
- // try as a .rocket.chat subdomain
- if (!/(^https?:\/\/)|(\.)|(^([^:]+:[^@]+@)?localhost(:\d+)?$)/.test(host)) {
- hostField.value = `https://${host}.rocket.chat`;
- return execValidation();
- }
-
- // If the url don't start with protocol try HTTPS
- if (!/^https?:\/\//.test(host)) {
- hostField.value = `https://${host}`;
- return execValidation();
- }
- });
- };
- execValidation();
- });
- }
-
- hostField.addEventListener('blur', function () {
- validateHost().then(function () {}, function () {});
- });
-
- ipcRenderer.on('certificate-reload', function (event, url) {
- hostField.value = url.replace(/\/api\/info$/, '');
- validateHost().then(function () {}, function () {});
- });
-
- ipcRenderer.on('render-taskbar-icon', (event, messageCount) => {
- // Create a canvas from unread messages
- function createOverlayIcon (messageCount) {
- const canvas = document.createElement('canvas');
- canvas.height = 128;
- canvas.width = 128;
-
- const ctx = canvas.getContext('2d');
- ctx.beginPath();
-
- ctx.fillStyle = 'red';
- ctx.arc(64, 64, 64, 0, 2 * Math.PI);
- ctx.fill();
- ctx.fillStyle = '#ffffff';
- ctx.textAlign = 'center';
- canvas.style.letterSpacing = '-4px';
- ctx.font = 'bold 92px sans-serif';
- ctx.fillText(String(Math.min(99, messageCount)), 64, 98);
-
- return canvas;
- }
- ipcRenderer.send('update-taskbar-icon', createOverlayIcon(messageCount).toDataURL(), String(messageCount));
- });
-
- const submit = function () {
- validateHost().then(function () {
- const input = form.querySelector('[name="host"]');
- let url = input.value;
-
- if (url.length === 0) {
- url = defaultInstance;
- }
-
- url = servers.addHost(url);
- if (url !== false) {
- sidebar.show();
- servers.setActive(url);
- }
-
- input.value = '';
- }, function () {});
- };
-
- hostField.addEventListener('keydown', function (ev) {
- if (ev.which === 13) {
- ev.preventDefault();
- ev.stopPropagation();
- submit();
- return false;
- }
- });
-
- form.addEventListener('submit', function (ev) {
- ev.preventDefault();
- ev.stopPropagation();
- submit();
- return false;
- });
-
- $('.add-server').on('click', function () {
- servers.clearActive();
- webview.showLanding();
- });
-
- servers.restoreActive();
+export const start = function() {
+ const defaultInstance = 'https://open.rocket.chat';
+
+ // connection check
+ function online() {
+ document.body.classList.remove('offline');
+ }
+
+ function offline() {
+ document.body.classList.add('offline');
+ }
+
+ if (!navigator.onLine) {
+ offline();
+ }
+ window.addEventListener('online', online);
+ window.addEventListener('offline', offline);
+ // end connection check
+
+ const form = document.querySelector('form');
+ const hostField = form.querySelector('[name="host"]');
+ const button = form.querySelector('[type="submit"]');
+ const invalidUrl = form.querySelector('#invalidUrl');
+
+ window.addEventListener('load', function() {
+ hostField.focus();
+ });
+
+ function validateHost() {
+ return new Promise(function(resolve, reject) {
+ const execValidation = function() {
+ invalidUrl.style.display = 'none';
+ hostField.classList.remove('wrong');
+
+ const host = hostField.value.trim();
+ hostField.value = host;
+
+ if (host.length === 0) {
+ button.value = i18n.__('Connect');
+ button.disabled = false;
+ resolve();
+ return;
+ }
+
+ button.value = i18n.__('Validating');
+ button.disabled = true;
+
+ servers.validateHost(host, 2000).then(function() {
+ button.value = i18n.__('Connect');
+ button.disabled = false;
+ resolve();
+ }, function(status) {
+ // If the url begins with HTTP, mark as invalid
+ if (/^https?:\/\/.+/.test(host) || status === 'basic-auth') {
+ button.value = i18n.__('Invalid_url');
+ invalidUrl.style.display = 'block';
+ switch (status) {
+ case 'basic-auth':
+ invalidUrl.innerHTML = i18n.__('Auth_needed_try', 'username:password@host');
+ break;
+ case 'invalid':
+ invalidUrl.innerHTML = i18n.__('No_valid_server_found');
+ break;
+ case 'timeout':
+ invalidUrl.innerHTML = i18n.__('Timeout_trying_to_connect');
+ break;
+ }
+ hostField.classList.add('wrong');
+ reject();
+ return;
+ }
+
+ // // If the url begins with HTTPS, fallback to HTTP
+ // if (/^https:\/\/.+/.test(host)) {
+ // hostField.value = host.replace('https://', 'http://');
+ // return execValidation();
+ // }
+
+ // If the url isn't localhost, don't have dots and don't have protocol
+ // try as a .rocket.chat subdomain
+ if (!/(^https?:\/\/)|(\.)|(^([^:]+:[^@]+@)?localhost(:\d+)?$)/.test(host)) {
+ hostField.value = `https://${ host }.rocket.chat`;
+ return execValidation();
+ }
+
+ // If the url don't start with protocol try HTTPS
+ if (!/^https?:\/\//.test(host)) {
+ hostField.value = `https://${ host }`;
+ return execValidation();
+ }
+ });
+ };
+ execValidation();
+ });
+ }
+
+ hostField.addEventListener('blur', function() {
+ validateHost().then(function() {}, function() {});
+ });
+
+ ipcRenderer.on('certificate-reload', function(event, url) {
+ hostField.value = url.replace(/\/api\/info$/, '');
+ validateHost().then(function() {}, function() {});
+ });
+
+ ipcRenderer.on('render-taskbar-icon', (event, messageCount) => {
+ // Create a canvas from unread messages
+ function createOverlayIcon(messageCount) {
+ const canvas = document.createElement('canvas');
+ canvas.height = 128;
+ canvas.width = 128;
+
+ const ctx = canvas.getContext('2d');
+ ctx.beginPath();
+
+ ctx.fillStyle = 'red';
+ ctx.arc(64, 64, 64, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.fillStyle = '#ffffff';
+ ctx.textAlign = 'center';
+ canvas.style.letterSpacing = '-4px';
+ ctx.font = 'bold 92px sans-serif';
+ ctx.fillText(String(Math.min(99, messageCount)), 64, 98);
+
+ return canvas;
+ }
+ ipcRenderer.send('update-taskbar-icon', createOverlayIcon(messageCount).toDataURL(), String(messageCount));
+ });
+
+ const submit = function() {
+ validateHost().then(function() {
+ const input = form.querySelector('[name="host"]');
+ let url = input.value;
+
+ if (url.length === 0) {
+ url = defaultInstance;
+ }
+
+ url = servers.addHost(url);
+ if (url !== false) {
+ sidebar.show();
+ servers.setActive(url);
+ }
+
+ input.value = '';
+ }, function() {});
+ };
+
+ hostField.addEventListener('keydown', function(ev) {
+ if (ev.which === 13) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ submit();
+ return false;
+ }
+ });
+
+ form.addEventListener('submit', function(ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ submit();
+ return false;
+ });
+
+ $('.add-server').on('click', function() {
+ servers.clearActive();
+ webview.showLanding();
+ });
+
+ servers.restoreActive();
};
-window.addEventListener('focus', function () {
- webview.focusActive();
+window.addEventListener('focus', function() {
+ webview.focusActive();
});
diff --git a/src/scripts/tray.js b/src/scripts/tray.js
index bd1ca96c7b..f67cf66d77 100644
--- a/src/scripts/tray.js
+++ b/src/scripts/tray.js
@@ -9,187 +9,187 @@ const { Tray, Menu } = remote;
const mainWindow = remote.getCurrentWindow();
const icons = {
- win32: {
- dir: 'windows'
- },
- linux: {
- dir: 'linux'
- },
- darwin: {
- dir: 'osx'
- }
+ win32: {
+ dir: 'windows',
+ },
+ linux: {
+ dir: 'linux',
+ },
+ darwin: {
+ dir: 'osx',
+ },
};
const statusBullet = {
- online: '\u001B[32m•',
- away: '\u001B[33m•',
- busy: '\u001B[31m•',
- offline: '\u001B[37m•'
+ online: '\u001B[32m•',
+ away: '\u001B[33m•',
+ busy: '\u001B[31m•',
+ offline: '\u001B[37m•',
};
const messageCountColor = {
- white: '\u001B[37m',
- black: '\u001B[0m'
+ white: '\u001B[37m',
+ black: '\u001B[0m',
};
-function getTrayImagePath (badge) {
- let iconFilename;
- if (badge.title === '•') {
- iconFilename = "icon-tray-dot";
- } else if (badge.count > 0) {
- if (badge.count > 9) {
- iconFilename = "icon-tray-9plus";
- } else {
- iconFilename = `icon-tray-${badge.count}`;
- }
- } else if (badge.showAlert) {
- iconFilename = "icon-tray-alert";
- } else {
- iconFilename = "icon-tray-Template";
- }
-
- if (process.platform === 'win32') {
- iconFilename += ".ico";
- } else {
- iconFilename += ".png";
- }
-
- return path.join(__dirname, 'images', icons[process.platform].dir, iconFilename);
+function getTrayImagePath(badge) {
+ let iconFilename;
+ if (badge.title === '•') {
+ iconFilename = 'icon-tray-dot';
+ } else if (badge.count > 0) {
+ if (badge.count > 9) {
+ iconFilename = 'icon-tray-9plus';
+ } else {
+ iconFilename = `icon-tray-${ badge.count }`;
+ }
+ } else if (badge.showAlert) {
+ iconFilename = 'icon-tray-alert';
+ } else {
+ iconFilename = 'icon-tray-Template';
+ }
+
+ if (process.platform === 'win32') {
+ iconFilename += '.ico';
+ } else {
+ iconFilename += '.png';
+ }
+
+ return path.join(__dirname, 'images', icons[process.platform].dir, iconFilename);
}
-function createAppTray () {
- const _tray = new Tray(getTrayImagePath({title:'', count:0, showAlert:false}));
- mainWindow.tray = _tray;
-
- const contextMenuShow = Menu.buildFromTemplate([{
- label: i18n.__('Show'),
- click () {
- mainWindow.show();
- }
- }, {
- label: i18n.__('Quit'),
- click () {
- remote.app.quit();
- }
- }]);
-
- const contextMenuHide = Menu.buildFromTemplate([{
- label: i18n.__('Hide'),
- click () {
- mainWindow.hide();
- }
- }, {
- label: i18n.__('Quit'),
- click () {
- remote.app.quit();
- }
- }]);
-
- if (!mainWindow.isMinimized() && !mainWindow.isVisible()) {
- _tray.setContextMenu(contextMenuShow);
- } else {
- _tray.setContextMenu(contextMenuHide);
- }
-
- const onShow = function () {
- _tray.setContextMenu(contextMenuHide);
- };
-
- const onHide = function () {
- _tray.setContextMenu(contextMenuShow);
- };
-
- mainWindow.on('show', onShow);
- mainWindow.on('restore', onShow);
-
- mainWindow.on('hide', onHide);
- mainWindow.on('minimize', onHide);
-
- _tray.setToolTip(remote.app.getName());
-
- _tray.on('right-click', function (e, b) {
- _tray.popUpContextMenu(undefined, b);
- });
-
- _tray.on('click', () => {
- if (mainWindow.isVisible()) {
- return mainWindow.hide();
- }
-
- mainWindow.show();
- });
-
- mainWindow.destroyTray = function () {
- mainWindow.removeListener('show', onShow);
- mainWindow.removeListener('hide', onHide);
- _tray.destroy();
- };
+function createAppTray() {
+ const _tray = new Tray(getTrayImagePath({ title:'', count:0, showAlert:false }));
+ mainWindow.tray = _tray;
+
+ const contextMenuShow = Menu.buildFromTemplate([{
+ label: i18n.__('Show'),
+ click() {
+ mainWindow.show();
+ },
+ }, {
+ label: i18n.__('Quit'),
+ click() {
+ remote.app.quit();
+ },
+ }]);
+
+ const contextMenuHide = Menu.buildFromTemplate([{
+ label: i18n.__('Hide'),
+ click() {
+ mainWindow.hide();
+ },
+ }, {
+ label: i18n.__('Quit'),
+ click() {
+ remote.app.quit();
+ },
+ }]);
+
+ if (!mainWindow.isMinimized() && !mainWindow.isVisible()) {
+ _tray.setContextMenu(contextMenuShow);
+ } else {
+ _tray.setContextMenu(contextMenuHide);
+ }
+
+ const onShow = function() {
+ _tray.setContextMenu(contextMenuHide);
+ };
+
+ const onHide = function() {
+ _tray.setContextMenu(contextMenuShow);
+ };
+
+ mainWindow.on('show', onShow);
+ mainWindow.on('restore', onShow);
+
+ mainWindow.on('hide', onHide);
+ mainWindow.on('minimize', onHide);
+
+ _tray.setToolTip(remote.app.getName());
+
+ _tray.on('right-click', function(e, b) {
+ _tray.popUpContextMenu(undefined, b);
+ });
+
+ _tray.on('click', () => {
+ if (mainWindow.isVisible()) {
+ return mainWindow.hide();
+ }
+
+ mainWindow.show();
+ });
+
+ mainWindow.destroyTray = function() {
+ mainWindow.removeListener('show', onShow);
+ mainWindow.removeListener('hide', onHide);
+ _tray.destroy();
+ };
}
-function showTrayAlert (badge, status = 'online') {
- if (mainWindow.tray === null || mainWindow.tray === undefined) {
- return;
- }
-
- const trayDisplayed = localStorage.getItem('hideTray') !== 'true';
- const hasMentions = badge.showAlert && badge.count > 0;
-
- if (!mainWindow.isFocused()) {
- mainWindow.flashFrame(hasMentions);
- }
-
- if (process.platform === 'win32') {
- if (hasMentions) {
- mainWindow.webContents.send('render-taskbar-icon', badge.count);
- } else {
- mainWindow.setOverlayIcon(null, '');
- }
- }
-
- if (process.platform === 'darwin') {
- let countColor = messageCountColor['black'];
- if (remote.systemPreferences.isDarkMode()) {
- countColor = messageCountColor['white'];
- }
-
- let trayTitle = `${statusBullet[status]}`;
- if (hasMentions) {
- trayTitle = `${statusBullet[status]} ${countColor}${badge.title}`;
- }
- remote.app.dock.setBadge(badge.title);
- if (trayDisplayed) {
- mainWindow.tray.setTitle(trayTitle);
- }
- }
-
- if (process.platform === 'linux') {
- remote.app.setBadgeCount(badge.count);
- }
-
- if (trayDisplayed) {
- mainWindow.tray.setImage(getTrayImagePath(badge));
- }
+function showTrayAlert(badge, status = 'online') {
+ if (mainWindow.tray === null || mainWindow.tray === undefined) {
+ return;
+ }
+
+ const trayDisplayed = localStorage.getItem('hideTray') !== 'true';
+ const hasMentions = badge.showAlert && badge.count > 0;
+
+ if (!mainWindow.isFocused()) {
+ mainWindow.flashFrame(hasMentions);
+ }
+
+ if (process.platform === 'win32') {
+ if (hasMentions) {
+ mainWindow.webContents.send('render-taskbar-icon', badge.count);
+ } else {
+ mainWindow.setOverlayIcon(null, '');
+ }
+ }
+
+ if (process.platform === 'darwin') {
+ let countColor = messageCountColor.black;
+ if (remote.systemPreferences.isDarkMode()) {
+ countColor = messageCountColor.white;
+ }
+
+ let trayTitle = `${ statusBullet[status] }`;
+ if (hasMentions) {
+ trayTitle = `${ statusBullet[status] } ${ countColor }${ badge.title }`;
+ }
+ remote.app.dock.setBadge(badge.title);
+ if (trayDisplayed) {
+ mainWindow.tray.setTitle(trayTitle);
+ }
+ }
+
+ if (process.platform === 'linux') {
+ remote.app.setBadgeCount(badge.count);
+ }
+
+ if (trayDisplayed) {
+ mainWindow.tray.setImage(getTrayImagePath(badge));
+ }
}
-function removeAppTray () {
- mainWindow.destroyTray();
+function removeAppTray() {
+ mainWindow.destroyTray();
}
-function toggle () {
- if (localStorage.getItem('hideTray') === 'true') {
- createAppTray();
- localStorage.setItem('hideTray', 'false');
- } else {
- removeAppTray();
- localStorage.setItem('hideTray', 'true');
- }
+function toggle() {
+ if (localStorage.getItem('hideTray') === 'true') {
+ createAppTray();
+ localStorage.setItem('hideTray', 'false');
+ } else {
+ removeAppTray();
+ localStorage.setItem('hideTray', 'true');
+ }
}
if (localStorage.getItem('hideTray') !== 'true') {
- createAppTray();
+ createAppTray();
}
export default {
- showTrayAlert,
- toggle
+ showTrayAlert,
+ toggle,
};
diff --git a/src/scripts/webview.js b/src/scripts/webview.js
index 0a2931003c..f549be4f37 100644
--- a/src/scripts/webview.js
+++ b/src/scripts/webview.js
@@ -2,212 +2,212 @@ import { EventEmitter } from 'events';
import servers from './servers';
import sidebar from './sidebar';
import tray from './tray';
-import { desktopCapturer, ipcRenderer, shell } from 'electron';
+import { desktopCapturer, ipcRenderer } from 'electron';
class WebView extends EventEmitter {
- constructor () {
- super();
+ constructor() {
+ super();
- this.webviewParentElement = document.body;
+ this.webviewParentElement = document.body;
- servers.forEach((host) => {
- this.add(host);
- });
+ servers.forEach((host) => {
+ this.add(host);
+ });
- servers.on('host-added', (hostUrl) => {
- this.add(servers.get(hostUrl));
- });
+ servers.on('host-added', (hostUrl) => {
+ this.add(servers.get(hostUrl));
+ });
- servers.on('host-removed', (hostUrl) => {
- this.remove(hostUrl);
- });
+ servers.on('host-removed', (hostUrl) => {
+ this.remove(hostUrl);
+ });
- servers.on('active-setted', (hostUrl) => {
- this.setActive(hostUrl);
- });
+ servers.on('active-setted', (hostUrl) => {
+ this.setActive(hostUrl);
+ });
- servers.on('active-cleared', (hostUrl) => {
- this.deactiveAll(hostUrl);
- });
+ servers.on('active-cleared', (hostUrl) => {
+ this.deactiveAll(hostUrl);
+ });
- servers.once('loaded', () => {
- this.loaded();
- });
+ servers.once('loaded', () => {
+ this.loaded();
+ });
- ipcRenderer.on('screenshare-result', (e, result) => {
- const webviewObj = this.getActive();
- webviewObj.executeJavaScript(`
+ ipcRenderer.on('screenshare-result', (e, result) => {
+ const webviewObj = this.getActive();
+ webviewObj.executeJavaScript(`
window.parent.postMessage({
- sourceId: '${result}'
+ sourceId: '${ result }'
}, '*')
`);
- });
- }
-
- loaded () {
- document.querySelector('#loading').style.display = 'none';
- document.querySelector('#login-card').style.display = 'block';
- document.querySelector('footer').style.display = 'block';
- }
-
- loading () {
- document.querySelector('#loading').style.display = 'block';
- document.querySelector('#login-card').style.display = 'none';
- document.querySelector('footer').style.display = 'none';
- }
-
- add (host) {
- let webviewObj = this.getByUrl(host.url);
- if (webviewObj) {
- return;
- }
-
- webviewObj = document.createElement('webview');
- webviewObj.setAttribute('server', host.url);
- webviewObj.setAttribute('preload', './preload.js');
- webviewObj.setAttribute('allowpopups', 'on');
- webviewObj.setAttribute('disablewebsecurity', 'on');
-
- webviewObj.addEventListener('did-navigate-in-page', (lastPath) => {
- if ((lastPath.url).includes(host.url)) {
- this.saveLastPath(host.url, lastPath.url);
- }
- });
-
- webviewObj.addEventListener('console-message', (e) => {
- console.log('webview:', e.message);
- });
-
- webviewObj.addEventListener('ipc-message', (event) => {
- this.emit('ipc-message-'+event.channel, host.url, event.args);
-
- switch (event.channel) {
- case 'title-changed':
- servers.setHostTitle(host.url, event.args[0]);
- break;
- case 'unread-changed':
- sidebar.setBadge(host.url, event.args[0]);
- break;
- case 'focus':
- servers.setActive(host.url);
- break;
- case 'user-status-manually-set':
- const badge = sidebar.getGlobalBadge();
- tray.showTrayAlert(badge, event.args[0]);
- break;
- case 'get-sourceId':
- desktopCapturer.getSources({types: ['window', 'screen']}, (error, sources) => {
- if (error) {
- throw error;
- }
-
- sources = sources.map(source => {
- source.thumbnail = source.thumbnail.toDataURL();
- return source;
- });
- ipcRenderer.send('screenshare', sources);
- });
- break;
- case 'reload-server':
- const active = this.getActive();
- const server = active.getAttribute('server');
- this.loading();
- active.loadURL(server);
- break;
- case 'sidebar-background':
- sidebar.changeSidebarColor(event.args[0]);
- break;
- }
- });
-
- webviewObj.addEventListener('dom-ready', () => {
- this.emit('dom-ready', host.url);
- });
-
- webviewObj.addEventListener('did-fail-load', (e) => {
- if (e.isMainFrame) {
- webviewObj.loadURL('file://' + __dirname + '/loading-error.html');
- }
- });
-
- webviewObj.addEventListener('did-get-response-details', (e) => {
- if (e.resourceType === 'mainFrame' && e.httpResponseCode >= 500) {
- webviewObj.loadURL('file://' + __dirname + '/loading-error.html');
- }
- });
-
- this.webviewParentElement.appendChild(webviewObj);
-
- webviewObj.src = host.lastPath || host.url;
- }
-
- remove (hostUrl) {
- const el = this.getByUrl(hostUrl);
- if (el) {
- el.remove();
- }
- }
-
- saveLastPath (hostUrl, lastPathUrl) {
- const hosts = servers.hosts;
- hosts[hostUrl].lastPath = lastPathUrl;
- servers.hosts = hosts;
- }
-
- getByUrl (hostUrl) {
- return this.webviewParentElement.querySelector(`webview[server="${hostUrl}"]`);
- }
-
- getActive () {
- return document.querySelector('webview.active');
- }
-
- isActive (hostUrl) {
- return !!this.webviewParentElement.querySelector(`webview.active[server="${hostUrl}"]`);
- }
-
- deactiveAll () {
- let item;
- while (!(item = this.getActive()) === false) {
- item.classList.remove('active');
- }
- document.querySelector('.landing-page').classList.add('hide');
- }
-
- showLanding () {
- this.loaded();
- document.querySelector('.landing-page').classList.remove('hide');
- }
-
- setActive (hostUrl) {
- if (this.isActive(hostUrl)) {
- return;
- }
-
- this.deactiveAll();
- const item = this.getByUrl(hostUrl);
- if (item) {
- item.classList.add('active');
- }
- this.focusActive();
- }
-
- focusActive () {
- const active = this.getActive();
- if (active) {
- active.focus();
- return true;
- }
- return false;
- }
-
- goBack () {
- this.getActive().goBack();
- }
-
- goForward () {
- this.getActive().goForward();
- }
+ });
+ }
+
+ loaded() {
+ document.querySelector('#loading').style.display = 'none';
+ document.querySelector('#login-card').style.display = 'block';
+ document.querySelector('footer').style.display = 'block';
+ }
+
+ loading() {
+ document.querySelector('#loading').style.display = 'block';
+ document.querySelector('#login-card').style.display = 'none';
+ document.querySelector('footer').style.display = 'none';
+ }
+
+ add(host) {
+ let webviewObj = this.getByUrl(host.url);
+ if (webviewObj) {
+ return;
+ }
+
+ webviewObj = document.createElement('webview');
+ webviewObj.setAttribute('server', host.url);
+ webviewObj.setAttribute('preload', './preload.js');
+ webviewObj.setAttribute('allowpopups', 'on');
+ webviewObj.setAttribute('disablewebsecurity', 'on');
+
+ webviewObj.addEventListener('did-navigate-in-page', (lastPath) => {
+ if ((lastPath.url).includes(host.url)) {
+ this.saveLastPath(host.url, lastPath.url);
+ }
+ });
+
+ webviewObj.addEventListener('console-message', (e) => {
+ console.log('webview:', e.message);
+ });
+
+ webviewObj.addEventListener('ipc-message', (event) => {
+ this.emit(`ipc-message-${ event.channel }`, host.url, event.args);
+
+ switch (event.channel) {
+ case 'title-changed':
+ servers.setHostTitle(host.url, event.args[0]);
+ break;
+ case 'unread-changed':
+ sidebar.setBadge(host.url, event.args[0]);
+ break;
+ case 'focus':
+ servers.setActive(host.url);
+ break;
+ case 'user-status-manually-set':
+ const badge = sidebar.getGlobalBadge();
+ tray.showTrayAlert(badge, event.args[0]);
+ break;
+ case 'get-sourceId':
+ desktopCapturer.getSources({ types: ['window', 'screen'] }, (error, sources) => {
+ if (error) {
+ throw error;
+ }
+
+ sources = sources.map((source) => {
+ source.thumbnail = source.thumbnail.toDataURL();
+ return source;
+ });
+ ipcRenderer.send('screenshare', sources);
+ });
+ break;
+ case 'reload-server':
+ const active = this.getActive();
+ const server = active.getAttribute('server');
+ this.loading();
+ active.loadURL(server);
+ break;
+ case 'sidebar-background':
+ sidebar.changeSidebarColor(event.args[0]);
+ break;
+ }
+ });
+
+ webviewObj.addEventListener('dom-ready', () => {
+ this.emit('dom-ready', host.url);
+ });
+
+ webviewObj.addEventListener('did-fail-load', (e) => {
+ if (e.isMainFrame) {
+ webviewObj.loadURL(`file://${ __dirname }/loading-error.html`);
+ }
+ });
+
+ webviewObj.addEventListener('did-get-response-details', (e) => {
+ if (e.resourceType === 'mainFrame' && e.httpResponseCode >= 500) {
+ webviewObj.loadURL(`file://${ __dirname }/loading-error.html`);
+ }
+ });
+
+ this.webviewParentElement.appendChild(webviewObj);
+
+ webviewObj.src = host.lastPath || host.url;
+ }
+
+ remove(hostUrl) {
+ const el = this.getByUrl(hostUrl);
+ if (el) {
+ el.remove();
+ }
+ }
+
+ saveLastPath(hostUrl, lastPathUrl) {
+ const { hosts } = servers;
+ hosts[hostUrl].lastPath = lastPathUrl;
+ servers.hosts = hosts;
+ }
+
+ getByUrl(hostUrl) {
+ return this.webviewParentElement.querySelector(`webview[server="${ hostUrl }"]`);
+ }
+
+ getActive() {
+ return document.querySelector('webview.active');
+ }
+
+ isActive(hostUrl) {
+ return !!this.webviewParentElement.querySelector(`webview.active[server="${ hostUrl }"]`);
+ }
+
+ deactiveAll() {
+ let item;
+ while (!(item = this.getActive()) === false) {
+ item.classList.remove('active');
+ }
+ document.querySelector('.landing-page').classList.add('hide');
+ }
+
+ showLanding() {
+ this.loaded();
+ document.querySelector('.landing-page').classList.remove('hide');
+ }
+
+ setActive(hostUrl) {
+ if (this.isActive(hostUrl)) {
+ return;
+ }
+
+ this.deactiveAll();
+ const item = this.getByUrl(hostUrl);
+ if (item) {
+ item.classList.add('active');
+ }
+ this.focusActive();
+ }
+
+ focusActive() {
+ const active = this.getActive();
+ if (active) {
+ active.focus();
+ return true;
+ }
+ return false;
+ }
+
+ goBack() {
+ this.getActive().goBack();
+ }
+
+ goForward() {
+ this.getActive().goForward();
+ }
}
export default new WebView();
diff --git a/tasks/build-app.js b/tasks/build-app.js
index d00913b530..75cf343d02 100644
--- a/tasks/build-app.js
+++ b/tasks/build-app.js
@@ -10,55 +10,45 @@ const bundle = require('./bundle');
const utils = require('./utils');
const { beepSound, srcDir, configDir, appDir } = require('./utils');
-gulp.task('public', () => {
- return gulp.src(srcDir.path('public/**/*'))
- .pipe(plumber())
- .pipe(gulp.dest(appDir.path('public')));
-});
+gulp.task('public', () => gulp.src(srcDir.path('public/**/*'))
+ .pipe(plumber())
+ .pipe(gulp.dest(appDir.path('public'))));
-gulp.task('i18n', () => {
- return gulp.src(srcDir.path('i18n/lang/**/*'))
- .pipe(plumber())
- .pipe(gulp.dest(appDir.path('i18n/lang')));
-});
+gulp.task('i18n', () => gulp.src(srcDir.path('i18n/lang/**/*'))
+ .pipe(plumber())
+ .pipe(gulp.dest(appDir.path('i18n/lang'))));
-gulp.task('bundle', () => {
- return Promise.all([
- bundle(srcDir.path('background.js'), appDir.path('background.js')),
- bundle(srcDir.path('app.js'), appDir.path('app.js')),
- bundle(srcDir.path('i18n/index.js'), appDir.path('i18n/index.js'))
- ]);
-});
+gulp.task('bundle', () => Promise.all([
+ bundle(srcDir.path('background.js'), appDir.path('background.js')),
+ bundle(srcDir.path('app.js'), appDir.path('app.js')),
+ bundle(srcDir.path('i18n/index.js'), appDir.path('i18n/index.js')),
+]));
-gulp.task('less', () => {
- return gulp.src(srcDir.path('stylesheets/main.less'))
- .pipe(plumber())
- .pipe(less())
- .pipe(gulp.dest(appDir.path('stylesheets')));
-});
+gulp.task('less', () => gulp.src(srcDir.path('stylesheets/main.less'))
+ .pipe(plumber())
+ .pipe(less())
+ .pipe(gulp.dest(appDir.path('stylesheets'))));
-gulp.task('environment', () => {
- return gulp.src(configDir.path(`env_${ utils.getEnvName() }.json`))
- .pipe(plumber())
- .pipe(rename('env.json'))
- .pipe(gulp.dest(appDir.path('.')));
-});
+gulp.task('environment', () => gulp.src(configDir.path(`env_${ utils.getEnvName() }.json`))
+ .pipe(plumber())
+ .pipe(rename('env.json'))
+ .pipe(gulp.dest(appDir.path('.'))));
-gulp.task('build-app', [ 'public', 'i18n', 'bundle', 'less', 'environment' ]);
+gulp.task('build-app', ['public', 'i18n', 'bundle', 'less', 'environment']);
gulp.task('watch', () => {
- const runOnChanges = taskName => batch((event, done) => {
- gulp.start(taskName, err => {
- if (err) {
- beepSound();
- }
- done(err);
- });
- });
-
- watch(srcDir.path('public/**/*'), runOnChanges('public'));
- watch(srcDir.path('i18n/lang/**/*'), runOnChanges('i18n'));
- watch(srcDir.path('**/*.js'), runOnChanges('bundle'));
- watch(srcDir.path('**/*.less'), runOnChanges('less'));
- watch(configDir.path('**/*'), runOnChanges('environment'));
+ const runOnChanges = (taskName) => batch((event, done) => {
+ gulp.start(taskName, (err) => {
+ if (err) {
+ beepSound();
+ }
+ done(err);
+ });
+ });
+
+ watch(srcDir.path('public/**/*'), runOnChanges('public'));
+ watch(srcDir.path('i18n/lang/**/*'), runOnChanges('i18n'));
+ watch(srcDir.path('**/*.js'), runOnChanges('bundle'));
+ watch(srcDir.path('**/*.less'), runOnChanges('less'));
+ watch(configDir.path('**/*'), runOnChanges('environment'));
});
diff --git a/tasks/build-tests.js b/tasks/build-tests.js
index ddde2d1c01..1853b2166f 100644
--- a/tasks/build-tests.js
+++ b/tasks/build-tests.js
@@ -5,30 +5,32 @@ const jetpack = require('fs-jetpack');
const bundle = require('./bundle');
const istanbul = require('rollup-plugin-istanbul');
-const createEntryFile = (srcDir, matching, outputDir, entryFileName, rollupOptions) => {
- return srcDir.findAsync('.', { matching })
- .then(specPaths => specPaths.map(path => `import './${ path.replace(/\\/g, '/') }';`))
- .then(imports => (
- "// This file is generated automatically.\n" +
- "// All modifications will be lost.\n" +
- imports.join('\n')
- ))
- .then(entryFileContent => srcDir.writeAsync(entryFileName, entryFileContent))
- .then(() => bundle(srcDir.path(entryFileName), outputDir.path(entryFileName), rollupOptions))
- .then(() => srcDir.remove(entryFileName));
+const createEntryFile = async(srcDir, matching, outputDir, entryFileName, rollupOptions) => {
+ const entryFileContent = srcDir.find('.', { matching })
+ .map((path) => `import './${ path.replace(/\\/g, '/') }';`)
+ .join('\n');
+
+ srcDir.write(entryFileName, entryFileContent);
+
+ await bundle(srcDir.path(entryFileName), outputDir.path(entryFileName), rollupOptions);
+
+ srcDir.remove(entryFileName);
};
-gulp.task('build-unit-tests', [ 'environment' ], () => {
- return createEntryFile(jetpack.cwd('src'), '*.spec.js', jetpack.cwd('app'), 'specs.js.autogenerated', {
- rollupPlugins: [
- istanbul({
- exclude: ['**/*.spec.js', '**/specs.js.autogenerated'],
- sourcemap: true
- })
- ]
- });
-});
+gulp.task('build-unit-tests', ['environment'], () => createEntryFile(
+ jetpack.cwd('src'), '*.spec.js',
+ jetpack.cwd('app'), 'specs.js.autogenerated',
+ {
+ rollupPlugins: [
+ istanbul({
+ exclude: ['**/*.spec.js', '**/specs.js.autogenerated'],
+ sourcemap: true,
+ }),
+ ],
+ }
+));
-gulp.task('build-e2e-tests', [ 'build-app' ], () => {
- return createEntryFile(jetpack.cwd('e2e'), '*.e2e.js', jetpack.cwd('app'), 'e2e.js.autogenerated');
-});
+gulp.task('build-e2e-tests', ['build-app'], () => createEntryFile(
+ jetpack.cwd('src'), '*.e2e.js',
+ jetpack.cwd('app'), 'e2e.js.autogenerated'
+));
diff --git a/tasks/bundle.js b/tasks/bundle.js
index 7c9db29bcc..6b5d666a4b 100644
--- a/tasks/bundle.js
+++ b/tasks/bundle.js
@@ -1,60 +1,46 @@
'use strict';
const path = require('path');
-const jetpack = require('fs-jetpack');
-const rollup = require('rollup').rollup;
+const { rollup } = require('rollup');
const rollupJson = require('rollup-plugin-json');
+const appManifest = require('../package.json');
-const nodeBuiltInModules = ['assert', 'buffer', 'child_process', 'cluster',
- 'console', 'constants', 'crypto', 'dgram', 'dns', 'domain', 'events',
- 'fs', 'http', 'https', 'module', 'net', 'os', 'path', 'process', 'punycode',
- 'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'timers',
- 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'zlib'];
+const nodeBuiltInModules = ['assert', 'buffer', 'child_process', 'cluster', 'console', 'constants', 'crypto', 'dgram',
+ 'dns', 'domain', 'events', 'fs', 'http', 'https', 'module', 'net', 'os', 'path', 'process', 'punycode', 'querystring',
+ 'readline', 'repl', 'stream', 'string_decoder', 'timers', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'zlib'];
const electronBuiltInModules = ['electron'];
-const generateExternalModulesList = function () {
- const appManifest = jetpack.read('./package.json', 'json');
- return [].concat(
- nodeBuiltInModules,
- electronBuiltInModules,
- Object.keys(appManifest.dependencies),
- Object.keys(appManifest.devDependencies)
- );
-};
+const externalModulesList = [
+ ...nodeBuiltInModules,
+ ...electronBuiltInModules,
+ ...Object.keys(appManifest.dependencies),
+ ...Object.keys(appManifest.devDependencies),
+];
const cached = {};
-module.exports = function (src, dest, opts) {
- opts = opts || {};
- opts.rollupPlugins = opts.rollupPlugins || [];
- return rollup({
- input: src,
- external: generateExternalModulesList(),
- cache: cached[src],
- plugins: [].concat(
- opts.rollupPlugins,
- rollupJson()
- ),
- })
- .then(function (bundle) {
- cached[src] = bundle;
-
- const jsFile = path.basename(dest);
- return bundle.generate({
- format: 'cjs',
- sourcemap: true,
- sourcemapFile: jsFile,
- });
- })
- .then(function (result) {
- // Wrap code in self invoking function so the variables don't
- // pollute the global namespace.
- const isolatedCode = '(function () {' + result.code + '\n}());';
- const jsFile = path.basename(dest);
- return Promise.all([
- jetpack.writeAsync(dest, isolatedCode + '\n//# sourcemappingURL=' + jsFile + '.map'),
- jetpack.writeAsync(dest + '.map', result.map.toString()),
- ]);
- });
+module.exports = async(src, dest, opts = {}) => {
+ const inputOptions = {
+ input: src,
+ external: externalModulesList,
+ cache: cached[src],
+ plugins: [
+ ...(opts.rollupPlugins || []),
+ rollupJson(),
+ ],
+ };
+
+ const outputOptions = {
+ format: 'cjs',
+ file: dest,
+ intro: '(function () {',
+ outro: '})()',
+ sourcemap: true,
+ sourcemapFile: path.basename(dest),
+ };
+
+ const bundle = await rollup(inputOptions);
+ cached[src] = bundle;
+ await bundle.write(outputOptions);
};
diff --git a/tasks/release.js b/tasks/release.js
index c95d312e26..24daef28e8 100644
--- a/tasks/release.js
+++ b/tasks/release.js
@@ -8,16 +8,11 @@ const { getEnvName } = require('./utils');
const publish = getEnvName() !== 'production' ? 'never' : 'onTagOrDraft';
gulp.task('release:darwin', () => build({ publish, x64: true, mac: [] }));
-gulp.task('release:win32', () => build({ publish, x64: true, ia32: true, win: [ 'nsis', 'appx' ] }));
-gulp.task('release:linux', (cb) => {
- build({ publish, x64: true, linux: [], c: { productName: 'rocketchat' } })
- .then(() => build({
- publish,
- ia32: true,
- linux: config.linux.target.filter(target => target !== 'snap'),
- c: { productName: 'rocketchat' }
- }))
- .then(() => cb(), (error) => cb(error));
+gulp.task('release:win32', () => build({ publish, x64: true, ia32: true, win: ['nsis', 'appx'] }));
+gulp.task('release:linux', async() => {
+ const allLinuxTargetsButSnap = config.linux.target.filter((target) => target !== 'snap');
+ await build({ publish, x64: true, linux: [], c: { productName: 'rocketchat' } });
+ await build({ publish, ia32: true, linux: allLinuxTargetsButSnap, c: { productName: 'rocketchat' } });
});
gulp.task('release', (cb) => runSequence('build-app', `release:${ process.platform }`, cb));
diff --git a/tasks/start.js b/tasks/start.js
index 6542c062af..89a64c0b88 100644
--- a/tasks/start.js
+++ b/tasks/start.js
@@ -4,7 +4,7 @@ const gulp = require('gulp');
const childProcess = require('child_process');
const electron = require('electron');
-gulp.task('start', [ 'build-app', 'watch' ], () => {
- childProcess.spawn(electron, [ '.' ], { stdio: 'inherit' })
- .on('close', () => process.exit());
+gulp.task('start', ['build-app', 'watch'], () => {
+ childProcess.spawn(electron, ['.'], { stdio: 'inherit' })
+ .on('close', () => process.exit());
});
diff --git a/yarn.lock b/yarn.lock
index 325d2d7b23..916409455f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -27,6 +27,12 @@
bindings "~1.2.1"
nan "^2.0.0"
+"@rocket.chat/eslint-config@^0.1.2":
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/@rocket.chat/eslint-config/-/eslint-config-0.1.2.tgz#f9c5041b8a0e849de9eb4013e4e3efcbe9951d0a"
+ dependencies:
+ eslint-plugin-import "^2.14.0"
+
"@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
@@ -1115,6 +1121,10 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+contains-path@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
+
conventional-changelog-angular@^1.6.6:
version "1.6.6"
resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-1.6.6.tgz#b27f2b315c16d0a1f23eb181309d0e6a4698ea0f"
@@ -1372,7 +1382,7 @@ dateformat@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
-debug@2.6.9, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
+debug@2.6.9, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
@@ -1532,6 +1542,13 @@ dmg-builder@5.3.1:
parse-color "^1.0.0"
sanitize-filename "^1.6.1"
+doctrine@1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
+ dependencies:
+ esutils "^2.0.2"
+ isarray "^1.0.0"
+
doctrine@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@@ -1781,6 +1798,35 @@ escodegen@1.8.x:
optionalDependencies:
source-map "~0.2.0"
+eslint-import-resolver-node@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a"
+ dependencies:
+ debug "^2.6.9"
+ resolve "^1.5.0"
+
+eslint-module-utils@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz#b270362cd88b1a48ad308976ce7fa54e98411746"
+ dependencies:
+ debug "^2.6.8"
+ pkg-dir "^1.0.0"
+
+eslint-plugin-import@^2.14.0:
+ version "2.14.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz#6b17626d2e3e6ad52cfce8807a845d15e22111a8"
+ dependencies:
+ contains-path "^0.1.0"
+ debug "^2.6.8"
+ doctrine "1.5.0"
+ eslint-import-resolver-node "^0.3.1"
+ eslint-module-utils "^2.2.0"
+ has "^1.0.1"
+ lodash "^4.17.4"
+ minimatch "^3.0.3"
+ read-pkg-up "^2.0.0"
+ resolve "^1.6.0"
+
eslint-scope@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172"
@@ -2295,6 +2341,10 @@ fstream@^1.0.0, fstream@^1.0.2:
mkdirp ">=0.5 0"
rimraf "2"
+function-bind@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+
functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
@@ -2774,6 +2824,12 @@ has-values@^1.0.0:
is-number "^3.0.0"
kind-of "^4.0.0"
+has@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ dependencies:
+ function-bind "^1.1.1"
+
he@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
@@ -3241,7 +3297,7 @@ isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
-isarray@1.0.0, isarray@~1.0.0:
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -3532,6 +3588,15 @@ load-json-file@^1.0.0:
pinkie-promise "^2.0.0"
strip-bom "^2.0.0"
+load-json-file@^2.0.0:
+ version "2.0.0"
+ resolved "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^2.2.0"
+ pify "^2.0.0"
+ strip-bom "^3.0.0"
+
load-json-file@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
@@ -3940,7 +4005,7 @@ mimic-fn@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
-"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2:
+"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
@@ -4789,6 +4854,12 @@ path-type@^1.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
+path-type@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
+ dependencies:
+ pify "^2.0.0"
+
path-type@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@@ -4825,6 +4896,12 @@ pinkie@^2.0.0:
version "2.0.4"
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+pkg-dir@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4"
+ dependencies:
+ find-up "^1.0.0"
+
plist@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
@@ -5098,6 +5175,13 @@ read-pkg-up@^1.0.1:
find-up "^1.0.0"
read-pkg "^1.0.0"
+read-pkg-up@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
+ dependencies:
+ find-up "^2.0.0"
+ read-pkg "^2.0.0"
+
read-pkg-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
@@ -5113,6 +5197,14 @@ read-pkg@^1.0.0, read-pkg@^1.1.0:
normalize-package-data "^2.3.2"
path-type "^1.0.0"
+read-pkg@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
+ dependencies:
+ load-json-file "^2.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^2.0.0"
+
read-pkg@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
@@ -5329,7 +5421,7 @@ resolve@1.1.x:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
-resolve@^1.1.6, resolve@^1.1.7, resolve@^1.5.0:
+resolve@^1.1.6, resolve@^1.1.7, resolve@^1.5.0, resolve@^1.6.0:
version "1.8.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26"
dependencies: