Browse Source

chore: tsify browser-window (#24326)

* chore: tsify browser-window

* fix focus

* also tsify top-level-window
Jeremy Rose 4 years ago
parent
commit
80e5007c47

+ 1 - 1
docs/api/browser-window.md

@@ -692,7 +692,7 @@ Returns `BrowserWindow | null` - The window that owns the given `browserView`. I
 
 * `id` Integer
 
-Returns `BrowserWindow` - The window with the given `id`.
+Returns `BrowserWindow | null` - The window with the given `id`.
 
 #### `BrowserWindow.addExtension(path)` _Deprecated_
 

+ 2 - 2
filenames.auto.gni

@@ -191,7 +191,7 @@ auto_filenames = {
     "lib/browser/api/auto-updater/auto-updater-win.js",
     "lib/browser/api/auto-updater/squirrel-update-win.js",
     "lib/browser/api/browser-view.ts",
-    "lib/browser/api/browser-window.js",
+    "lib/browser/api/browser-window.ts",
     "lib/browser/api/content-tracing.ts",
     "lib/browser/api/crash-reporter.ts",
     "lib/browser/api/desktop-capturer.ts",
@@ -216,7 +216,7 @@ auto_filenames = {
     "lib/browser/api/screen.ts",
     "lib/browser/api/session.ts",
     "lib/browser/api/system-preferences.ts",
-    "lib/browser/api/top-level-window.js",
+    "lib/browser/api/top-level-window.ts",
     "lib/browser/api/touch-bar.js",
     "lib/browser/api/tray.ts",
     "lib/browser/api/view.ts",

+ 0 - 168
lib/browser/api/browser-window.js

@@ -1,168 +0,0 @@
-'use strict';
-
-const electron = require('electron');
-const { TopLevelWindow, deprecate } = electron;
-const { BrowserWindow } = process._linkedBinding('electron_browser_window');
-
-Object.setPrototypeOf(BrowserWindow.prototype, TopLevelWindow.prototype);
-
-BrowserWindow.prototype._init = function () {
-  // Call parent class's _init.
-  TopLevelWindow.prototype._init.call(this);
-
-  // Avoid recursive require.
-  const { app } = electron;
-
-  const nativeSetBounds = this.setBounds;
-  this.setBounds = (bounds, ...opts) => {
-    bounds = {
-      ...this.getBounds(),
-      ...bounds
-    };
-    nativeSetBounds.call(this, bounds, ...opts);
-  };
-
-  // Sometimes the webContents doesn't get focus when window is shown, so we
-  // have to force focusing on webContents in this case. The safest way is to
-  // focus it when we first start to load URL, if we do it earlier it won't
-  // have effect, if we do it later we might move focus in the page.
-  //
-  // Though this hack is only needed on macOS when the app is launched from
-  // Finder, we still do it on all platforms in case of other bugs we don't
-  // know.
-  this.webContents.once('load-url', function () {
-    this.focus();
-  });
-
-  // Redirect focus/blur event to app instance too.
-  this.on('blur', (event) => {
-    app.emit('browser-window-blur', event, this);
-  });
-  this.on('focus', (event) => {
-    app.emit('browser-window-focus', event, this);
-  });
-
-  // Subscribe to visibilityState changes and pass to renderer process.
-  let isVisible = this.isVisible() && !this.isMinimized();
-  const visibilityChanged = () => {
-    const newState = this.isVisible() && !this.isMinimized();
-    if (isVisible !== newState) {
-      isVisible = newState;
-      const visibilityState = isVisible ? 'visible' : 'hidden';
-      this.webContents.emit('-window-visibility-change', visibilityState);
-    }
-  };
-
-  const visibilityEvents = ['show', 'hide', 'minimize', 'maximize', 'restore'];
-  for (const event of visibilityEvents) {
-    this.on(event, visibilityChanged);
-  }
-
-  // Notify the creation of the window.
-  const event = process._linkedBinding('electron_browser_event').createEmpty();
-  app.emit('browser-window-created', event, this);
-
-  Object.defineProperty(this, 'devToolsWebContents', {
-    enumerable: true,
-    configurable: false,
-    get () {
-      return this.webContents.devToolsWebContents;
-    }
-  });
-};
-
-const isBrowserWindow = (win) => {
-  return win && win.constructor.name === 'BrowserWindow';
-};
-
-BrowserWindow.fromId = (id) => {
-  const win = TopLevelWindow.fromId(id);
-  return isBrowserWindow(win) ? win : null;
-};
-
-BrowserWindow.getAllWindows = () => {
-  return TopLevelWindow.getAllWindows().filter(isBrowserWindow);
-};
-
-BrowserWindow.getFocusedWindow = () => {
-  for (const window of BrowserWindow.getAllWindows()) {
-    if (window.isFocused() || window.isDevToolsFocused()) return window;
-  }
-  return null;
-};
-
-BrowserWindow.fromWebContents = (webContents) => {
-  for (const window of BrowserWindow.getAllWindows()) {
-    if (window.webContents && window.webContents.equal(webContents)) return window;
-  }
-
-  return null;
-};
-
-BrowserWindow.fromBrowserView = (browserView) => {
-  for (const window of BrowserWindow.getAllWindows()) {
-    if (window.getBrowserView() === browserView) return window;
-  }
-
-  return null;
-};
-
-// Helpers.
-Object.assign(BrowserWindow.prototype, {
-  loadURL (...args) {
-    return this.webContents.loadURL(...args);
-  },
-  getURL (...args) {
-    return this.webContents.getURL();
-  },
-  loadFile (...args) {
-    return this.webContents.loadFile(...args);
-  },
-  reload (...args) {
-    return this.webContents.reload(...args);
-  },
-  send (...args) {
-    return this.webContents.send(...args);
-  },
-  openDevTools (...args) {
-    return this.webContents.openDevTools(...args);
-  },
-  closeDevTools () {
-    return this.webContents.closeDevTools();
-  },
-  isDevToolsOpened () {
-    return this.webContents.isDevToolsOpened();
-  },
-  isDevToolsFocused () {
-    return this.webContents.isDevToolsFocused();
-  },
-  toggleDevTools () {
-    return this.webContents.toggleDevTools();
-  },
-  inspectElement (...args) {
-    return this.webContents.inspectElement(...args);
-  },
-  inspectSharedWorker () {
-    return this.webContents.inspectSharedWorker();
-  },
-  inspectServiceWorker () {
-    return this.webContents.inspectServiceWorker();
-  },
-  showDefinitionForSelection () {
-    return this.webContents.showDefinitionForSelection();
-  },
-  capturePage (...args) {
-    return this.webContents.capturePage(...args);
-  },
-  setTouchBar (touchBar) {
-    electron.TouchBar._setOnWindow(touchBar, this);
-  },
-  getBackgroundThrottling () {
-    return this.webContents.getBackgroundThrottling();
-  },
-  setBackgroundThrottling (allowed) {
-    this.webContents.setBackgroundThrottling(allowed);
-  }
-});
-
-module.exports = BrowserWindow;

+ 182 - 0
lib/browser/api/browser-window.ts

@@ -0,0 +1,182 @@
+import { TopLevelWindow, WebContents, Event, BrowserView, TouchBar } from 'electron';
+import type { BrowserWindow as BWT } from 'electron';
+const { BrowserWindow } = process._linkedBinding('electron_browser_window') as { BrowserWindow: typeof BWT };
+
+Object.setPrototypeOf(BrowserWindow.prototype, TopLevelWindow.prototype);
+
+(BrowserWindow.prototype as any)._init = function (this: BWT) {
+  // Call parent class's _init.
+  (TopLevelWindow.prototype as any)._init.call(this);
+
+  // Avoid recursive require.
+  const { app } = require('electron');
+
+  const nativeSetBounds = this.setBounds;
+  this.setBounds = (bounds, ...opts) => {
+    bounds = {
+      ...this.getBounds(),
+      ...bounds
+    };
+    nativeSetBounds.call(this, bounds, ...opts);
+  };
+
+  // Sometimes the webContents doesn't get focus when window is shown, so we
+  // have to force focusing on webContents in this case. The safest way is to
+  // focus it when we first start to load URL, if we do it earlier it won't
+  // have effect, if we do it later we might move focus in the page.
+  //
+  // Though this hack is only needed on macOS when the app is launched from
+  // Finder, we still do it on all platforms in case of other bugs we don't
+  // know.
+  this.webContents.once('load-url' as any, function (this: WebContents) {
+    this.focus();
+  });
+
+  // Redirect focus/blur event to app instance too.
+  this.on('blur', (event: Event) => {
+    app.emit('browser-window-blur', event, this);
+  });
+  this.on('focus', (event: Event) => {
+    app.emit('browser-window-focus', event, this);
+  });
+
+  // Subscribe to visibilityState changes and pass to renderer process.
+  let isVisible = this.isVisible() && !this.isMinimized();
+  const visibilityChanged = () => {
+    const newState = this.isVisible() && !this.isMinimized();
+    if (isVisible !== newState) {
+      isVisible = newState;
+      const visibilityState = isVisible ? 'visible' : 'hidden';
+      this.webContents.emit('-window-visibility-change', visibilityState);
+    }
+  };
+
+  const visibilityEvents = ['show', 'hide', 'minimize', 'maximize', 'restore'];
+  for (const event of visibilityEvents) {
+    this.on(event as any, visibilityChanged);
+  }
+
+  // Notify the creation of the window.
+  const event = process._linkedBinding('electron_browser_event').createEmpty();
+  app.emit('browser-window-created', event, this);
+
+  Object.defineProperty(this, 'devToolsWebContents', {
+    enumerable: true,
+    configurable: false,
+    get () {
+      return this.webContents.devToolsWebContents;
+    }
+  });
+};
+
+const isBrowserWindow = (win: any) => {
+  return win && win.constructor.name === 'BrowserWindow';
+};
+
+BrowserWindow.fromId = (id: number) => {
+  const win = TopLevelWindow.fromId(id);
+  return isBrowserWindow(win) ? win as any as BWT : null;
+};
+
+BrowserWindow.getAllWindows = () => {
+  return TopLevelWindow.getAllWindows().filter(isBrowserWindow) as any[] as BWT[];
+};
+
+BrowserWindow.getFocusedWindow = () => {
+  for (const window of BrowserWindow.getAllWindows()) {
+    if (window.isFocused() || window.isDevToolsFocused()) return window;
+  }
+  return null;
+};
+
+BrowserWindow.fromWebContents = (webContents: WebContents) => {
+  for (const window of BrowserWindow.getAllWindows()) {
+    if (window.webContents && window.webContents.equal(webContents)) return window;
+  }
+
+  return null;
+};
+
+BrowserWindow.fromBrowserView = (browserView: BrowserView) => {
+  for (const window of BrowserWindow.getAllWindows()) {
+    if (window.getBrowserView() === browserView) return window;
+  }
+
+  return null;
+};
+
+BrowserWindow.prototype.setTouchBar = function (touchBar) {
+  (TouchBar as any)._setOnWindow(touchBar, this);
+};
+
+// Forwarded to webContents:
+
+BrowserWindow.prototype.loadURL = function (...args) {
+  return this.webContents.loadURL(...args);
+};
+
+BrowserWindow.prototype.getURL = function () {
+  return this.webContents.getURL();
+};
+
+BrowserWindow.prototype.loadFile = function (...args) {
+  return this.webContents.loadFile(...args);
+};
+
+BrowserWindow.prototype.reload = function (...args) {
+  return this.webContents.reload(...args);
+};
+
+BrowserWindow.prototype.send = function (...args) {
+  return this.webContents.send(...args);
+};
+
+BrowserWindow.prototype.openDevTools = function (...args) {
+  return this.webContents.openDevTools(...args);
+};
+
+BrowserWindow.prototype.closeDevTools = function () {
+  return this.webContents.closeDevTools();
+};
+
+BrowserWindow.prototype.isDevToolsOpened = function () {
+  return this.webContents.isDevToolsOpened();
+};
+
+BrowserWindow.prototype.isDevToolsFocused = function () {
+  return this.webContents.isDevToolsFocused();
+};
+
+BrowserWindow.prototype.toggleDevTools = function () {
+  return this.webContents.toggleDevTools();
+};
+
+BrowserWindow.prototype.inspectElement = function (...args) {
+  return this.webContents.inspectElement(...args);
+};
+
+BrowserWindow.prototype.inspectSharedWorker = function () {
+  return this.webContents.inspectSharedWorker();
+};
+
+BrowserWindow.prototype.inspectServiceWorker = function () {
+  return this.webContents.inspectServiceWorker();
+};
+
+BrowserWindow.prototype.showDefinitionForSelection = function () {
+  return this.webContents.showDefinitionForSelection();
+};
+
+BrowserWindow.prototype.capturePage = function (...args) {
+  return this.webContents.capturePage(...args);
+};
+
+BrowserWindow.prototype.getBackgroundThrottling = function () {
+  return this.webContents.getBackgroundThrottling();
+};
+
+BrowserWindow.prototype.setBackgroundThrottling = function (allowed: boolean) {
+  return this.webContents.setBackgroundThrottling(allowed);
+};
+
+module.exports = BrowserWindow;

+ 5 - 7
lib/browser/api/top-level-window.js → lib/browser/api/top-level-window.ts

@@ -1,14 +1,12 @@
-'use strict';
-
-const electron = require('electron');
-const { EventEmitter } = require('events');
-const { TopLevelWindow } = process._linkedBinding('electron_browser_top_level_window');
+import { EventEmitter } from 'events';
+import type { TopLevelWindow as TLWT } from 'electron';
+const { TopLevelWindow } = process._linkedBinding('electron_browser_top_level_window') as { TopLevelWindow: typeof TLWT };
 
 Object.setPrototypeOf(TopLevelWindow.prototype, EventEmitter.prototype);
 
-TopLevelWindow.prototype._init = function () {
+(TopLevelWindow.prototype as any)._init = function () {
   // Avoid recursive require.
-  const { app } = electron;
+  const { app } = require('electron');
 
   // Simulate the application menu on platforms other than macOS.
   if (process.platform !== 'darwin') {

+ 0 - 15
spec-main/ambient.d.ts

@@ -19,21 +19,6 @@ declare namespace Electron {
   interface Session {
     destroy(): void;
   }
-
-  // Experimental views API
-  class TopLevelWindow {
-    constructor(args: {show: boolean})
-    setContentView(view: View): void
-  }
-  class WebContentsView {
-    constructor(options: BrowserWindowConstructorOptions)
-  }
-
-  namespace Main {
-    class TopLevelWindow extends Electron.TopLevelWindow {}
-    class View extends Electron.View {}
-    class WebContentsView extends Electron.WebContentsView {}
-  }
 }
 
 declare module 'dbus-native';

+ 1 - 1
spec-main/api-browser-window-spec.ts

@@ -1495,7 +1495,7 @@ describe('BrowserWindow module', () => {
     afterEach(closeAllWindows);
     it('returns the window with id', () => {
       const w = new BrowserWindow({ show: false });
-      expect(BrowserWindow.fromId(w.id).id).to.equal(w.id);
+      expect(BrowserWindow.fromId(w.id)!.id).to.equal(w.id);
     });
   });
 

+ 36 - 0
typings/internal-electron.d.ts

@@ -34,6 +34,7 @@ declare namespace Electron {
     getOwnerBrowserWindow(): Electron.BrowserWindow;
     getLastWebPreferences(): Electron.WebPreferences;
     _getPreloadPaths(): string[];
+    equal(other: WebContents): boolean;
   }
 
   interface WebPreferences {
@@ -96,6 +97,41 @@ declare namespace Electron {
   }
 
   class View {}
+  
+  // Experimental views API
+  class TopLevelWindow {
+    constructor(args: {show: boolean})
+    setContentView(view: View): void
+    static fromId(id: number): TopLevelWindow;
+    static getAllWindows(): TopLevelWindow[];
+    isFocused(): boolean;
+    static getFocusedWindow(): TopLevelWindow | undefined;
+  }
+  class WebContentsView {
+    constructor(options: BrowserWindowConstructorOptions)
+  }
+
+  // Deprecated / undocumented BrowserWindow methods
+  interface BrowserWindow {
+    getURL(): string;
+    send(channel: string, ...args: any[]): void;
+    openDevTools(options?: Electron.OpenDevToolsOptions): void;
+    closeDevTools(): void;
+    isDevToolsOpened(): void;
+    isDevToolsFocused(): void;
+    toggleDevTools(): void;
+    inspectElement(x: number, y: number): void;
+    inspectSharedWorker(): void;
+    inspectServiceWorker(): void;
+    getBackgroundThrottling(): void;
+    setBackgroundThrottling(allowed: boolean): void;
+  }
+
+  namespace Main {
+    class TopLevelWindow extends Electron.TopLevelWindow {}
+    class View extends Electron.View {}
+    class WebContentsView extends Electron.WebContentsView {}
+  }
 }
 
 declare namespace ElectronInternal {