Skip to content

Commit

Permalink
Merge pull request #54 from electron/multi-window
Browse files Browse the repository at this point in the history
feat: Multi window support
  • Loading branch information
felixrieseberg authored Aug 9, 2018
2 parents 82b0fea + 766cf91 commit 61e8524
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 39 deletions.
54 changes: 45 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,62 @@
# Electron Fiddle

> :warning: Still a work in progress, please stay tuned.
<center>

[![Build status](https://ci.appveyor.com/api/projects/status/ngeqlis14337ke3q/branch/master?svg=true)](https://ci.appveyor.com/project/felixrieseberg/fiddle/branch/master)
[![Build Status](https://travis-ci.org/electron/fiddle.svg?branch=master)](https://travis-ci.org/electron/fiddle)

</center>

Electron Fiddle let's you create and play with small Electron experiments. It
greets you with a quick-start template after opening – change a few things,
choose the version of Electron you want to run it with, and play around. Then,
save your fiddle either as a GitHub Gist or to a local folder. Once pushed to
GitHub, anyone can quickly try your fiddle out by just entering it in the
address bar.

![](https://user-images.githubusercontent.com/1426799/41096018-8499e31a-6a53-11e8-9887-7483fd38e58b.png)
![Screenshot](https://user-images.githubusercontent.com/1426799/43873471-8893e3a8-9b3b-11e8-975b-e357f8039b5c.png)

# Features

### Explore Electron

![Screenshot: Electron App running](https://user-images.githubusercontent.com/1426799/43873856-5f66e56e-9b3d-11e8-8472-3a14d6a08c62.png)

Try Electron without installing any dependencies: Fiddle includes everything
you'll need to explore the platform. It also includes examples for every API
available in Electron, so if you want to quickly see what a
[BrowserView][BrowserView] is or how the [desktopCapturer][desktopCapturer]
works, Fiddle has got you covered.

### Code with Types

![Screenshot: Fiddle's Types](https://user-images.githubusercontent.com/1426799/43874324-10e46eae-9b40-11e8-962b-8c793d73c259.png)

Fiddle includes Microsoft's excellent Monaco Editor, the same editor powering
Visual Studio Code. It also installs the type definitions for the currently
selected version of Electron automatically, ensuring that you always have
all Electron APIs only a few keystrokes away.

### Compile and Package

![Screenshot: Fiddle's Tasks Menu](https://user-images.githubusercontent.com/1426799/43874349-3f5abd74-9b40-11e8-9225-ddd1f1087a47.png)

Fiddle can automatically turn your experiment into binaries you can share with
your friends, coworkers, or grandparents. It does so thanks to
[electron-forge][electron-forge], allowing you to package your fiddle as an
app for Windows, macOS, or Linux.

### Start with Fiddle, Continue Wherever

![Screenshot: Visual Studio Code with Fiddle Export](https://user-images.githubusercontent.com/1426799/43874411-9cfd5946-9b40-11e8-8797-dd4138e31933.png)

Fiddle is not an IDE – it is however an excellent starting point. Once your
fiddle has grown up, export it as a project with or without
[electron-forge][electron-forge]. Then, use your favorite editor and take on
the world!

## License

[MIT, please see the LICENSE file for full details](https://github.com/electron/fiddle/blob/master/LICENSE).

When using the Electron or other GitHub logos, be sure to follow the [GitHub
logo guidelines](https://github.com/logos).
logo guidelines](https://github.com/logos).

[BrowserView]: https://electronjs.org/docs/api/browser-view
[desktopCapturer]: https://electronjs.org/docs/api/desktop-capturer
[electron-forge]: https://electronforge.io/
2 changes: 1 addition & 1 deletion src/main/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class IpcMainManager extends EventEmitter {
super();

ipcMainEvents.forEach((name) => {
ipcMain.on(name, (...args) => this.emit(name, ...args));
ipcMain.on(name, (...args: Array<any>) => this.emit(name, ...args));
});
}

Expand Down
8 changes: 7 additions & 1 deletion src/main/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IpcEvents } from '../ipc-events';
import { SHOW_ME_TEMPLATES } from '../templates';
import { showOpenDialog, showSaveDialog } from './files';
import { ipcMainManager } from './ipc';
import { createMainWindow } from './windows';

/**
* Is the passed object a constructor for an Electron Menu?
Expand Down Expand Up @@ -173,7 +174,12 @@ function getFileMenu(): MenuItemConstructorOptions {
const fileMenu: Array<MenuItemConstructorOptions> = [
{
label: 'New Fiddle',
click: () => ipcMainManager.send(IpcEvents.FS_NEW_FIDDLE)
click: () => ipcMainManager.send(IpcEvents.FS_NEW_FIDDLE),
accelerator: 'CommandOrCtrl+N'
}, {
label: 'New Window',
click: () => createMainWindow(),
accelerator: 'CommandOrCtrl+Shift+N'
}, {
type: 'separator'
},
Expand Down
43 changes: 25 additions & 18 deletions src/main/windows.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { BrowserWindow } from 'electron';
import { WindowNames } from '../interfaces';
import { IpcEvents } from '../ipc-events';
import { createContextMenu } from './context-menu';
import { ipcMainManager } from './ipc';

// Keep a global reference of the window objects, if we don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
export const browserWindows: Record<WindowNames, Electron.BrowserWindow | null> = {
main: null
};
export let browserWindows: Array<BrowserWindow> = [];

/**
* Gets default options for the main window
Expand All @@ -27,26 +22,38 @@ export function getMainWindowOptions(): Electron.BrowserWindowConstructorOptions
};
}


/**
* Gets or creates the main window, returning it in both cases.
* Creates a new main window.
*
* @export
* @returns {Electron.BrowserWindow}
*/
export function getOrCreateMainWindow(): Electron.BrowserWindow {
if (browserWindows.main) return browserWindows.main;

browserWindows.main = new BrowserWindow(getMainWindowOptions());
browserWindows.main.loadFile('./dist/index.html');
export function createMainWindow(): Electron.BrowserWindow {
const browserWindow = new BrowserWindow(getMainWindowOptions());
browserWindow.loadFile('./dist/index.html');

browserWindows.main.webContents.once('dom-ready', () => {
if (browserWindows.main) {
createContextMenu(browserWindows.main);
browserWindow.webContents.once('dom-ready', () => {
if (browserWindow) {
createContextMenu(browserWindow);
}
});

browserWindows.main.on('closed', () => {
browserWindows.main = null;
browserWindow.on('closed', () => {
browserWindows = browserWindows
.filter((bw) => browserWindow !== bw);
});

return browserWindows.main;
browserWindows.push(browserWindow);

return browserWindow;
}

/**
* Gets or creates the main window, returning it in both cases.
*
* @returns {Electron.BrowserWindow}
*/
export function getOrCreateMainWindow(): Electron.BrowserWindow {
return BrowserWindow.getFocusedWindow() || browserWindows[0] || createMainWindow();
}
19 changes: 14 additions & 5 deletions tests/main/menu-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import * as electron from 'electron';
import { IpcEvents } from '../../src/ipc-events';
import { ipcMainManager } from '../../src/main/ipc';
import { setupMenu } from '../../src/main/menu';
import { createMainWindow } from '../../src/main/windows';
import { overridePlatform, resetPlatform } from '../utils';

jest.mock('../../src/main/windows');

describe('menu', () => {
beforeEach(() => {
(electron.app.getName as any).mockReturnValue('Electron Fiddle');
Expand Down Expand Up @@ -195,28 +198,34 @@ describe('menu', () => {
expect(ipcMainManager.send).toHaveBeenCalledWith(IpcEvents.FS_NEW_FIDDLE);
});

it('creates a new window', () => {
file.submenu[1].click();
file.submenu[1].click();
expect(createMainWindow).toHaveBeenCalledTimes(2);
});

it('opens a fiddle', () => {
file.submenu[2].click();
file.submenu[3].click();
expect(electron.dialog.showOpenDialog).toHaveBeenCalled();
});

it('saves a fiddle', () => {
file.submenu[4].click();
file.submenu[5].click();
expect(ipcMainManager.send).toHaveBeenCalledWith(IpcEvents.FS_SAVE_FIDDLE);
});

it('saves a fiddle as', () => {
file.submenu[5].click();
file.submenu[6].click();
expect(electron.dialog.showOpenDialog).toHaveBeenCalled();
});

it('saves a fiddle as a gist', () => {
file.submenu[7].click();
file.submenu[8].click();
expect(ipcMainManager.send).toHaveBeenCalledWith(IpcEvents.FS_SAVE_FIDDLE_GIST);
});

it('saves a fiddle as a forge project', () => {
file.submenu[8].click();
file.submenu[9].click();
expect(electron.dialog.showOpenDialog).toHaveBeenCalled();
});
});
Expand Down
10 changes: 5 additions & 5 deletions tests/main/windows-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,21 @@ describe('windows', () => {

describe('getOrCreateMainWindow()', () => {
it('creates a window on first call', () => {
expect(browserWindows.main).toBe(null);
expect(browserWindows.length).toBe(0);
getOrCreateMainWindow();
expect(browserWindows.main).toBeTruthy();
expect(browserWindows[0]).toBeTruthy();
});

it('updates "browserWindows" on "close"', () => {
getOrCreateMainWindow();
expect(browserWindows.main).toBeTruthy();
expect(browserWindows[0]).toBeTruthy();
getOrCreateMainWindow().emit('closed');
expect(browserWindows.main).toBe(null);
expect(browserWindows.length).toBe(0);
});

it('creates the context menu on "dom-ready"', () => {
getOrCreateMainWindow();
expect(browserWindows.main).toBeTruthy();
expect(browserWindows[0]).toBeTruthy();
getOrCreateMainWindow().webContents.emit('dom-ready');
expect(createContextMenu).toHaveBeenCalled();
});
Expand Down

0 comments on commit 61e8524

Please sign in to comment.