typescript: Enable strictNullChecks.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2021-04-02 15:19:42 -07:00
parent 33c21d0153
commit 9a81ade1c8
13 changed files with 129 additions and 117 deletions

View File

@@ -292,7 +292,7 @@ function getHelpSubmenu(): Electron.MenuItemConstructorOptions[] {
function getWindowSubmenu( function getWindowSubmenu(
tabs: TabData[], tabs: TabData[],
activeTabIndex: number, activeTabIndex?: number,
): Electron.MenuItemConstructorOptions[] { ): Electron.MenuItemConstructorOptions[] {
const initialSubmenu: Electron.MenuItemConstructorOptions[] = [ const initialSubmenu: Electron.MenuItemConstructorOptions[] = [
{ {
@@ -342,7 +342,7 @@ function getWindowSubmenu(
if (focusedWindow) { if (focusedWindow) {
sendAction( sendAction(
"switch-server-tab", "switch-server-tab",
getNextServer(tabs, activeTabIndex), getNextServer(tabs, activeTabIndex!),
); );
} }
}, },
@@ -355,7 +355,7 @@ function getWindowSubmenu(
if (focusedWindow) { if (focusedWindow) {
sendAction( sendAction(
"switch-server-tab", "switch-server-tab",
getPreviousServer(tabs, activeTabIndex), getPreviousServer(tabs, activeTabIndex!),
); );
} }
}, },
@@ -367,7 +367,7 @@ function getWindowSubmenu(
} }
function getDarwinTpl(props: MenuProps): Electron.MenuItemConstructorOptions[] { function getDarwinTpl(props: MenuProps): Electron.MenuItemConstructorOptions[] {
const {tabs, activeTabIndex, enableMenu} = props; const {tabs, activeTabIndex, enableMenu = false} = props;
return [ return [
{ {
@@ -533,7 +533,7 @@ function getDarwinTpl(props: MenuProps): Electron.MenuItemConstructorOptions[] {
} }
function getOtherTpl(props: MenuProps): Electron.MenuItemConstructorOptions[] { function getOtherTpl(props: MenuProps): Electron.MenuItemConstructorOptions[] {
const {tabs, activeTabIndex, enableMenu} = props; const {tabs, activeTabIndex, enableMenu = false} = props;
return [ return [
{ {
label: t.__("File"), label: t.__("File"),

View File

@@ -6,7 +6,8 @@ import type {TabProps} from "./tab";
import Tab from "./tab"; import Tab from "./tab";
export default class FunctionalTab extends Tab { export default class FunctionalTab extends Tab {
$closeButton: Element; $el: Element;
$closeButton?: Element;
constructor(props: TabProps) { constructor(props: TabProps) {
super(props); super(props);
@@ -14,7 +15,7 @@ export default class FunctionalTab extends Tab {
this.$el = generateNodeFromHTML(this.templateHTML()); this.$el = generateNodeFromHTML(this.templateHTML());
if (this.props.name !== "Settings") { if (this.props.name !== "Settings") {
this.props.$root.append(this.$el); this.props.$root.append(this.$el);
this.$closeButton = this.$el.querySelector(".server-tab-badge"); this.$closeButton = this.$el.querySelector(".server-tab-badge")!;
this.registerListeners(); this.registerListeners();
} }
} }
@@ -36,15 +37,15 @@ export default class FunctionalTab extends Tab {
super.registerListeners(); super.registerListeners();
this.$el.addEventListener("mouseover", () => { this.$el.addEventListener("mouseover", () => {
this.$closeButton.classList.add("active"); this.$closeButton?.classList.add("active");
}); });
this.$el.addEventListener("mouseout", () => { this.$el.addEventListener("mouseout", () => {
this.$closeButton.classList.remove("active"); this.$closeButton?.classList.remove("active");
}); });
this.$closeButton.addEventListener("click", (event: Event) => { this.$closeButton?.addEventListener("click", (event: Event) => {
this.props.onDestroy(); this.props.onDestroy?.();
event.stopPropagation(); event.stopPropagation();
}); });
} }

View File

@@ -59,7 +59,7 @@ export default function handleExternalLink(
body: "Download failed", body: "Download failed",
}); });
} else { } else {
this.$el.downloadURL(url.href); this.$el!.downloadURL(url.href);
} }
} }

View File

@@ -9,6 +9,7 @@ import type {TabProps} from "./tab";
import Tab from "./tab"; import Tab from "./tab";
export default class ServerTab extends Tab { export default class ServerTab extends Tab {
$el: Element;
$badge: Element; $badge: Element;
constructor(props: TabProps) { constructor(props: TabProps) {
@@ -17,7 +18,7 @@ export default class ServerTab extends Tab {
this.$el = generateNodeFromHTML(this.templateHTML()); this.$el = generateNodeFromHTML(this.templateHTML());
this.props.$root.append(this.$el); this.props.$root.append(this.$el);
this.registerListeners(); this.registerListeners();
this.$badge = this.$el.querySelector(".server-tab-badge"); this.$badge = this.$el.querySelector(".server-tab-badge")!;
} }
templateHTML(): HTML { templateHTML(): HTML {

View File

@@ -15,10 +15,11 @@ export interface TabProps {
onDestroy?: () => void; onDestroy?: () => void;
} }
export default class Tab { export default abstract class Tab {
props: TabProps; props: TabProps;
webview: WebView; webview: WebView;
$el: Element; abstract $el: Element;
constructor(props: TabProps) { constructor(props: TabProps) {
this.props = props; this.props = props;
this.webview = this.props.webview; this.webview = this.props.webview;
@@ -26,8 +27,14 @@ export default class Tab {
registerListeners(): void { registerListeners(): void {
this.$el.addEventListener("click", this.props.onClick); this.$el.addEventListener("click", this.props.onClick);
this.$el.addEventListener("mouseover", this.props.onHover);
this.$el.addEventListener("mouseout", this.props.onHoverOut); if (this.props.onHover !== undefined) {
this.$el.addEventListener("mouseover", this.props.onHover);
}
if (this.props.onHoverOut !== undefined) {
this.$el.addEventListener("mouseout", this.props.onHoverOut);
}
} }
showNetworkError(): void { showNetworkError(): void {
@@ -46,6 +53,6 @@ export default class Tab {
destroy(): void { destroy(): void {
this.$el.remove(); this.$el.remove();
this.webview.$el.remove(); this.webview.$el!.remove();
} }
} }

View File

@@ -35,9 +35,9 @@ export default class WebView {
zoomFactor: number; zoomFactor: number;
badgeCount: number; badgeCount: number;
loading: boolean; loading: boolean;
customCSS: string; customCSS: string | null;
$webviewsContainer: DOMTokenList; $webviewsContainer: DOMTokenList;
$el: Electron.WebviewTag; $el?: Electron.WebviewTag;
domReady?: Promise<void>; domReady?: Promise<void>;
constructor(props: WebViewProps) { constructor(props: WebViewProps) {
@@ -48,7 +48,7 @@ export default class WebView {
this.customCSS = ConfigUtil.getConfigItem("customCSS"); this.customCSS = ConfigUtil.getConfigItem("customCSS");
this.$webviewsContainer = document.querySelector( this.$webviewsContainer = document.querySelector(
"#webviews-container", "#webviews-container",
).classList; )!.classList;
} }
templateHTML(): HTML { templateHTML(): HTML {
@@ -74,7 +74,7 @@ export default class WebView {
init(): void { init(): void {
this.$el = generateNodeFromHTML(this.templateHTML()) as Electron.WebviewTag; this.$el = generateNodeFromHTML(this.templateHTML()) as Electron.WebviewTag;
this.domReady = new Promise((resolve) => { this.domReady = new Promise((resolve) => {
this.$el.addEventListener( this.$el!.addEventListener(
"dom-ready", "dom-ready",
() => { () => {
resolve(); resolve();
@@ -88,23 +88,23 @@ export default class WebView {
} }
registerListeners(): void { registerListeners(): void {
this.$el.addEventListener("new-window", (event) => { this.$el!.addEventListener("new-window", (event) => {
handleExternalLink.call(this, event); handleExternalLink.call(this, event);
}); });
if (shouldSilentWebview) { if (shouldSilentWebview) {
this.$el.addEventListener("dom-ready", () => { this.$el!.addEventListener("dom-ready", () => {
this.$el.setAudioMuted(true); this.$el!.setAudioMuted(true);
}); });
} }
this.$el.addEventListener("page-title-updated", (event) => { this.$el!.addEventListener("page-title-updated", (event) => {
const {title} = event; const {title} = event;
this.badgeCount = this.getBadgeCount(title); this.badgeCount = this.getBadgeCount(title);
this.props.onTitleChange(); this.props.onTitleChange();
}); });
this.$el.addEventListener("did-navigate-in-page", (event) => { this.$el!.addEventListener("did-navigate-in-page", (event) => {
const isSettingPage = event.url.includes("renderer/preference.html"); const isSettingPage = event.url.includes("renderer/preference.html");
if (isSettingPage) { if (isSettingPage) {
return; return;
@@ -113,11 +113,11 @@ export default class WebView {
this.canGoBackButton(); this.canGoBackButton();
}); });
this.$el.addEventListener("did-navigate", () => { this.$el!.addEventListener("did-navigate", () => {
this.canGoBackButton(); this.canGoBackButton();
}); });
this.$el.addEventListener("page-favicon-updated", (event) => { this.$el!.addEventListener("page-favicon-updated", (event) => {
const {favicons} = event; const {favicons} = event;
// This returns a string of favicons URL. If there is a PM counts in unread messages then the URL would be like // This returns a string of favicons URL. If there is a PM counts in unread messages then the URL would be like
@@ -135,16 +135,16 @@ export default class WebView {
} }
}); });
this.$el.addEventListener("dom-ready", () => { this.$el!.addEventListener("dom-ready", () => {
const webContents = remote.webContents.fromId( const webContents = remote.webContents.fromId(
this.$el.getWebContentsId(), this.$el!.getWebContentsId(),
); );
webContents.addListener("context-menu", (event, menuParameters) => { webContents.addListener("context-menu", (event, menuParameters) => {
contextMenu(webContents, event, menuParameters); contextMenu(webContents, event, menuParameters);
}); });
if (this.props.role === "server") { if (this.props.role === "server") {
this.$el.classList.add("onload"); this.$el!.classList.add("onload");
} }
this.loading = false; this.loading = false;
@@ -153,11 +153,11 @@ export default class WebView {
// Refocus text boxes after reload // Refocus text boxes after reload
// Remove when upstream issue https://github.com/electron/electron/issues/14474 is fixed // Remove when upstream issue https://github.com/electron/electron/issues/14474 is fixed
this.$el.blur(); this.$el!.blur();
this.$el.focus(); this.$el!.focus();
}); });
this.$el.addEventListener("did-fail-load", (event) => { this.$el!.addEventListener("did-fail-load", (event) => {
const {errorDescription} = event; const {errorDescription} = event;
const hasConnectivityError = SystemUtil.connectivityERR.includes( const hasConnectivityError = SystemUtil.connectivityERR.includes(
errorDescription, errorDescription,
@@ -170,14 +170,14 @@ export default class WebView {
} }
}); });
this.$el.addEventListener("did-start-loading", () => { this.$el!.addEventListener("did-start-loading", () => {
const isSettingPage = this.props.url.includes("renderer/preference.html"); const isSettingPage = this.props.url.includes("renderer/preference.html");
if (!isSettingPage) { if (!isSettingPage) {
this.props.switchLoading(true, this.props.url); this.props.switchLoading(true, this.props.url);
} }
}); });
this.$el.addEventListener("did-stop-loading", () => { this.$el!.addEventListener("did-stop-loading", () => {
this.props.switchLoading(false, this.props.url); this.props.switchLoading(false, this.props.url);
}); });
} }
@@ -189,7 +189,7 @@ export default class WebView {
showNotificationSettings(): void { showNotificationSettings(): void {
ipcRenderer.sendTo( ipcRenderer.sendTo(
this.$el.getWebContentsId(), this.$el!.getWebContentsId(),
"show-notification-settings", "show-notification-settings",
); );
} }
@@ -207,18 +207,18 @@ export default class WebView {
this.$webviewsContainer.add("loaded"); this.$webviewsContainer.add("loaded");
} }
this.$el.classList.remove("disabled"); this.$el!.classList.remove("disabled");
this.$el.classList.add("active"); this.$el!.classList.add("active");
setTimeout(() => { setTimeout(() => {
if (this.props.role === "server") { if (this.props.role === "server") {
this.$el.classList.remove("onload"); this.$el!.classList.remove("onload");
} }
}, 1000); }, 1000);
this.focus(); this.focus();
this.props.onTitleChange(); this.props.onTitleChange();
// Injecting preload css in webview to override some css rules // Injecting preload css in webview to override some css rules
(async () => (async () =>
this.$el.insertCSS( this.$el!.insertCSS(
fs.readFileSync(path.join(__dirname, "/../../css/preload.css"), "utf8"), fs.readFileSync(path.join(__dirname, "/../../css/preload.css"), "utf8"),
))(); ))();
@@ -235,15 +235,15 @@ export default class WebView {
} }
(async () => (async () =>
this.$el.insertCSS( this.$el!.insertCSS(
fs.readFileSync(path.resolve(__dirname, this.customCSS), "utf8"), fs.readFileSync(path.resolve(__dirname, this.customCSS!), "utf8"),
))(); ))();
} }
} }
focus(): void { focus(): void {
// Focus Webview and it's contents when Window regain focus. // Focus Webview and it's contents when Window regain focus.
const webContents = remote.webContents.fromId(this.$el.getWebContentsId()); const webContents = remote.webContents.fromId(this.$el!.getWebContentsId());
// HACK: webContents.isFocused() seems to be true even without the element // HACK: webContents.isFocused() seems to be true even without the element
// being in focus. So, we check against `document.activeElement`. // being in focus. So, we check against `document.activeElement`.
if (webContents && this.$el !== document.activeElement) { if (webContents && this.$el !== document.activeElement) {
@@ -251,14 +251,14 @@ export default class WebView {
// element to transfer focus correctly, in Electron v3.0.10 // element to transfer focus correctly, in Electron v3.0.10
// See https://github.com/electron/electron/issues/15718 // See https://github.com/electron/electron/issues/15718
(document.activeElement as HTMLElement).blur(); (document.activeElement as HTMLElement).blur();
this.$el.focus(); this.$el!.focus();
webContents.focus(); webContents.focus();
} }
} }
hide(): void { hide(): void {
this.$el.classList.add("disabled"); this.$el!.classList.add("disabled");
this.$el.classList.remove("active"); this.$el!.classList.remove("active");
} }
load(): void { load(): void {
@@ -271,34 +271,34 @@ export default class WebView {
zoomIn(): void { zoomIn(): void {
this.zoomFactor += 0.1; this.zoomFactor += 0.1;
this.$el.setZoomFactor(this.zoomFactor); this.$el!.setZoomFactor(this.zoomFactor);
} }
zoomOut(): void { zoomOut(): void {
this.zoomFactor -= 0.1; this.zoomFactor -= 0.1;
this.$el.setZoomFactor(this.zoomFactor); this.$el!.setZoomFactor(this.zoomFactor);
} }
zoomActualSize(): void { zoomActualSize(): void {
this.zoomFactor = 1; this.zoomFactor = 1;
this.$el.setZoomFactor(this.zoomFactor); this.$el!.setZoomFactor(this.zoomFactor);
} }
logOut(): void { logOut(): void {
ipcRenderer.sendTo(this.$el.getWebContentsId(), "logout"); ipcRenderer.sendTo(this.$el!.getWebContentsId(), "logout");
} }
showKeyboardShortcuts(): void { showKeyboardShortcuts(): void {
ipcRenderer.sendTo(this.$el.getWebContentsId(), "show-keyboard-shortcuts"); ipcRenderer.sendTo(this.$el!.getWebContentsId(), "show-keyboard-shortcuts");
} }
openDevTools(): void { openDevTools(): void {
this.$el.openDevTools(); this.$el!.openDevTools();
} }
back(): void { back(): void {
if (this.$el.canGoBack()) { if (this.$el!.canGoBack()) {
this.$el.goBack(); this.$el!.goBack();
this.focus(); this.focus();
} }
} }
@@ -306,8 +306,8 @@ export default class WebView {
canGoBackButton(): void { canGoBackButton(): void {
const $backButton = document.querySelector( const $backButton = document.querySelector(
"#actions-container #back-action", "#actions-container #back-action",
); )!;
if (this.$el.canGoBack()) { if (this.$el!.canGoBack()) {
$backButton.classList.remove("disable"); $backButton.classList.remove("disable");
} else { } else {
$backButton.classList.add("disable"); $backButton.classList.add("disable");
@@ -315,8 +315,8 @@ export default class WebView {
} }
forward(): void { forward(): void {
if (this.$el.canGoForward()) { if (this.$el!.canGoForward()) {
this.$el.goForward(); this.$el!.goForward();
} }
} }
@@ -326,7 +326,7 @@ export default class WebView {
this.$webviewsContainer.remove("loaded"); this.$webviewsContainer.remove("loaded");
this.loading = true; this.loading = true;
this.props.switchLoading(true, this.props.url); this.props.switchLoading(true, this.props.url);
this.$el.reload(); this.$el!.reload();
} }
forceLoad(): void { forceLoad(): void {
@@ -335,6 +335,6 @@ export default class WebView {
async send(channel: string, ...parameters: unknown[]): Promise<void> { async send(channel: string, ...parameters: unknown[]): Promise<void> {
await this.domReady; await this.domReady;
await this.$el.send(channel, ...parameters); await this.$el!.send(channel, ...parameters);
} }
} }

View File

@@ -9,8 +9,8 @@ const {app} = remote;
customElements.define("send-feedback", SendFeedback); customElements.define("send-feedback", SendFeedback);
export const sendFeedback: SendFeedback = document.querySelector( export const sendFeedback: SendFeedback = document.querySelector(
"send-feedback", "send-feedback",
); )!;
export const feedbackHolder = sendFeedback.parentElement; export const feedbackHolder = sendFeedback.parentElement!;
// Make the button color match zulip app's theme // Make the button color match zulip app's theme
sendFeedback.customStylesheet = "css/feedback.css"; sendFeedback.customStylesheet = "css/feedback.css";

View File

@@ -86,21 +86,25 @@ class ServerManagerView {
tabIndex: number; tabIndex: number;
presetOrgs: string[]; presetOrgs: string[];
constructor() { constructor() {
this.$addServerButton = document.querySelector("#add-tab"); this.$addServerButton = document.querySelector("#add-tab")!;
this.$tabsContainer = document.querySelector("#tabs-container"); this.$tabsContainer = document.querySelector("#tabs-container")!;
const $actionsContainer = document.querySelector("#actions-container"); const $actionsContainer = document.querySelector("#actions-container")!;
this.$reloadButton = $actionsContainer.querySelector("#reload-action"); this.$reloadButton = $actionsContainer.querySelector("#reload-action")!;
this.$loadingIndicator = $actionsContainer.querySelector("#loading-action"); this.$loadingIndicator = $actionsContainer.querySelector(
this.$settingsButton = $actionsContainer.querySelector("#settings-action"); "#loading-action",
this.$webviewsContainer = document.querySelector("#webviews-container"); )!;
this.$backButton = $actionsContainer.querySelector("#back-action"); this.$settingsButton = $actionsContainer.querySelector("#settings-action")!;
this.$dndButton = $actionsContainer.querySelector("#dnd-action"); this.$webviewsContainer = document.querySelector("#webviews-container")!;
this.$backButton = $actionsContainer.querySelector("#back-action")!;
this.$dndButton = $actionsContainer.querySelector("#dnd-action")!;
this.$addServerTooltip = document.querySelector("#add-server-tooltip"); this.$addServerTooltip = document.querySelector("#add-server-tooltip")!;
this.$reloadTooltip = $actionsContainer.querySelector("#reload-tooltip"); this.$reloadTooltip = $actionsContainer.querySelector("#reload-tooltip")!;
this.$loadingTooltip = $actionsContainer.querySelector("#loading-tooltip"); this.$loadingTooltip = $actionsContainer.querySelector("#loading-tooltip")!;
this.$settingsTooltip = $actionsContainer.querySelector("#setting-tooltip"); this.$settingsTooltip = $actionsContainer.querySelector(
"#setting-tooltip",
)!;
// TODO: This should have been querySelector but the problem is that // TODO: This should have been querySelector but the problem is that
// querySelector doesn't return elements not present in dom whereas somehow // querySelector doesn't return elements not present in dom whereas somehow
@@ -110,12 +114,12 @@ class ServerManagerView {
this.$serverIconTooltip = document.getElementsByClassName( this.$serverIconTooltip = document.getElementsByClassName(
"server-tooltip", "server-tooltip",
) as HTMLCollectionOf<HTMLElement>; ) as HTMLCollectionOf<HTMLElement>;
this.$backTooltip = $actionsContainer.querySelector("#back-tooltip"); this.$backTooltip = $actionsContainer.querySelector("#back-tooltip")!;
this.$dndTooltip = $actionsContainer.querySelector("#dnd-tooltip"); this.$dndTooltip = $actionsContainer.querySelector("#dnd-tooltip")!;
this.$sidebar = document.querySelector("#sidebar"); this.$sidebar = document.querySelector("#sidebar")!;
this.$fullscreenPopup = document.querySelector("#fullscreen-popup"); this.$fullscreenPopup = document.querySelector("#fullscreen-popup")!;
this.$fullscreenEscapeKey = process.platform === "darwin" ? "^⌘F" : "F11"; this.$fullscreenEscapeKey = process.platform === "darwin" ? "^⌘F" : "F11";
this.$fullscreenPopup.textContent = `Press ${this.$fullscreenEscapeKey} to exit full screen`; this.$fullscreenPopup.textContent = `Press ${this.$fullscreenEscapeKey} to exit full screen`;
@@ -486,12 +490,12 @@ class ServerManagerView {
// error // error
const $altIcon = document.createElement("div"); const $altIcon = document.createElement("div");
const $parent = $img.parentElement; const $parent = $img.parentElement!;
const $container = $parent.parentElement; const $container = $parent.parentElement!;
const webviewId = $container.dataset.tabId; const webviewId = $container.dataset.tabId!;
const $webview = document.querySelector( const $webview = document.querySelector(
`webview[data-tab-id="${CSS.escape(webviewId)}"]`, `webview[data-tab-id="${CSS.escape(webviewId)}"]`,
); )!;
const realmName = $webview.getAttribute("name"); const realmName = $webview.getAttribute("name");
if (realmName === null) { if (realmName === null) {
@@ -539,7 +543,7 @@ class ServerManagerView {
// as that of its parent element. // as that of its parent element.
const {top} = this.$serverIconTooltip[ const {top} = this.$serverIconTooltip[
index index
].parentElement.getBoundingClientRect(); ].parentElement!.getBoundingClientRect();
this.$serverIconTooltip[index].style.top = `${top}px`; this.$serverIconTooltip[index].style.top = `${top}px`;
} }
@@ -549,7 +553,7 @@ class ServerManagerView {
openFunctionalTab(tabProps: FunctionalTabProps): void { openFunctionalTab(tabProps: FunctionalTabProps): void {
if (this.functionalTabs.has(tabProps.name)) { if (this.functionalTabs.has(tabProps.name)) {
this.activateTab(this.functionalTabs.get(tabProps.name)); this.activateTab(this.functionalTabs.get(tabProps.name)!);
return; return;
} }
@@ -563,20 +567,20 @@ class ServerManagerView {
materialIcon: tabProps.materialIcon, materialIcon: tabProps.materialIcon,
name: tabProps.name, name: tabProps.name,
$root: this.$tabsContainer, $root: this.$tabsContainer,
index: this.functionalTabs.get(tabProps.name), index: this.functionalTabs.get(tabProps.name)!,
tabIndex, tabIndex,
onClick: this.activateTab.bind( onClick: this.activateTab.bind(
this, this,
this.functionalTabs.get(tabProps.name), this.functionalTabs.get(tabProps.name)!,
), ),
onDestroy: this.destroyTab.bind( onDestroy: this.destroyTab.bind(
this, this,
tabProps.name, tabProps.name,
this.functionalTabs.get(tabProps.name), this.functionalTabs.get(tabProps.name)!,
), ),
webview: new WebView({ webview: new WebView({
$root: this.$webviewsContainer, $root: this.$webviewsContainer,
index: this.functionalTabs.get(tabProps.name), index: this.functionalTabs.get(tabProps.name)!,
tabIndex, tabIndex,
url: tabProps.url, url: tabProps.url,
role: "function", role: "function",
@@ -610,7 +614,7 @@ class ServerManagerView {
// closed when the functional tab DOM is ready, handled in webview.js // closed when the functional tab DOM is ready, handled in webview.js
this.$webviewsContainer.classList.remove("loaded"); this.$webviewsContainer.classList.remove("loaded");
this.activateTab(this.functionalTabs.get(tabProps.name)); this.activateTab(this.functionalTabs.get(tabProps.name)!);
} }
async openSettings(nav: NavItem = "General"): Promise<void> { async openSettings(nav: NavItem = "General"): Promise<void> {
@@ -620,7 +624,7 @@ class ServerManagerView {
url: `file://${rendererDirectory}/preference.html#${nav}`, url: `file://${rendererDirectory}/preference.html#${nav}`,
}); });
this.$settingsButton.classList.add("active"); this.$settingsButton.classList.add("active");
await this.tabs[this.functionalTabs.get("Settings")].webview.send( await this.tabs[this.functionalTabs.get("Settings")!].webview.send(
"switch-settings-nav", "switch-settings-nav",
nav, nav,
); );
@@ -798,19 +802,19 @@ class ServerManagerView {
toggleDNDButton(alert: boolean): void { toggleDNDButton(alert: boolean): void {
this.$dndTooltip.textContent = this.$dndTooltip.textContent =
(alert ? "Disable" : "Enable") + " Do Not Disturb"; (alert ? "Disable" : "Enable") + " Do Not Disturb";
this.$dndButton.querySelector("i").textContent = alert this.$dndButton.querySelector("i")!.textContent = alert
? "notifications_off" ? "notifications_off"
: "notifications"; : "notifications";
} }
isLoggedIn(tabIndex: number): boolean { isLoggedIn(tabIndex: number): boolean {
const url = this.tabs[tabIndex].webview.$el.src; const url = this.tabs[tabIndex].webview.$el!.src;
return !(url.endsWith("/login/") || this.tabs[tabIndex].webview.loading); return !(url.endsWith("/login/") || this.tabs[tabIndex].webview.loading);
} }
getActiveWebview(): Electron.WebviewTag { getActiveWebview(): Electron.WebviewTag {
const selector = "webview:not(.disabled)"; const selector = "webview:not(.disabled)";
const webview: Electron.WebviewTag = document.querySelector(selector); const webview: Electron.WebviewTag = document.querySelector(selector)!;
return webview; return webview;
} }
@@ -954,7 +958,7 @@ class ServerManagerView {
: this.tabs.some( : this.tabs.some(
({webview}) => ({webview}) =>
!webview.loading && !webview.loading &&
webview.$el.getWebContentsId() === webContentsId && webview.$el!.getWebContentsId() === webContentsId &&
webview.props.hasPermission?.(origin, permission), webview.props.hasPermission?.(origin, permission),
); );
console.log( console.log(
@@ -1132,10 +1136,10 @@ class ServerManagerView {
); );
for (const webview of webviews) { for (const webview of webviews) {
const currentId = webview.getWebContentsId(); const currentId = webview.getWebContentsId();
const tabId = webview.getAttribute("data-tab-id"); const tabId = webview.getAttribute("data-tab-id")!;
const concurrentTab: HTMLButtonElement = document.querySelector( const concurrentTab: HTMLButtonElement = document.querySelector(
`div[data-tab-id="${CSS.escape(tabId)}"]`, `div[data-tab-id="${CSS.escape(tabId)}"]`,
); )!;
if (currentId === webviewId) { if (currentId === webviewId) {
concurrentTab.click(); concurrentTab.click();
} }
@@ -1152,7 +1156,7 @@ class ServerManagerView {
canvas.height = 128; canvas.height = 128;
canvas.width = 128; canvas.width = 128;
canvas.style.letterSpacing = "-5px"; canvas.style.letterSpacing = "-5px";
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d")!;
ctx.fillStyle = "#f42020"; ctx.fillStyle = "#f42020";
ctx.beginPath(); ctx.beginPath();
ctx.ellipse(64, 64, 64, 64, 0, 0, 2 * Math.PI); ctx.ellipse(64, 64, 64, 64, 0, 0, 2 * Math.PI);

View File

@@ -53,7 +53,7 @@ export default class PreferenceNav {
registerListeners(): void { registerListeners(): void {
for (const navItem of this.navItems) { for (const navItem of this.navItems) {
const $item = document.querySelector(`#nav-${CSS.escape(navItem)}`); const $item = document.querySelector(`#nav-${CSS.escape(navItem)}`)!;
$item.addEventListener("click", () => { $item.addEventListener("click", () => {
this.props.onItemSelected(navItem); this.props.onItemSelected(navItem);
}); });
@@ -71,12 +71,12 @@ export default class PreferenceNav {
} }
activate(navItem: NavItem): void { activate(navItem: NavItem): void {
const $item = document.querySelector(`#nav-${CSS.escape(navItem)}`); const $item = document.querySelector(`#nav-${CSS.escape(navItem)}`)!;
$item.classList.add("active"); $item.classList.add("active");
} }
deactivate(navItem: NavItem): void { deactivate(navItem: NavItem): void {
const $item = document.querySelector(`#nav-${CSS.escape(navItem)}`); const $item = document.querySelector(`#nav-${CSS.escape(navItem)}`)!;
$item.classList.remove("active"); $item.classList.remove("active");
} }
} }

View File

@@ -12,7 +12,7 @@ ipcRenderer.on("logout", () => {
} }
// Create the menu for the below // Create the menu for the below
const dropdown: HTMLElement = document.querySelector(".dropdown-toggle"); const dropdown: HTMLElement = document.querySelector(".dropdown-toggle")!;
dropdown.click(); dropdown.click();
const nodes: NodeListOf<HTMLElement> = document.querySelectorAll( const nodes: NodeListOf<HTMLElement> = document.querySelectorAll(
@@ -29,13 +29,13 @@ ipcRenderer.on("show-keyboard-shortcuts", () => {
// Create the menu for the below // Create the menu for the below
const node: HTMLElement = document.querySelector( const node: HTMLElement = document.querySelector(
"a[data-overlay-trigger=keyboard-shortcuts]", "a[data-overlay-trigger=keyboard-shortcuts]",
); )!;
// Additional check // Additional check
if (node.textContent.trim().toLowerCase() === "keyboard shortcuts (?)") { if (node.textContent!.trim().toLowerCase() === "keyboard shortcuts (?)") {
node.click(); node.click();
} else { } else {
// Atleast click the dropdown // Atleast click the dropdown
const dropdown: HTMLElement = document.querySelector(".dropdown-toggle"); const dropdown: HTMLElement = document.querySelector(".dropdown-toggle")!;
dropdown.click(); dropdown.click();
} }
}); });
@@ -46,7 +46,7 @@ ipcRenderer.on("show-notification-settings", () => {
} }
// Create the menu for the below // Create the menu for the below
const dropdown: HTMLElement = document.querySelector(".dropdown-toggle"); const dropdown: HTMLElement = document.querySelector(".dropdown-toggle")!;
dropdown.click(); dropdown.click();
const nodes: NodeListOf<HTMLElement> = document.querySelectorAll( const nodes: NodeListOf<HTMLElement> = document.querySelectorAll(
@@ -69,8 +69,8 @@ window.addEventListener("load", (event: any): void => {
return; return;
} }
const $reconnectButton = document.querySelector("#reconnect"); const $reconnectButton = document.querySelector("#reconnect")!;
const $settingsButton = document.querySelector("#settings"); const $settingsButton = document.querySelector("#settings")!;
NetworkError.init($reconnectButton, $settingsButton); NetworkError.init($reconnectButton, $settingsButton);
}); });

View File

@@ -6,7 +6,7 @@ import * as ConfigUtil from "../../common/config-util";
const {Tray, Menu, nativeImage, BrowserWindow} = remote; const {Tray, Menu, nativeImage, BrowserWindow} = remote;
let tray: Electron.Tray; let tray: Electron.Tray | null = null;
const ICON_DIR = "../../resources/tray"; const ICON_DIR = "../../resources/tray";
@@ -69,7 +69,7 @@ const renderCanvas = function (arg: number): HTMLCanvasElement {
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
canvas.width = SIZE; canvas.width = SIZE;
canvas.height = SIZE; canvas.height = SIZE;
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d")!;
// Circle // Circle
// If (!config.thick || config.thick && HAS_COUNT) { // If (!config.thick || config.thick && HAS_COUNT) {
@@ -210,15 +210,15 @@ function toggleTray(): void {
createTray(); createTray();
if (process.platform === "linux" || process.platform === "win32") { if (process.platform === "linux" || process.platform === "win32") {
const image = renderNativeImage(unread); const image = renderNativeImage(unread);
tray.setImage(image); tray!.setImage(image);
tray.setToolTip(`${unread} unread messages`); tray!.setToolTip(`${unread} unread messages`);
} }
ConfigUtil.setConfigItem("trayIcon", true); ConfigUtil.setConfigItem("trayIcon", true);
} }
const selector = "webview:not([class*=disabled])"; const selector = "webview:not([class*=disabled])";
const webview: WebviewTag = document.querySelector(selector); const webview: WebviewTag = document.querySelector(selector)!;
const webContents = remote.webContents.fromId(webview.getWebContentsId()); const webContents = remote.webContents.fromId(webview.getWebContentsId());
webContents.send("toggletray", state); webContents.send("toggletray", state);
} }

View File

@@ -17,7 +17,7 @@ const logger = new Logger({
const defaultIconUrl = "../renderer/img/icon.png"; const defaultIconUrl = "../renderer/img/icon.png";
let db: JsonDB; let db!: JsonDB;
reloadDB(); reloadDB();
// Migrate from old schema // Migrate from old schema

View File

@@ -10,7 +10,6 @@
/* Strict type-checking */ /* Strict type-checking */
"strict": true, "strict": true,
"noImplicitAny": true, "noImplicitAny": true,
"strictNullChecks": false,
"noImplicitThis": true, "noImplicitThis": true,
"alwaysStrict": true, "alwaysStrict": true,