@raydiant/playlist-window-manager 0.28.0 → 0.28.2-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,6 +4,7 @@ export default class IFrameRenderer implements PresentationWindowRenderer {
|
|
|
4
4
|
private windows;
|
|
5
5
|
constructor(container: HTMLElement);
|
|
6
6
|
createWindow({ windowId, bounds, backgroundColor, receiveMessageCallback, }: CreateWindowOptions): Promise<void>;
|
|
7
|
+
private loadWindowResolvers;
|
|
7
8
|
loadWindow(windowId: string, url: string): Promise<void>;
|
|
8
9
|
updateWindowBounds(windowId: string, bounds: WindowBounds): void;
|
|
9
10
|
showWindow(windowId: string, isFocused: boolean): void;
|
package/build/IFrameRenderer.js
CHANGED
|
@@ -42,6 +42,7 @@ var IFrameRenderer = /** @class */ (function () {
|
|
|
42
42
|
var _this = this;
|
|
43
43
|
this.container = container;
|
|
44
44
|
this.windows = {};
|
|
45
|
+
this.loadWindowResolvers = [];
|
|
45
46
|
this.globalMessageHandler = function (event) {
|
|
46
47
|
// Ignore messages that don't start with the message prefix.
|
|
47
48
|
if (typeof event.data === 'string' && event.data.startsWith(namespace)) {
|
|
@@ -106,18 +107,35 @@ var IFrameRenderer = /** @class */ (function () {
|
|
|
106
107
|
});
|
|
107
108
|
};
|
|
108
109
|
IFrameRenderer.prototype.loadWindow = function (windowId, url) {
|
|
110
|
+
var _this = this;
|
|
109
111
|
var window = this.getWindow(windowId);
|
|
110
112
|
if (!window) {
|
|
111
113
|
throw new Error("Failed to update window bounds, missing window id '".concat(windowId, "'"));
|
|
112
114
|
}
|
|
113
115
|
// Return a promise that resolves then the window has successfully loaded.
|
|
114
116
|
return new Promise(function (resolve, reject) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
_this.loadWindowResolvers.push([resolve, reject]);
|
|
118
|
+
// If we reassign onload, we may lost any pending promise called previously.
|
|
119
|
+
// Basically, if this function is called a first time, then it's called a
|
|
120
|
+
// second time without the first one completes load, the resolve callback
|
|
121
|
+
// will never be called, and the code that is awaiting for the promise will
|
|
122
|
+
// never be fulfilled.
|
|
123
|
+
if (!window.frame.onload) {
|
|
124
|
+
window.frame.onload = function () {
|
|
125
|
+
while (_this.loadWindowResolvers.length) {
|
|
126
|
+
var resolve_1 = (_this.loadWindowResolvers.shift() || [])[0];
|
|
127
|
+
resolve_1 === null || resolve_1 === void 0 ? void 0 : resolve_1();
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (!window.frame.onerror) {
|
|
132
|
+
window.frame.onerror = function () {
|
|
133
|
+
while (_this.loadWindowResolvers.length) {
|
|
134
|
+
var _a = _this.loadWindowResolvers.shift() || [], _ = _a[0], reject_1 = _a[1];
|
|
135
|
+
reject_1 === null || reject_1 === void 0 ? void 0 : reject_1(new Error("Error loading window for '".concat(url, "'")));
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
121
139
|
window.frame.src = url;
|
|
122
140
|
});
|
|
123
141
|
};
|
|
@@ -17,6 +17,7 @@ export interface PlaylistWindowManagerOptions {
|
|
|
17
17
|
parentWindowId?: string;
|
|
18
18
|
windowName?: string;
|
|
19
19
|
isPreview?: boolean;
|
|
20
|
+
closeWindowDelayMs?: number;
|
|
20
21
|
onEnableInterruptLock?: () => void;
|
|
21
22
|
onDisableInterruptLock?: () => void;
|
|
22
23
|
getTerminal?: () => Terminal | null;
|
|
@@ -74,6 +74,7 @@ var WindowLoadError_1 = __importDefault(require("./WindowLoadError"));
|
|
|
74
74
|
// Wait at least 3 seconds before restarting or moving onto the next window
|
|
75
75
|
// to prevent log spam causing devices to become unresponsive.
|
|
76
76
|
var minTimeBetweenCompletes = 3000;
|
|
77
|
+
var delay = function (ms) { return new Promise(function (res) { return setTimeout(res, ms); }); };
|
|
77
78
|
var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
78
79
|
__extends(PlaylistWindowManager, _super);
|
|
79
80
|
function PlaylistWindowManager(options) {
|
|
@@ -123,7 +124,7 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
123
124
|
_this.emitCurrentWindowEvent('window_charge_request', request);
|
|
124
125
|
};
|
|
125
126
|
_this.handleCurrentPresentationComplete = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
126
|
-
var logger, isThrottled, now, timeSinceLastComplete,
|
|
127
|
+
var logger, isThrottled, now, timeSinceLastComplete, delay_1, _a, next, preview, nextPreviewPresentationId;
|
|
127
128
|
var _this = this;
|
|
128
129
|
return __generator(this, function (_b) {
|
|
129
130
|
switch (_b.label) {
|
|
@@ -137,12 +138,12 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
137
138
|
isThrottled = true;
|
|
138
139
|
// Throttle presentation complete handler if we have not throttled already.
|
|
139
140
|
if (this.currentPresentationCompleteTimeout === null) {
|
|
140
|
-
|
|
141
|
-
logger.warn("Throttling presentation complete handler for ".concat(
|
|
141
|
+
delay_1 = minTimeBetweenCompletes - timeSinceLastComplete + 1;
|
|
142
|
+
logger.warn("Throttling presentation complete handler for ".concat(delay_1, "ms because it was called again in less than ").concat(minTimeBetweenCompletes, "ms"));
|
|
142
143
|
this.currentPresentationCompleteTimeout = setTimeout(function () {
|
|
143
144
|
_this.currentPresentationCompleteTimeout = null;
|
|
144
145
|
_this.handleCurrentPresentationComplete();
|
|
145
|
-
},
|
|
146
|
+
}, delay_1);
|
|
146
147
|
}
|
|
147
148
|
else {
|
|
148
149
|
logger.warn("Skipping presentation complete because it is currently throttled");
|
|
@@ -940,13 +941,19 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
|
|
|
940
941
|
if (this.nextWindow) {
|
|
941
942
|
this.nextWindow.show(this.isFocused);
|
|
942
943
|
}
|
|
943
|
-
if (!this.currentWindow) return [3 /*break*/,
|
|
944
|
-
this.
|
|
945
|
-
return [4 /*yield*/, this.
|
|
944
|
+
if (!this.currentWindow) return [3 /*break*/, 4];
|
|
945
|
+
if (!(this.options.closeWindowDelayMs !== undefined)) return [3 /*break*/, 2];
|
|
946
|
+
return [4 /*yield*/, delay(this.options.closeWindowDelayMs)];
|
|
946
947
|
case 1:
|
|
947
948
|
_a.sent();
|
|
948
949
|
_a.label = 2;
|
|
949
950
|
case 2:
|
|
951
|
+
this.currentWindow.hide();
|
|
952
|
+
return [4 /*yield*/, this.removeCurrentWindow()];
|
|
953
|
+
case 3:
|
|
954
|
+
_a.sent();
|
|
955
|
+
_a.label = 4;
|
|
956
|
+
case 4:
|
|
950
957
|
// Swap windows.
|
|
951
958
|
this.currentWindow = this.nextWindow;
|
|
952
959
|
if (this.currentWindow) {
|
package/package.json
CHANGED
package/src/IFrameRenderer.ts
CHANGED
|
@@ -69,6 +69,8 @@ export default class IFrameRenderer implements PresentationWindowRenderer {
|
|
|
69
69
|
this.container.appendChild(frame);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
private loadWindowResolvers: Array<[() => void, (err: Error) => void]> = [];
|
|
73
|
+
|
|
72
74
|
public loadWindow(windowId: string, url: string) {
|
|
73
75
|
const window = this.getWindow(windowId);
|
|
74
76
|
if (!window) {
|
|
@@ -79,13 +81,30 @@ export default class IFrameRenderer implements PresentationWindowRenderer {
|
|
|
79
81
|
|
|
80
82
|
// Return a promise that resolves then the window has successfully loaded.
|
|
81
83
|
return new Promise<void>((resolve, reject) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
this.loadWindowResolvers.push([resolve, reject]);
|
|
85
|
+
|
|
86
|
+
// If we reassign onload, we may lost any pending promise called previously.
|
|
87
|
+
// Basically, if this function is called a first time, then it's called a
|
|
88
|
+
// second time without the first one completes load, the resolve callback
|
|
89
|
+
// will never be called, and the code that is awaiting for the promise will
|
|
90
|
+
// never be fulfilled.
|
|
91
|
+
if (!window.frame.onload) {
|
|
92
|
+
window.frame.onload = () => {
|
|
93
|
+
while (this.loadWindowResolvers.length) {
|
|
94
|
+
const [resolve] = this.loadWindowResolvers.shift() || [];
|
|
95
|
+
resolve?.();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
85
99
|
|
|
86
|
-
window.frame.onerror
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
if (!window.frame.onerror) {
|
|
101
|
+
window.frame.onerror = () => {
|
|
102
|
+
while (this.loadWindowResolvers.length) {
|
|
103
|
+
const [_, reject] = this.loadWindowResolvers.shift() || [];
|
|
104
|
+
reject?.(new Error(`Error loading window for '${url}'`));
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
89
108
|
|
|
90
109
|
window.frame.src = url;
|
|
91
110
|
});
|
|
@@ -70,6 +70,8 @@ export interface PlaylistWindowManagerOptions {
|
|
|
70
70
|
// Set to true to render the presentation window as a preview.
|
|
71
71
|
isPreview?: boolean;
|
|
72
72
|
|
|
73
|
+
closeWindowDelayMs?: number;
|
|
74
|
+
|
|
73
75
|
// Called when the current window wants to enable the interrupt lock
|
|
74
76
|
onEnableInterruptLock?: () => void;
|
|
75
77
|
|
|
@@ -87,6 +89,8 @@ export interface PlaylistWindowManagerOptions {
|
|
|
87
89
|
// to prevent log spam causing devices to become unresponsive.
|
|
88
90
|
const minTimeBetweenCompletes = 3000;
|
|
89
91
|
|
|
92
|
+
const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
|
93
|
+
|
|
90
94
|
interface EvalRuleEngineResult {
|
|
91
95
|
next: RE.NextPresentationID;
|
|
92
96
|
preview: RE.NextPresentationID;
|
|
@@ -750,6 +754,9 @@ export default class PlaylistWindowManager extends EventEmitter {
|
|
|
750
754
|
// If current window isn't defined we don't need to hide it but we still
|
|
751
755
|
// want to make the next window the new current window.
|
|
752
756
|
if (this.currentWindow) {
|
|
757
|
+
if (this.options.closeWindowDelayMs !== undefined) {
|
|
758
|
+
await delay(this.options.closeWindowDelayMs);
|
|
759
|
+
}
|
|
753
760
|
this.currentWindow.hide();
|
|
754
761
|
await this.removeCurrentWindow();
|
|
755
762
|
}
|