js: Explode more singleton classes to modules.

Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
This commit is contained in:
Anders Kaseorg
2020-03-04 16:26:36 -08:00
parent 20c6f487c4
commit b3261bcdff
7 changed files with 659 additions and 678 deletions

View File

@@ -17,15 +17,14 @@ const logger = new Logger({
timestamp: true
});
class AppMenu {
getHistorySubmenu(enableMenu: boolean): Electron.MenuItemConstructorOptions[] {
function getHistorySubmenu(enableMenu: boolean): Electron.MenuItemConstructorOptions[] {
return [{
label: t.__('Back'),
accelerator: process.platform === 'darwin' ? 'Command+Left' : 'Alt+Left',
enabled: enableMenu,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('back');
sendAction('back');
}
}
}, {
@@ -34,17 +33,17 @@ class AppMenu {
enabled: enableMenu,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('forward');
sendAction('forward');
}
}
}];
}
}
getToolsSubmenu(): Electron.MenuItemConstructorOptions[] {
function getToolsSubmenu(): Electron.MenuItemConstructorOptions[] {
return [{
label: t.__('Check for Updates'),
click() {
AppMenu.checkForUpdate();
checkForUpdate();
}
},
{
@@ -60,7 +59,7 @@ class AppMenu {
label: t.__('Factory Reset'),
accelerator: process.platform === 'darwin' ? 'Command+Shift+D' : 'Ctrl+Shift+D',
click() {
AppMenu.resetAppSettings();
resetAppSettings();
}
},
{
@@ -99,19 +98,19 @@ class AppMenu {
accelerator: process.platform === 'darwin' ? 'Alt+Command+U' : 'Ctrl+Shift+U',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('tab-devtools');
sendAction('tab-devtools');
}
}
}];
}
}
getViewSubmenu(): Electron.MenuItemConstructorOptions[] {
function getViewSubmenu(): Electron.MenuItemConstructorOptions[] {
return [{
label: t.__('Reload'),
accelerator: 'CommandOrControl+R',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('reload-current-viewer');
sendAction('reload-current-viewer');
}
}
}, {
@@ -119,7 +118,7 @@ class AppMenu {
accelerator: 'CommandOrControl+Shift+R',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('hard-reload');
sendAction('hard-reload');
}
}
}, {
@@ -132,7 +131,7 @@ class AppMenu {
role: 'zoomIn',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('zoomIn');
sendAction('zoomIn');
}
}
}, {
@@ -141,7 +140,7 @@ class AppMenu {
accelerator: 'CommandOrControl+-',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('zoomOut');
sendAction('zoomOut');
}
}
}, {
@@ -150,7 +149,7 @@ class AppMenu {
accelerator: 'CommandOrControl+0',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('zoomActualSize');
sendAction('zoomActualSize');
}
}
}, {
@@ -187,9 +186,9 @@ class AppMenu {
},
type: 'checkbox'
}];
}
}
getHelpSubmenu(): Electron.MenuItemConstructorOptions[] {
function getHelpSubmenu(): Electron.MenuItemConstructorOptions[] {
return [
{
label: `${appName + ' Desktop'} v${app.getVersion()}`,
@@ -199,7 +198,7 @@ class AppMenu {
label: t.__('About Zulip'),
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('open-about');
sendAction('open-about');
}
}
},
@@ -207,7 +206,7 @@ class AppMenu {
label: t.__('Help Center'),
click(focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('open-help');
sendAction('open-help');
}
}
},
@@ -222,9 +221,9 @@ class AppMenu {
}
}
];
}
}
getWindowSubmenu(tabs: any[], activeTabIndex: number, enableMenu: boolean): Electron.MenuItemConstructorOptions[] {
function getWindowSubmenu(tabs: any[], activeTabIndex: number, enableMenu: boolean): Electron.MenuItemConstructorOptions[] {
const initialSubmenu: Electron.MenuItemConstructorOptions[] = [{
label: t.__('Minimize'),
role: 'minimize'
@@ -250,7 +249,7 @@ class AppMenu {
checked: tab.props.index === activeTabIndex,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('switch-server-tab', tab.props.index);
sendAction('switch-server-tab', tab.props.index);
}
},
type: 'checkbox'
@@ -265,7 +264,7 @@ class AppMenu {
enabled: tabs.length > 1,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('switch-server-tab', AppMenu.getNextServer(tabs, activeTabIndex));
sendAction('switch-server-tab', getNextServer(tabs, activeTabIndex));
}
}
}, {
@@ -274,16 +273,16 @@ class AppMenu {
enabled: tabs.length > 1,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('switch-server-tab', AppMenu.getPreviousServer(tabs, activeTabIndex));
sendAction('switch-server-tab', getPreviousServer(tabs, activeTabIndex));
}
}
});
}
return initialSubmenu;
}
}
getDarwinTpl(props: any): Electron.MenuItemConstructorOptions[] {
function getDarwinTpl(props: any): Electron.MenuItemConstructorOptions[] {
const { tabs, activeTabIndex, enableMenu } = props;
return [{
@@ -293,7 +292,7 @@ class AppMenu {
accelerator: 'Cmd+Shift+N',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('new-server');
sendAction('new-server');
}
}
}, {
@@ -301,14 +300,14 @@ class AppMenu {
accelerator: 'Cmd+Shift+M',
click() {
const dndUtil = DNDUtil.toggle();
AppMenu.sendAction('toggle-dnd', dndUtil.dnd, dndUtil.newSettings);
sendAction('toggle-dnd', dndUtil.dnd, dndUtil.newSettings);
}
}, {
label: t.__('Desktop Settings'),
accelerator: 'Cmd+,',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('open-settings');
sendAction('open-settings');
}
}
}, {
@@ -317,7 +316,7 @@ class AppMenu {
enabled: enableMenu,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('shortcut');
sendAction('shortcut');
}
}
}, {
@@ -328,7 +327,7 @@ class AppMenu {
enabled: enableMenu,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('copy-zulip-url');
sendAction('copy-zulip-url');
}
}
}, {
@@ -337,7 +336,7 @@ class AppMenu {
enabled: enableMenu,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('log-out');
sendAction('log-out');
}
}
}, {
@@ -397,24 +396,24 @@ class AppMenu {
}]
}, {
label: t.__('View'),
submenu: this.getViewSubmenu()
submenu: getViewSubmenu()
}, {
label: t.__('History'),
submenu: this.getHistorySubmenu(enableMenu)
submenu: getHistorySubmenu(enableMenu)
}, {
label: t.__('Window'),
submenu: this.getWindowSubmenu(tabs, activeTabIndex, enableMenu)
submenu: getWindowSubmenu(tabs, activeTabIndex, enableMenu)
}, {
label: t.__('Tools'),
submenu: this.getToolsSubmenu()
submenu: getToolsSubmenu()
}, {
label: t.__('Help'),
role: 'help',
submenu: this.getHelpSubmenu()
submenu: getHelpSubmenu()
}];
}
}
getOtherTpl(props: any): Electron.MenuItemConstructorOptions[] {
function getOtherTpl(props: any): Electron.MenuItemConstructorOptions[] {
const { tabs, activeTabIndex, enableMenu } = props;
return [{
label: t.__('File'),
@@ -423,7 +422,7 @@ class AppMenu {
accelerator: 'Ctrl+Shift+N',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('new-server');
sendAction('new-server');
}
}
}, {
@@ -433,14 +432,14 @@ class AppMenu {
accelerator: 'Ctrl+Shift+M',
click() {
const dndUtil = DNDUtil.toggle();
AppMenu.sendAction('toggle-dnd', dndUtil.dnd, dndUtil.newSettings);
sendAction('toggle-dnd', dndUtil.dnd, dndUtil.newSettings);
}
}, {
label: t.__('Desktop Settings'),
accelerator: 'Ctrl+,',
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('open-settings');
sendAction('open-settings');
}
}
}, {
@@ -449,7 +448,7 @@ class AppMenu {
enabled: enableMenu,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('shortcut');
sendAction('shortcut');
}
}
}, {
@@ -460,7 +459,7 @@ class AppMenu {
enabled: enableMenu,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('copy-zulip-url');
sendAction('copy-zulip-url');
}
}
}, {
@@ -469,7 +468,7 @@ class AppMenu {
enabled: enableMenu,
click(_item: any, focusedWindow: any) {
if (focusedWindow) {
AppMenu.sendAction('log-out');
sendAction('log-out');
}
}
}, {
@@ -515,24 +514,24 @@ class AppMenu {
}]
}, {
label: t.__('View'),
submenu: this.getViewSubmenu()
submenu: getViewSubmenu()
}, {
label: t.__('History'),
submenu: this.getHistorySubmenu(enableMenu)
submenu: getHistorySubmenu(enableMenu)
}, {
label: t.__('Window'),
submenu: this.getWindowSubmenu(tabs, activeTabIndex, enableMenu)
submenu: getWindowSubmenu(tabs, activeTabIndex, enableMenu)
}, {
label: t.__('Tools'),
submenu: this.getToolsSubmenu()
submenu: getToolsSubmenu()
}, {
label: t.__('Help'),
role: 'help',
submenu: this.getHelpSubmenu()
submenu: getHelpSubmenu()
}];
}
}
static sendAction(action: string, ...params: any[]): void {
function sendAction(action: string, ...params: any[]): void {
const win = BrowserWindow.getAllWindows()[0];
if (process.platform === 'darwin') {
@@ -540,29 +539,29 @@ class AppMenu {
}
win.webContents.send(action, ...params);
}
}
static checkForUpdate(): void {
function checkForUpdate(): void {
appUpdater(true);
}
}
static getNextServer(tabs: any[], activeTabIndex: number): number {
function getNextServer(tabs: any[], activeTabIndex: number): number {
do {
activeTabIndex = (activeTabIndex + 1) % tabs.length;
}
while (tabs[activeTabIndex].props.role !== 'server');
return activeTabIndex;
}
}
static getPreviousServer(tabs: any[], activeTabIndex: number): number {
function getPreviousServer(tabs: any[], activeTabIndex: number): number {
do {
activeTabIndex = (activeTabIndex - 1 + tabs.length) % tabs.length;
}
while (tabs[activeTabIndex].props.role !== 'server');
return activeTabIndex;
}
}
static async resetAppSettings(): Promise<void> {
async function resetAppSettings(): Promise<void> {
const resetAppSettingsMessage = 'By proceeding you will be removing all connected organizations and preferences from Zulip.';
// We save App's settings/configurations in following files
@@ -584,19 +583,16 @@ class AppMenu {
logger.error(error);
} else {
fs.unlink(getSettingFilesPath, () => {
AppMenu.sendAction('clear-app-data');
sendAction('clear-app-data');
});
}
});
});
}
}
setMenu(props: any): void {
const tpl = process.platform === 'darwin' ? this.getDarwinTpl(props) : this.getOtherTpl(props);
const menu = Menu.buildFromTemplate(tpl);
Menu.setApplicationMenu(menu);
}
}
export = new AppMenu();
export function setMenu(props: any): void {
const tpl = process.platform === 'darwin' ? getDarwinTpl(props) : getOtherTpl(props);
const menu = Menu.buildFromTemplate(tpl);
Menu.setApplicationMenu(menu);
}

View File

@@ -1050,4 +1050,4 @@ window.addEventListener('load', () => {
}
});
export = new ServerManagerView();
export {};

View File

@@ -2,15 +2,11 @@
import { ipcRenderer } from 'electron';
class NetworkTroubleshootingView {
init($reconnectButton: Element, $settingsButton: Element): void {
export function init($reconnectButton: Element, $settingsButton: Element): void {
$reconnectButton.addEventListener('click', () => {
ipcRenderer.send('forward-message', 'reload-viewer');
});
$settingsButton.addEventListener('click', () => {
ipcRenderer.send('forward-message', 'open-settings');
});
}
}
export = new NetworkTroubleshootingView();

View File

@@ -1,7 +1,7 @@
'use strict';
import { ipcRenderer, shell } from 'electron';
import SetupSpellChecker from './spellchecker';
import * as SetupSpellChecker from './spellchecker';
import isDev = require('electron-is-dev');
import LinkUtil = require('./utils/link-util');

View File

@@ -18,47 +18,44 @@ const logger = new Logger({
timestamp: true
});
class SetupSpellChecker {
SpellCheckHandler: SpellCheckHandler;
contextMenuListener: ContextMenuListener;
init(serverLanguage: string): void {
if (ConfigUtil.getConfigItem('enableSpellchecker')) {
this.enableSpellChecker();
}
this.enableContextMenu(serverLanguage);
}
let spellCheckHandler: SpellCheckHandler;
let contextMenuListener: ContextMenuListener;
enableSpellChecker(): void {
export function init(serverLanguage: string): void {
if (ConfigUtil.getConfigItem('enableSpellchecker')) {
enableSpellChecker();
}
enableContextMenu(serverLanguage);
}
function enableSpellChecker(): void {
try {
this.SpellCheckHandler = new SpellCheckHandler();
spellCheckHandler = new SpellCheckHandler();
} catch (err) {
logger.error(err);
}
}
enableContextMenu(serverLanguage: string): void {
if (this.SpellCheckHandler) {
this.SpellCheckHandler.attachToInput();
this.SpellCheckHandler.switchLanguage(serverLanguage);
this.SpellCheckHandler.currentSpellcheckerChanged.subscribe(() => {
this.SpellCheckHandler.switchLanguage(this.SpellCheckHandler.currentSpellcheckerLanguage);
});
}
const contextMenuBuilder = new ContextMenuBuilder(this.SpellCheckHandler);
this.contextMenuListener = new ContextMenuListener(info => {
contextMenuBuilder.showPopupMenu(info);
});
}
unsubscribeSpellChecker(): void {
if (this.SpellCheckHandler) {
this.SpellCheckHandler.unsubscribe();
}
if (this.contextMenuListener) {
this.contextMenuListener.unsubscribe();
}
}
}
export = new SetupSpellChecker();
function enableContextMenu(serverLanguage: string): void {
if (spellCheckHandler) {
spellCheckHandler.attachToInput();
spellCheckHandler.switchLanguage(serverLanguage);
spellCheckHandler.currentSpellcheckerChanged.subscribe(() => {
spellCheckHandler.switchLanguage(spellCheckHandler.currentSpellcheckerLanguage);
});
}
const contextMenuBuilder = new ContextMenuBuilder(spellCheckHandler);
contextMenuListener = new ContextMenuListener(info => {
contextMenuBuilder.showPopupMenu(info);
});
}
export function unsubscribeSpellChecker(): void {
if (spellCheckHandler) {
spellCheckHandler.unsubscribe();
}
if (contextMenuListener) {
contextMenuListener.unsubscribe();
}
}

View File

@@ -5,14 +5,13 @@ import ConfigUtil = require('./config-util');
const { shell } = remote;
class AuthUtil {
openInBrowser = (link: string): void => {
export const openInBrowser = (link: string): void => {
const otp = cryptoRandomString({length: 64});
ConfigUtil.setConfigItem('desktopOtp', otp);
shell.openExternal(`${link}?desktop_flow_otp=${otp}`);
};
};
xorStrings = (a: string, b: string): string => {
export const xorStrings = (a: string, b: string): string => {
if (a.length === b.length) {
return a
.split('')
@@ -22,15 +21,12 @@ class AuthUtil {
} else {
return '';
}
};
};
hexToAscii = (hex: string): string => {
export const hexToAscii = (hex: string): string => {
let ascii = '';
for (let i = 0; i < hex.length; i += 2) {
ascii += String.fromCharCode(parseInt(hex.slice(i, i + 2), 16));
}
return ascii;
};
}
export = new AuthUtil();
};

View File

@@ -3,8 +3,7 @@ interface DialogBoxError {
content: string;
}
class Messages {
invalidZulipServerError(domain: string): string {
export function invalidZulipServerError(domain: string): string {
return `${domain} does not appear to be a valid Zulip server. Make sure that
\n • You can connect to that URL in a web browser.\
\n • If you need a proxy to connect to the Internet, that you've configured your proxy in the Network settings.\
@@ -12,25 +11,25 @@ class Messages {
\n • The server has a valid certificate. (You can add custom certificates in Settings > Organizations). \
\n • The SSL is correctly configured for the certificate. Check out the SSL troubleshooting guide -
\n https://zulip.readthedocs.io/en/stable/production/ssl-certificates.html`;
}
}
noOrgsError(domain: string): string {
export function noOrgsError(domain: string): string {
return `${domain} does not have any organizations added.\
\nPlease contact your server administrator.`;
}
}
certErrorMessage(domain: string, error: string): string {
export function certErrorMessage(domain: string, error: string): string {
return `Do you trust certificate from ${domain}? \n ${error}`;
}
}
certErrorDetail(): string {
export function certErrorDetail(): string {
return `The organization you're connecting to is either someone impersonating the Zulip server you entered, or the server you're trying to connect to is configured in an insecure way.
\nIf you have a valid certificate please add it from Settings>Organizations and try to add the organization again.
\nUnless you have a good reason to believe otherwise, you should not proceed.
\nYou can click here if you'd like to proceed with the connection.`;
}
}
enterpriseOrgError(length: number, domains: string[]): DialogBoxError {
export function enterpriseOrgError(length: number, domains: string[]): DialogBoxError {
let domainList = '';
for (const domain of domains) {
domainList += `${domain}\n`;
@@ -39,14 +38,11 @@ class Messages {
title: `Could not add the following ${length === 1 ? 'organization' : 'organizations'}`,
content: `${domainList}\nPlease contact your system administrator.`
};
}
}
orgRemovalError(url: string): DialogBoxError {
export function orgRemovalError(url: string): DialogBoxError {
return {
title: `Removing ${url} is a restricted operation.`,
content: 'Please contact your system administrator.'
};
}
}
export = new Messages();