From ec8e0b9cc25fa8137557b4abac14d3da16cb97d8 Mon Sep 17 00:00:00 2001 From: Christopher Poile Date: Fri, 17 Feb 2023 13:41:01 -0500 Subject: [PATCH] MM-49079 - Calls: process link clicks from Calls popout (#2558) * process link clicks from Calls popout * add a mock for windows tests --- src/common/communication.ts | 1 + src/main/preload/callsWidget.js | 2 ++ src/main/windows/callsWidgetWindow.test.js | 26 ++++++++++++++++++---- src/main/windows/callsWidgetWindow.ts | 8 ++++++- src/main/windows/windowManager.test.js | 24 ++++++++++++++++++++ src/main/windows/windowManager.ts | 13 ++++++++--- src/types/calls.ts | 4 ++++ 7 files changed, 70 insertions(+), 8 deletions(-) diff --git a/src/common/communication.ts b/src/common/communication.ts index b247fd46..0745c510 100644 --- a/src/common/communication.ts +++ b/src/common/communication.ts @@ -135,6 +135,7 @@ export const CALLS_LEAVE_CALL = 'calls-leave-call'; export const CALLS_WIDGET_RESIZE = 'calls-widget-resize'; export const CALLS_WIDGET_SHARE_SCREEN = 'calls-widget-share-screen'; export const CALLS_WIDGET_CHANNEL_LINK_CLICK = 'calls-widget-channel-link-click'; +export const CALLS_LINK_CLICK = 'calls-link-click'; export const CALLS_JOINED_CALL = 'calls-joined-call'; export const CALLS_POPOUT_FOCUS = 'calls-popout-focus'; export const CALLS_ERROR = 'calls-error'; diff --git a/src/main/preload/callsWidget.js b/src/main/preload/callsWidget.js index 1bc37ed3..1b8a1db4 100644 --- a/src/main/preload/callsWidget.js +++ b/src/main/preload/callsWidget.js @@ -16,6 +16,7 @@ import { DESKTOP_SOURCES_RESULT, DESKTOP_SOURCES_MODAL_REQUEST, DISPATCH_GET_DESKTOP_SOURCES, + CALLS_LINK_CLICK, } from 'common/communication'; window.addEventListener('message', ({origin, data = {}} = {}) => { @@ -47,6 +48,7 @@ window.addEventListener('message', ({origin, data = {}} = {}) => { } case DESKTOP_SOURCES_MODAL_REQUEST: case CALLS_WIDGET_CHANNEL_LINK_CLICK: + case CALLS_LINK_CLICK: case CALLS_WIDGET_RESIZE: case CALLS_JOINED_CALL: case CALLS_POPOUT_FOCUS: diff --git a/src/main/windows/callsWidgetWindow.test.js b/src/main/windows/callsWidgetWindow.test.js index 339c4f41..8d67dfe9 100644 --- a/src/main/windows/callsWidgetWindow.test.js +++ b/src/main/windows/callsWidgetWindow.test.js @@ -10,17 +10,26 @@ import { MINIMUM_CALLS_WIDGET_HEIGHT, CALLS_PLUGIN_ID, } from 'common/utils/constants'; +import WebContentsEventManager from '../views/webContentEvents'; import CallsWidgetWindow from './callsWidgetWindow'; jest.mock('electron', () => ({ + app: { + getAppPath: () => '/path/to/app', + }, BrowserWindow: jest.fn(), ipcMain: { on: jest.fn(), off: jest.fn(), + handle: jest.fn(), }, })); +jest.mock('../views/webContentEvents', () => ({ + generateNewWindowListener: jest.fn(), +})); + describe('main/windows/callsWidgetWindow', () => { describe('create CallsWidgetWindow', () => { const widgetConfig = { @@ -330,9 +339,7 @@ describe('main/windows/callsWidgetWindow', () => { send: jest.fn(), }; - let isMinimized = false; baseWindow.restore = jest.fn(); - baseWindow.isMinimized = jest.fn(() => isMinimized); const widgetWindow = new CallsWidgetWindow(mainWindow, mainView, widgetConfig); @@ -341,19 +348,30 @@ describe('main/windows/callsWidgetWindow', () => { expect(widgetWindow.popOut).toBeNull(); - const popOut = new BrowserWindow(); + const popOut = new EventEmitter(); + popOut.webContents = { + setWindowOpenHandler: jest.fn(), + on: jest.fn(), + id: 'webContentsId', + }; + popOut.focus = jest.fn(); + popOut.restore = jest.fn(); + popOut.isMinimized = jest.fn().mockReturnValue(false); + widgetWindow.onPopOutFocus(); expect(popOut.focus).not.toHaveBeenCalled(); expect(popOut.restore).not.toHaveBeenCalled(); widgetWindow.onPopOutCreate(popOut); expect(widgetWindow.popOut).toBe(popOut); + expect(popOut.webContents.setWindowOpenHandler).toHaveBeenCalled(); + expect(WebContentsEventManager.generateNewWindowListener).toHaveBeenCalledWith('webContentsId', true); widgetWindow.onPopOutFocus(); expect(popOut.focus).toHaveBeenCalled(); expect(popOut.restore).not.toHaveBeenCalled(); - isMinimized = true; + popOut.isMinimized = jest.fn().mockReturnValue(true); widgetWindow.onPopOutFocus(); expect(popOut.focus).toHaveBeenCalled(); expect(popOut.restore).toHaveBeenCalled(); diff --git a/src/main/windows/callsWidgetWindow.ts b/src/main/windows/callsWidgetWindow.ts index 2d426a4e..e4104e3a 100644 --- a/src/main/windows/callsWidgetWindow.ts +++ b/src/main/windows/callsWidgetWindow.ts @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import url from 'url'; - import {EventEmitter} from 'events'; import {BrowserWindow, Rectangle, ipcMain, IpcMainEvent} from 'electron'; import log from 'electron-log'; @@ -31,6 +30,8 @@ import { CALLS_WIDGET_RESIZE, CALLS_WIDGET_SHARE_SCREEN, } from 'common/communication'; +import webContentsEventManager from 'main/views/webContentEvents'; +import Config from 'common/config'; type LoadURLOpts = { extraHeaders: string; @@ -200,6 +201,11 @@ export default class CallsWidgetWindow extends EventEmitter { private onPopOutCreate = (win: BrowserWindow) => { this.popOut = win; + + // Let the webContentsEventManager handle links that try to open a new window + const spellcheck = Config.useSpellChecker; + const newWindow = webContentsEventManager.generateNewWindowListener(this.popOut.webContents.id, spellcheck); + this.popOut.webContents.setWindowOpenHandler(newWindow); } private onPopOutFocus = () => { diff --git a/src/main/windows/windowManager.test.js b/src/main/windows/windowManager.test.js index 01786fe6..215dd6f6 100644 --- a/src/main/windows/windowManager.test.js +++ b/src/main/windows/windowManager.test.js @@ -80,6 +80,7 @@ jest.mock('../downloadsManager', () => ({ })); jest.mock('./callsWidgetWindow'); +jest.mock('main/views/webContentEvents', () => ({})); describe('main/windows/windowManager', () => { describe('handleUpdateConfig', () => { @@ -1266,6 +1267,29 @@ describe('main/windows/windowManager', () => { }); }); + describe('handleCallsLinkClick', () => { + const windowManager = new WindowManager(); + const view1 = { + view: { + webContents: { + send: jest.fn(), + }, + }, + }; + windowManager.viewManager = { + views: new Map([ + ['server-1_tab-messaging', view1], + ]), + getCurrentView: jest.fn(), + }; + + it('should pass through the click link to browser history push', () => { + windowManager.viewManager.getCurrentView.mockReturnValue(view1); + windowManager.handleCallsLinkClick(null, {link: '/other/subpath'}); + expect(view1.view.webContents.send).toBeCalledWith('browser-history-push', '/other/subpath'); + }); + }); + describe('getServerURLFromWebContentsId', () => { const view = { name: 'server-1_tab-messaging', diff --git a/src/main/windows/windowManager.ts b/src/main/windows/windowManager.ts index cc1d0809..305da340 100644 --- a/src/main/windows/windowManager.ts +++ b/src/main/windows/windowManager.ts @@ -7,9 +7,7 @@ import path from 'path'; import {app, BrowserWindow, nativeImage, systemPreferences, ipcMain, IpcMainEvent, IpcMainInvokeEvent, desktopCapturer} from 'electron'; import log from 'electron-log'; -import { - CallsJoinCallMessage, -} from 'types/calls'; +import {CallsJoinCallMessage, CallsLinkClickMessage} from 'types/calls'; import { MAXIMIZE_CHANGE, @@ -35,6 +33,7 @@ import { DESKTOP_SOURCES_MODAL_REQUEST, CALLS_WIDGET_CHANNEL_LINK_CLICK, CALLS_ERROR, + CALLS_LINK_CLICK, } from 'common/communication'; import urlUtils from 'common/utils/url'; import {SECOND} from 'common/utils/constants'; @@ -95,6 +94,7 @@ export class WindowManager { ipcMain.on(CALLS_LEAVE_CALL, () => this.callsWidgetWindow?.close()); ipcMain.on(DESKTOP_SOURCES_MODAL_REQUEST, this.handleDesktopSourcesModalRequest); ipcMain.on(CALLS_WIDGET_CHANNEL_LINK_CLICK, this.handleCallsWidgetChannelLinkClick); + ipcMain.on(CALLS_LINK_CLICK, this.handleCallsLinkClick); } handleUpdateConfig = () => { @@ -150,6 +150,13 @@ export class WindowManager { } } + handleCallsLinkClick = (_: IpcMainEvent, msg: CallsLinkClickMessage) => { + log.debug('WindowManager.handleCallsLinkClick with linkURL', msg.link); + this.mainWindow?.focus(); + const currentView = this.viewManager?.getCurrentView(); + currentView?.view.webContents.send(BROWSER_HISTORY_PUSH, msg.link); + } + showSettingsWindow = () => { log.debug('WindowManager.showSettingsWindow'); diff --git a/src/types/calls.ts b/src/types/calls.ts index 592597ac..9339cc9d 100644 --- a/src/types/calls.ts +++ b/src/types/calls.ts @@ -28,3 +28,7 @@ export type CallsWidgetShareScreenMessage = { export type CallsJoinedCallMessage = { callID: string; } + +export type CallsLinkClickMessage = { + link: string | URL; +}