From 8f96fe42c7b731c321e60dec9c4cac36a82c737c Mon Sep 17 00:00:00 2001 From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com> Date: Mon, 10 Jan 2022 17:38:23 -0500 Subject: [PATCH] [MM-32371] Communicate history information to webapp for disable/enabling Back/Forward buttons (#1941) * [MM-32371] Communicate history information to webapp for disable/enabling Back/Forward buttons * Merge'd --- src/common/communication.ts | 1 + src/main/menus/app.ts | 18 ++++---- src/main/preload/mattermost.js | 19 ++++++++ src/main/views/MattermostView.ts | 2 + src/main/windows/windowManager.test.js | 62 ++++++++++++++++++++++++++ src/main/windows/windowManager.ts | 18 ++++++++ 6 files changed, 112 insertions(+), 8 deletions(-) diff --git a/src/common/communication.ts b/src/common/communication.ts index c288d3eb..7e7dda3a 100644 --- a/src/common/communication.ts +++ b/src/common/communication.ts @@ -89,6 +89,7 @@ export const REQUEST_TEAMS_DROPDOWN_INFO = 'request-teams-dropdown-info'; export const RECEIVE_DROPDOWN_MENU_SIZE = 'receive-dropdown-menu-size'; export const SEND_DROPDOWN_MENU_SIZE = 'send-dropdown-menu-size'; +export const BROWSER_HISTORY_BUTTON = 'browser-history-button'; export const BROWSER_HISTORY_PUSH = 'browser-history-push'; export const APP_LOGGED_IN = 'app-logged-in'; export const APP_LOGGED_OUT = 'app-logged-out'; diff --git a/src/main/menus/app.ts b/src/main/menus/app.ts index 25ff9662..75870d01 100644 --- a/src/main/menus/app.ts +++ b/src/main/menus/app.ts @@ -3,9 +3,9 @@ // See LICENSE.txt for license information. 'use strict'; -import {app, ipcMain, Menu, MenuItemConstructorOptions, MenuItem, session, shell, WebContents, webContents, clipboard} from 'electron'; +import {app, ipcMain, Menu, MenuItemConstructorOptions, MenuItem, session, shell, WebContents, clipboard} from 'electron'; -import {OPEN_TEAMS_DROPDOWN, SHOW_NEW_SERVER_MODAL} from 'common/communication'; +import {BROWSER_HISTORY_BUTTON, OPEN_TEAMS_DROPDOWN, SHOW_NEW_SERVER_MODAL} from 'common/communication'; import {Config} from 'common/config'; import {TabType, getTabDisplayName} from 'common/tabs/TabView'; @@ -178,18 +178,20 @@ export function createTemplate(config: Config) { label: 'Back', accelerator: process.platform === 'darwin' ? 'Cmd+[' : 'Alt+Left', click: () => { - const focused = webContents.getFocusedWebContents(); - if (focused.canGoBack()) { - focused.goBack(); + const view = WindowManager.viewManager?.getCurrentView(); + if (view && view.view.webContents.canGoBack() && !view.isAtRoot) { + view.view.webContents.goBack(); + ipcMain.emit(BROWSER_HISTORY_BUTTON, null, view.name); } }, }, { label: 'Forward', accelerator: process.platform === 'darwin' ? 'Cmd+]' : 'Alt+Right', click: () => { - const focused = webContents.getFocusedWebContents(); - if (focused.canGoForward()) { - focused.goForward(); + const view = WindowManager.viewManager?.getCurrentView(); + if (view && view.view.webContents.canGoForward()) { + view.view.webContents.goForward(); + ipcMain.emit(BROWSER_HISTORY_BUTTON, null, view.name); } }, }], diff --git a/src/main/preload/mattermost.js b/src/main/preload/mattermost.js index cbb18728..9750633b 100644 --- a/src/main/preload/mattermost.js +++ b/src/main/preload/mattermost.js @@ -21,6 +21,7 @@ import { REACT_APP_INITIALIZED, USER_ACTIVITY_UPDATE, CLOSE_TEAMS_DROPDOWN, + BROWSER_HISTORY_BUTTON, BROWSER_HISTORY_PUSH, APP_LOGGED_IN, APP_LOGGED_OUT, @@ -82,6 +83,7 @@ window.addEventListener('load', () => { } watchReactAppUntilInitialized(() => { ipcRenderer.send(REACT_APP_INITIALIZED, viewName); + ipcRenderer.send(BROWSER_HISTORY_BUTTON, viewName); }); }); @@ -143,6 +145,10 @@ window.addEventListener('message', ({origin, data = {}} = {}) => { ipcRenderer.send(BROWSER_HISTORY_PUSH, viewName, path); break; } + case 'history-button': { + ipcRenderer.send(BROWSER_HISTORY_BUTTON, viewName); + break; + } default: if (typeof type === 'undefined') { console.log('ignoring message of undefined type:'); @@ -253,6 +259,19 @@ ipcRenderer.on(BROWSER_HISTORY_PUSH, (event, pathName) => { ); }); +ipcRenderer.on(BROWSER_HISTORY_BUTTON, (event, enableBack, enableForward) => { + window.postMessage( + { + type: 'history-button-return', + message: { + enableBack, + enableForward, + }, + }, + window.location.origin, + ); +}); + window.addEventListener('storage', (e) => { if (e.key === '__login__' && e.storageArea === localStorage && e.newValue) { ipcRenderer.send(APP_LOGGED_IN, viewName); diff --git a/src/main/views/MattermostView.ts b/src/main/views/MattermostView.ts index 03ec162a..f5874c74 100644 --- a/src/main/views/MattermostView.ts +++ b/src/main/views/MattermostView.ts @@ -48,6 +48,7 @@ export class MattermostView extends EventEmitter { view: BrowserView; isVisible: boolean; isLoggedIn: boolean; + isAtRoot: boolean; options: BrowserViewConstructorOptions; serverInfo: ServerInfo; @@ -88,6 +89,7 @@ export class MattermostView extends EventEmitter { }; this.isVisible = false; this.isLoggedIn = false; + this.isAtRoot = true; this.view = new BrowserView(this.options); this.resetLoadingStatus(); diff --git a/src/main/windows/windowManager.test.js b/src/main/windows/windowManager.test.js index 51c5e66b..478b6ba5 100644 --- a/src/main/windows/windowManager.test.js +++ b/src/main/windows/windowManager.test.js @@ -759,6 +759,7 @@ describe('main/windows/windowManager', () => { openClosedTab: jest.fn(), showByName: jest.fn(), }; + windowManager.handleBrowserHistoryButton = jest.fn(); beforeEach(() => { Config.teams = [ @@ -817,4 +818,65 @@ describe('main/windows/windowManager', () => { expect(view1.view.webContents.send).not.toBeCalled(); }); }); + + describe('handleBrowserHistoryButton', () => { + const windowManager = new WindowManager(); + const view1 = { + name: 'server-1_tab-messaging', + isLoggedIn: true, + isAtRoot: true, + tab: { + type: TAB_MESSAGING, + server: { + url: 'http://server-1.com', + }, + url: new URL('http://server-1.com'), + }, + view: { + webContents: { + canGoBack: jest.fn(), + canGoForward: jest.fn(), + clearHistory: jest.fn(), + send: jest.fn(), + getURL: jest.fn(), + }, + }, + }; + windowManager.viewManager = { + views: new Map([ + ['server-1_tab-messaging', view1], + ]), + }; + + beforeEach(() => { + Config.teams = [ + { + name: 'server-1', + url: 'http://server-1.com', + order: 0, + tabs: [ + { + name: 'tab-messaging', + order: 0, + isOpen: true, + }, + ], + }, + ]; + }); + + afterEach(() => { + jest.resetAllMocks(); + Config.teams = []; + view1.isAtRoot = true; + }); + + it('should erase history and set isAtRoot when navigating to root URL', () => { + view1.isAtRoot = false; + view1.view.webContents.getURL.mockReturnValue(view1.tab.url.toString()); + windowManager.handleBrowserHistoryButton(null, 'server-1_tab-messaging'); + expect(view1.view.webContents.clearHistory).toHaveBeenCalled(); + expect(view1.isAtRoot).toBe(true); + }); + }); }); diff --git a/src/main/windows/windowManager.ts b/src/main/windows/windowManager.ts index 66636ec9..0becdf9e 100644 --- a/src/main/windows/windowManager.ts +++ b/src/main/windows/windowManager.ts @@ -21,6 +21,7 @@ import { GET_VIEW_WEBCONTENTS_ID, RESIZE_MODAL, APP_LOGGED_OUT, + BROWSER_HISTORY_BUTTON, } from 'common/communication'; import urlUtils from 'common/utils/url'; import Config from 'common/config'; @@ -56,6 +57,7 @@ export class WindowManager { ipcMain.on(REACT_APP_INITIALIZED, this.handleReactAppInitialized); ipcMain.on(LOADING_SCREEN_ANIMATION_FINISHED, this.handleLoadingScreenAnimationFinished); ipcMain.on(BROWSER_HISTORY_PUSH, this.handleBrowserHistoryPush); + ipcMain.on(BROWSER_HISTORY_BUTTON, this.handleBrowserHistoryButton); ipcMain.on(APP_LOGGED_IN, this.handleAppLoggedIn); ipcMain.on(APP_LOGGED_OUT, this.handleAppLoggedOut); ipcMain.handle(GET_VIEW_NAME, this.handleGetViewName); @@ -558,6 +560,22 @@ export class WindowManager { // Special case check for Channels to not force a redirect to "/", causing a refresh if (!(redirectedView !== currentView && redirectedView?.tab.type === TAB_MESSAGING && pathName === '/')) { redirectedView?.view.webContents.send(BROWSER_HISTORY_PUSH, pathName); + if (redirectedView) { + this.handleBrowserHistoryButton(e, redirectedView.name); + } + } + } + + handleBrowserHistoryButton = (e: IpcMainEvent, viewName: string) => { + const currentView = this.viewManager?.views.get(viewName); + if (currentView) { + if (currentView.view.webContents.getURL() === currentView.tab.url.toString()) { + currentView.view.webContents.clearHistory(); + currentView.isAtRoot = true; + } else { + currentView.isAtRoot = false; + } + currentView?.view.webContents.send(BROWSER_HISTORY_BUTTON, currentView.view.webContents.canGoBack(), currentView.view.webContents.canGoForward()); } }