[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
This commit is contained in:
Devin Binnie
2022-01-10 17:38:23 -05:00
committed by GitHub
parent 8ad949eedb
commit 8f96fe42c7
6 changed files with 112 additions and 8 deletions

View File

@@ -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';

View File

@@ -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);
}
},
}],

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);
});
});
});

View File

@@ -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());
}
}