Skip to content

Commit

Permalink
Add persist: false option to createWindow (#247)
Browse files Browse the repository at this point in the history
If createWindow options include persist: false, do not include the window in layout persistence.

Fixes #241
  • Loading branch information
bingenito authored May 30, 2019
1 parent 18e097c commit 579989d
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 70 deletions.
7 changes: 6 additions & 1 deletion packages/desktopjs-electron/src/electron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,11 @@ export class ElectronContainer extends WebContainerBase {
return new Promise<PersistedWindowLayout>((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<void>(innerResolve => {
window.getGroup().then(async group => {
layout.windows.push(
Expand All @@ -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)
});
Expand Down
22 changes: 22 additions & 0 deletions packages/desktopjs-electron/tests/electron.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});

Expand Down
34 changes: 20 additions & 14 deletions packages/desktopjs-openfin/src/openfin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -661,21 +661,27 @@ export class OpenFinContainer extends WebContainerBase {
const window = djsWindow.innerWindow;
window.getBounds(bounds => {
window.getOptions(options => {
delete (<any>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 (<any>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);
}));
Expand Down
116 changes: 63 additions & 53 deletions packages/desktopjs-openfin/tests/openfin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {};
}

Expand Down Expand Up @@ -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();
(<any>container).closeAllWindows().then(done).catch(error => {
it("closeAllWindows invokes window.close", (done) => {
spyOn(MockWindow.singleton, "close").and.callThrough();
(<any>container).closeAllWindows().then(done).catch(error => {
fail(error);
done();
});;
expect(MockWindow.singleton.close).toHaveBeenCalled();
});

it("saveLayout invokes underlying saveLayoutToStorage", (done) => {
spyOn<any>(container, "saveLayoutToStorage").and.stub();
container.saveLayout("Test")
.then(layout => {
expect(layout).toBeDefined();
expect((<any>container).saveLayoutToStorage).toHaveBeenCalledWith("Test", layout);
done();
}).catch(error => {
fail(error);
done();
});;
expect(MockWindow.singleton.close).toHaveBeenCalled();
});
});
});

it("saveLayout invokes underlying saveLayoutToStorage", (done) => {
spyOn<any>(container, "saveLayoutToStorage").and.stub();
container.saveLayout("Test")
.then(layout => {
expect(layout).toBeDefined();
expect((<any>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", () => {
Expand Down
10 changes: 8 additions & 2 deletions packages/desktopjs/src/Default/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,16 +385,22 @@ 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<void>(async (innerResolve) => {
const nativeWin = window.nativeWindow;
if (this.globalWindow !== nativeWin) {
layout.windows.push(
{
name: window.name,
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()
}
);
Expand Down
19 changes: 19 additions & 0 deletions packages/desktopjs/tests/unit/Default/default.spec.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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);
});
});
});

Expand Down

0 comments on commit 579989d

Please sign in to comment.