From 09a110ffac28bdb4c6aa8e782fe7af1a33f2b121 Mon Sep 17 00:00:00 2001 From: bingenito Date: Wed, 29 May 2019 15:19:50 -0400 Subject: [PATCH] Add persist: false option to createWindow If createWindow options include persist: false, do not include the window in layout persistence. Fixes #241 --- packages/desktopjs-electron/src/electron.ts | 7 +- .../desktopjs-electron/tests/electron.spec.ts | 22 ++++ packages/desktopjs-openfin/src/openfin.ts | 34 ++--- .../desktopjs-openfin/tests/openfin.spec.ts | 116 ++++++++++-------- packages/desktopjs/src/Default/default.ts | 10 +- .../tests/unit/Default/default.spec.ts | 19 +++ 6 files changed, 138 insertions(+), 70 deletions(-) diff --git a/packages/desktopjs-electron/src/electron.ts b/packages/desktopjs-electron/src/electron.ts index bc986813..0189e918 100644 --- a/packages/desktopjs-electron/src/electron.ts +++ b/packages/desktopjs-electron/src/electron.ts @@ -505,6 +505,11 @@ export class ElectronContainer extends WebContainerBase { return new Promise((resolve, reject) => { this.getAllWindows().then(windows => { windows.forEach(window => { + const options = window.innerWindow[Container.windowOptionsPropertyKey]; + if (options && "persist" in options && !options.persist) { + return; + } + promises.push(new Promise(innerResolve => { window.getGroup().then(async group => { layout.windows.push( @@ -514,7 +519,7 @@ export class ElectronContainer extends WebContainerBase { url: window.innerWindow.webContents.getURL(), main: (mainWindow === window.innerWindow), state: await window.getState(), - options: window.innerWindow[Container.windowOptionsPropertyKey], + options: options, bounds: window.innerWindow.getBounds(), group: group.map(win => win.id) }); diff --git a/packages/desktopjs-electron/tests/electron.spec.ts b/packages/desktopjs-electron/tests/electron.spec.ts index fdd3dcb5..19ebb877 100644 --- a/packages/desktopjs-electron/tests/electron.spec.ts +++ b/packages/desktopjs-electron/tests/electron.spec.ts @@ -665,6 +665,28 @@ describe("ElectronContainer", () => { done(); }); }); + + it("buildLayout skips windows with persist false", (done) => { + const win1 = jasmine.createSpyObj(["getOptions", "getGroup", "getState"]); + Object.defineProperty(win1, "innerWindow", { + value: { name: "win1", "desktopJS-options": { main: true }, "webContents": { getURL() { return "" } }, getBounds() { return undefined } } + }); + win1.getGroup.and.returnValue(Promise.resolve([])); + win1.getState.and.returnValue(Promise.resolve(undefined)); + const win2 = jasmine.createSpyObj(["getOptions", "getGroup", "getState"]); + Object.defineProperty(win2, "innerWindow", { + value: { name: "win2", "desktopJS-options": { persist: false }, "webContents": { getURL() { return "" } }, getBounds() { return undefined } } + }); + win2.getGroup.and.returnValue(Promise.resolve([])); + win2.getState.and.returnValue(Promise.resolve(undefined)); + spyOn(container, "getMainWindow").and.returnValue(win1); + spyOn(container, "getAllWindows").and.returnValue(Promise.resolve([win1, win2])); + container.buildLayout().then(layout => { + expect(layout).toBeDefined(); + expect(layout.windows.length).toEqual(1); + expect(layout.windows[0].name === "win1") + }).then(done); + }); }); }); diff --git a/packages/desktopjs-openfin/src/openfin.ts b/packages/desktopjs-openfin/src/openfin.ts index a818d06b..73f6d69e 100644 --- a/packages/desktopjs-openfin/src/openfin.ts +++ b/packages/desktopjs-openfin/src/openfin.ts @@ -661,21 +661,27 @@ export class OpenFinContainer extends WebContainerBase { const window = djsWindow.innerWindow; window.getBounds(bounds => { window.getOptions(options => { - delete (options).show; // show is an undocumented option that interferes with the createWindow mapping of show -> autoShow - window.getGroup(group => { - layout.windows.push( - { - name: window.name, - id: window.name, - url: window.getNativeWindow() ? window.getNativeWindow().location.toString() : options.url, - main: (mainWindow && (mainWindow.name === window.name)), - options: options, - state: state, - bounds: { x: bounds.left, y: bounds.top, width: bounds.width, height: bounds.height }, - group: group.map(win => win.name) - }); + // If window was created with persist: false, skip from layout + const customData: any = (options.customData ? JSON.parse(options.customData) : undefined); + if (customData && "persist" in customData && !customData.persist) { innerResolve(); - }, innerReject); + } else { + delete (options).show; // show is an undocumented option that interferes with the createWindow mapping of show -> autoShow + window.getGroup(group => { + layout.windows.push( + { + name: window.name, + id: window.name, + url: window.getNativeWindow() ? window.getNativeWindow().location.toString() : options.url, + main: (mainWindow && (mainWindow.name === window.name)), + options: options, + state: state, + bounds: { x: bounds.left, y: bounds.top, width: bounds.width, height: bounds.height }, + group: group.map(win => win.name) + }); + innerResolve(); + }, innerReject); + } }, innerReject); }, innerReject); })); diff --git a/packages/desktopjs-openfin/tests/openfin.spec.ts b/packages/desktopjs-openfin/tests/openfin.spec.ts index 119209d1..46b5695a 100644 --- a/packages/desktopjs-openfin/tests/openfin.spec.ts +++ b/packages/desktopjs-openfin/tests/openfin.spec.ts @@ -6,7 +6,7 @@ class MockDesktop { public static application: any = { eventListeners: new Map(), uuid: "uuid", - getChildWindows(callback) { callback([MockWindow.singleton]); }, + getChildWindows(callback) { callback([MockWindow.singleton, new MockWindow("Window2", JSON.stringify({ persist: false }))]); }, setTrayIcon() { }, getWindow() { return MockWindow.singleton; }, addEventListener(eventName, listener) { @@ -60,9 +60,11 @@ class MockInterApplicationBus { class MockWindow { static singleton: MockWindow = new MockWindow("Singleton"); public nativeWindow: Window = jasmine.createSpyObj("window", ["location", "getState", "setState"]); + private customData: string; - constructor(name?: string) { + constructor(name?: string, customData?: string) { this.name = name; + this.customData = customData; } public name: string; @@ -142,7 +144,7 @@ class MockWindow { } getOptions(callback: (options: any) => void, error: (reason) => void): any { - callback({ url: "url" }); + callback({ url: "url", customData: this.customData }); return {}; } @@ -647,72 +649,80 @@ describe("OpenFinContainer", () => { container.addListener("window-created", () => done()); MockDesktop.application.emit('window-created', { name: "name" }); }); + }); - describe("window management", () => { - it("getAllWindows returns wrapped native windows", (done) => { - container.getAllWindows().then(windows => { - expect(windows).not.toBeNull(); - expect(windows.length).toEqual(2); - expect(windows[0].innerWindow).toEqual(MockWindow.singleton); - done(); - }); + describe("window management", () => { + it("getAllWindows returns wrapped native windows", (done) => { + container.getAllWindows().then(windows => { + expect(windows).not.toBeNull(); + expect(windows.length).toEqual(3); + expect(windows[0].innerWindow).toEqual(MockWindow.singleton); + done(); }); + }); - describe("getWindow", () => { - it("getWindowById returns wrapped window", (done) => { - container.getWindowById("Singleton").then(win => { - expect(win).toBeDefined(); - expect(win.id).toEqual("Singleton"); - done(); - }); + describe("getWindow", () => { + it("getWindowById returns wrapped window", (done) => { + container.getWindowById("Singleton").then(win => { + expect(win).toBeDefined(); + expect(win.id).toEqual("Singleton"); + done(); }); + }); - it ("getWindowById with unknown id returns null", (done) => { - container.getWindowById("DoesNotExist").then(win => { - expect(win).toBeNull(); - done(); - }); + it ("getWindowById with unknown id returns null", (done) => { + container.getWindowById("DoesNotExist").then(win => { + expect(win).toBeNull(); + done(); }); + }); - it("getWindowByName returns wrapped window", (done) => { - container.getWindowByName("Singleton").then(win => { - expect(win).toBeDefined(); - expect(win.id).toEqual("Singleton"); - done(); - }); + it("getWindowByName returns wrapped window", (done) => { + container.getWindowByName("Singleton").then(win => { + expect(win).toBeDefined(); + expect(win.id).toEqual("Singleton"); + done(); }); + }); - it ("getWindowByName with unknown name returns null", (done) => { - container.getWindowByName("DoesNotExist").then(win => { - expect(win).toBeNull(); - done(); - }); + it ("getWindowByName with unknown name returns null", (done) => { + container.getWindowByName("DoesNotExist").then(win => { + expect(win).toBeNull(); + done(); }); }); + }); - it("closeAllWindows invokes window.close", (done) => { - spyOn(MockWindow.singleton, "close").and.callThrough(); - (container).closeAllWindows().then(done).catch(error => { + it("closeAllWindows invokes window.close", (done) => { + spyOn(MockWindow.singleton, "close").and.callThrough(); + (container).closeAllWindows().then(done).catch(error => { + fail(error); + done(); + });; + expect(MockWindow.singleton.close).toHaveBeenCalled(); + }); + + it("saveLayout invokes underlying saveLayoutToStorage", (done) => { + spyOn(container, "saveLayoutToStorage").and.stub(); + container.saveLayout("Test") + .then(layout => { + expect(layout).toBeDefined(); + expect((container).saveLayoutToStorage).toHaveBeenCalledWith("Test", layout); + done(); + }).catch(error => { fail(error); done(); - });; - expect(MockWindow.singleton.close).toHaveBeenCalled(); - }); + }); + }); - it("saveLayout invokes underlying saveLayoutToStorage", (done) => { - spyOn(container, "saveLayoutToStorage").and.stub(); - container.saveLayout("Test") - .then(layout => { - expect(layout).toBeDefined(); - expect((container).saveLayoutToStorage).toHaveBeenCalledWith("Test", layout); - done(); - }).catch(error => { - fail(error); - done(); - }); - }); + it("buildLayout skips windows with persist false", (done) => { + container.buildLayout().then(layout => { + expect(layout).toBeDefined(); + expect(layout.windows.length).toEqual(2); + expect(layout.windows[0].name === "Singleton") + }).then(done); }); - }); + }); describe("notifications", () => { it("showNotification passes message and invokes underlying notification api", () => { diff --git a/packages/desktopjs/src/Default/default.ts b/packages/desktopjs/src/Default/default.ts index 4e1427d2..29b2e937 100644 --- a/packages/desktopjs/src/Default/default.ts +++ b/packages/desktopjs/src/Default/default.ts @@ -385,8 +385,14 @@ export namespace Default { this.getAllWindows().then(windows => { windows.forEach(window => { + const nativeWin = window.nativeWindow; + + const options = nativeWin[Container.windowOptionsPropertyKey]; + if (options && "persist" in options && !options.persist) { + return; + } + promises.push(new Promise(async (innerResolve) => { - const nativeWin = window.nativeWindow; if (this.globalWindow !== nativeWin) { layout.windows.push( { @@ -394,7 +400,7 @@ export namespace Default { url: nativeWin.location.toString(), id: window.id, bounds: { x: nativeWin.screenX, y: nativeWin.screenY, width: nativeWin.outerWidth, height: nativeWin.outerHeight }, - options: nativeWin[Container.windowOptionsPropertyKey], + options: options, state: await window.getState() } ); diff --git a/packages/desktopjs/tests/unit/Default/default.spec.ts b/packages/desktopjs/tests/unit/Default/default.spec.ts index 55b91f24..1299ba07 100644 --- a/packages/desktopjs/tests/unit/Default/default.spec.ts +++ b/packages/desktopjs/tests/unit/Default/default.spec.ts @@ -1,6 +1,7 @@ import {} from "jasmine"; import { Default } from "../../../src/Default/default"; import { ContainerWindow } from "../../../src/window"; +import { Container } from "../../../src/container"; class MockWindow { public listener: any; @@ -460,6 +461,24 @@ describe("DefaultContainer", () => { done(); }); }); + + it("buildLayout skips windows with persist false", (done) => { + window[Default.DefaultContainer.windowsPropertyKey] = { + "1": new MockWindow(), + "2": new MockWindow() + }; + + window[Default.DefaultContainer.windowsPropertyKey]["1"][Default.DefaultContainer.windowNamePropertyKey] = "win1"; + window[Default.DefaultContainer.windowsPropertyKey]["1"][Container.windowOptionsPropertyKey] = { persist: false }; + window[Default.DefaultContainer.windowsPropertyKey]["2"][Default.DefaultContainer.windowNamePropertyKey] = "win2"; + + let container: Default.DefaultContainer = new Default.DefaultContainer(window); + container.buildLayout().then(layout => { + expect(layout).toBeDefined(); + expect(layout.windows.length).toEqual(1); + expect(layout.windows[0].name).toEqual("win2"); + }).then(done); + }); }); });