nexfep 0.1.4 → 0.1.6
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.
- package/README-CN.md +62 -1
- package/README.md +62 -1
- package/index.d.ts +1 -46
- package/index.js +1 -357
- package/package.json +4 -2
- package/src/WindowManager.d.ts +46 -0
- package/src/WindowManager.js +387 -0
package/README-CN.md
CHANGED
|
@@ -117,13 +117,14 @@ pool.onCustomMessage = (window, data) => {
|
|
|
117
117
|
在页面中通过 `window.invoke` 触发事件:
|
|
118
118
|
|
|
119
119
|
```javascript
|
|
120
|
+
window.invoke('hello');
|
|
120
121
|
window.invoke('hello', 'world');
|
|
121
122
|
```
|
|
122
123
|
|
|
123
124
|
**参数说明**
|
|
124
125
|
|
|
125
126
|
- `event` — 事件名称
|
|
126
|
-
- `data
|
|
127
|
+
- `data`(可选)— 任意类型的可序列化数据,会被序列化为 JSON 字符串后发送
|
|
127
128
|
|
|
128
129
|
#### 监听事件
|
|
129
130
|
|
|
@@ -192,6 +193,59 @@ globals.set('hello', 'world');
|
|
|
192
193
|
const value = globals.get('hello');
|
|
193
194
|
```
|
|
194
195
|
|
|
196
|
+
### 窗口间通信
|
|
197
|
+
|
|
198
|
+
框架支持窗口之间通过 `window.broadcast` 和 `window.tell` 直接通信,无需经过主进程。
|
|
199
|
+
|
|
200
|
+
#### 广播
|
|
201
|
+
|
|
202
|
+
通过 `window.broadcast` 向所有其他打开的窗口发送事件:
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
window.broadcast('user-login', { userId: 123 });
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**参数说明**
|
|
209
|
+
|
|
210
|
+
- `name` — 事件名称
|
|
211
|
+
- `data`(可选)— 任意类型的可序列化数据,会被序列化为 JSON 字符串后发送
|
|
212
|
+
|
|
213
|
+
其他窗口通过 `window.addEventListener` 监听广播事件:
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
window.addEventListener('user-login', (event) => {
|
|
217
|
+
console.log('用户已登录:', event.detail);
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### 定向发送
|
|
222
|
+
|
|
223
|
+
通过 `window.tell` 向指定 ID 的窗口发送消息:
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
window.tell(2, 'custom-message', { text: '你好,窗口2' });
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**参数说明**
|
|
230
|
+
|
|
231
|
+
- `to` — 目标窗口 ID(数字类型)
|
|
232
|
+
- `message` — 事件名称
|
|
233
|
+
- `data`(可选)— 任意类型的可序列化数据,会被序列化为 JSON 字符串后发送
|
|
234
|
+
|
|
235
|
+
目标窗口通过 `window.addEventListener` 接收消息:
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
window.addEventListener('custom-message', (event) => {
|
|
239
|
+
console.log('收到消息:', event.detail);
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
每个窗口的 ID 可通过 `window.id` 获取:
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
console.log('当前窗口 ID:', window.id);
|
|
247
|
+
```
|
|
248
|
+
|
|
195
249
|
### 窗口控制函数
|
|
196
250
|
|
|
197
251
|
页面中可直接调用以下注入函数进行窗口控制:
|
|
@@ -207,6 +261,13 @@ window.openDevTools(); // 打开开发者工具
|
|
|
207
261
|
window.closeDevTools(); // 关闭开发者工具
|
|
208
262
|
```
|
|
209
263
|
|
|
264
|
+
页面中还可访问以下属性:
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
console.log(window.id); // 窗口唯一标识
|
|
268
|
+
console.log(window.isNexfepLoadDone); // 窗口是否已加载完成
|
|
269
|
+
```
|
|
270
|
+
|
|
210
271
|
### 拖拽区域
|
|
211
272
|
|
|
212
273
|
通过 HTML 属性即可定义窗口拖拽区域,无需编写额外 JavaScript 代码。这些属性会自动应用 `-webkit-app-region` 和 `app-region` CSS 属性。
|
package/README.md
CHANGED
|
@@ -117,13 +117,14 @@ pool.onCustomMessage = (window, data) => {
|
|
|
117
117
|
Invoke events via `window.invoke` in the page:
|
|
118
118
|
|
|
119
119
|
```javascript
|
|
120
|
+
window.invoke('hello');
|
|
120
121
|
window.invoke('hello', 'world');
|
|
121
122
|
```
|
|
122
123
|
|
|
123
124
|
**Parameters**
|
|
124
125
|
|
|
125
126
|
- `event` — Event name
|
|
126
|
-
- `data` — Any serializable data, will be serialized to JSON string before sending
|
|
127
|
+
- `data` (optional) — Any serializable data, will be serialized to JSON string before sending
|
|
127
128
|
|
|
128
129
|
#### Listen for Events
|
|
129
130
|
|
|
@@ -192,6 +193,59 @@ globals.set('hello', 'world');
|
|
|
192
193
|
const value = globals.get('hello');
|
|
193
194
|
```
|
|
194
195
|
|
|
196
|
+
### Inter-Window Communication
|
|
197
|
+
|
|
198
|
+
The framework supports direct communication between windows via `window.broadcast` and `window.tell`, without going through the main process.
|
|
199
|
+
|
|
200
|
+
#### Broadcast
|
|
201
|
+
|
|
202
|
+
Send an event to all other open windows via `window.broadcast`:
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
window.broadcast('user-login', { userId: 123 });
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Parameters**
|
|
209
|
+
|
|
210
|
+
- `name` — Event name
|
|
211
|
+
- `data` (optional) — Any serializable data, will be serialized to JSON string before sending
|
|
212
|
+
|
|
213
|
+
Other windows listen for the broadcast event via `window.addEventListener`:
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
window.addEventListener('user-login', (event) => {
|
|
217
|
+
console.log('User logged in:', event.detail);
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### Tell
|
|
222
|
+
|
|
223
|
+
Send a message to a specific window by its ID via `window.tell`:
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
window.tell(2, 'custom-message', { text: 'Hello Window 2' });
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Parameters**
|
|
230
|
+
|
|
231
|
+
- `to` — Target window ID (number)
|
|
232
|
+
- `message` — Event name
|
|
233
|
+
- `data` (optional) — Any serializable data, will be serialized to JSON string before sending
|
|
234
|
+
|
|
235
|
+
The target window receives the message via `window.addEventListener`:
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
window.addEventListener('custom-message', (event) => {
|
|
239
|
+
console.log('Received message:', event.detail);
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Each window's ID can be accessed via `window.id`:
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
console.log('This window ID:', window.id);
|
|
247
|
+
```
|
|
248
|
+
|
|
195
249
|
### Window Control Functions
|
|
196
250
|
|
|
197
251
|
The following injected functions can be directly called in the page for window control:
|
|
@@ -207,6 +261,13 @@ window.openDevTools(); // Open developer tools
|
|
|
207
261
|
window.closeDevTools(); // Close developer tools
|
|
208
262
|
```
|
|
209
263
|
|
|
264
|
+
The following properties are also available in the page:
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
console.log(window.id); // Window unique identifier
|
|
268
|
+
console.log(window.isNexfepLoadDone); // Whether the window has finished loading
|
|
269
|
+
```
|
|
270
|
+
|
|
210
271
|
### Drag Regions
|
|
211
272
|
|
|
212
273
|
Define window drag regions via HTML attributes without writing additional JavaScript code. These attributes automatically apply `-webkit-app-region` and `app-region` CSS properties.
|
package/index.d.ts
CHANGED
|
@@ -1,46 +1 @@
|
|
|
1
|
-
|
|
2
|
-
declare class Window {
|
|
3
|
-
window: BrowserWindow;
|
|
4
|
-
webview: Webview;
|
|
5
|
-
isOpen: boolean;
|
|
6
|
-
isShow: boolean;
|
|
7
|
-
isDecorated: boolean;
|
|
8
|
-
id: number;
|
|
9
|
-
private myPool;
|
|
10
|
-
constructor(window: BrowserWindow, webview: Webview, id: number, myPool: WindowPool);
|
|
11
|
-
setDecorated(isDecorated: boolean): void;
|
|
12
|
-
setTitle(title: string): void;
|
|
13
|
-
resizable(resizable: boolean): void;
|
|
14
|
-
maximize(): void;
|
|
15
|
-
minimize(): void;
|
|
16
|
-
unMaximize(): void;
|
|
17
|
-
unMinimize(): void;
|
|
18
|
-
openDevTools(): void;
|
|
19
|
-
closeDevTools(): void;
|
|
20
|
-
hide(): void;
|
|
21
|
-
show(): void;
|
|
22
|
-
close(): void;
|
|
23
|
-
loadURL(url: string): Promise<void>;
|
|
24
|
-
loadHTML(html: string): Promise<void>;
|
|
25
|
-
}
|
|
26
|
-
declare class WindowPool {
|
|
27
|
-
onCustomMessage: (window: Window, data: string) => void;
|
|
28
|
-
private app;
|
|
29
|
-
private windows;
|
|
30
|
-
private handlers;
|
|
31
|
-
private injectCount;
|
|
32
|
-
private windowCount;
|
|
33
|
-
private freeWindowCount;
|
|
34
|
-
global: Map<string, any>;
|
|
35
|
-
constructor(WindowsWebview2UserDataFolder?: string);
|
|
36
|
-
__injectCode(window: Window, code: string): Promise<void>;
|
|
37
|
-
__injectControlFunctions(windowObj: Window): Promise<void>;
|
|
38
|
-
__createNewWindowObj(): Promise<Window>;
|
|
39
|
-
createWindow(isShow?: boolean, isDecorated?: boolean): Promise<Window>;
|
|
40
|
-
closeWindow(window: Window): Promise<void>;
|
|
41
|
-
closePool(): Promise<void>;
|
|
42
|
-
handle(event: string, callback: (data: any) => any): Promise<void>;
|
|
43
|
-
unhandle(event: string, callback: (data: any) => any): Promise<void>;
|
|
44
|
-
mainloop(): void;
|
|
45
|
-
}
|
|
46
|
-
export { WindowPool, Window };
|
|
1
|
+
export * from './src/WindowManager';
|
package/index.js
CHANGED
|
@@ -1,357 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import fs from 'fs';
|
|
5
|
-
class Window {
|
|
6
|
-
window;
|
|
7
|
-
webview;
|
|
8
|
-
isOpen;
|
|
9
|
-
isShow;
|
|
10
|
-
isDecorated;
|
|
11
|
-
id;
|
|
12
|
-
myPool;
|
|
13
|
-
constructor(window, webview, id, myPool) {
|
|
14
|
-
this.myPool = myPool;
|
|
15
|
-
this.window = window;
|
|
16
|
-
this.webview = webview;
|
|
17
|
-
this.isOpen = false;
|
|
18
|
-
this.isShow = false;
|
|
19
|
-
this.isDecorated = false;
|
|
20
|
-
this.id = id;
|
|
21
|
-
}
|
|
22
|
-
setDecorated(isDecorated) {
|
|
23
|
-
this.window.setDecorations(isDecorated);
|
|
24
|
-
this.isDecorated = isDecorated;
|
|
25
|
-
}
|
|
26
|
-
setTitle(title) {
|
|
27
|
-
this.window.setTitle(title);
|
|
28
|
-
}
|
|
29
|
-
resizable(resizable) {
|
|
30
|
-
this.window.setResizable(resizable);
|
|
31
|
-
}
|
|
32
|
-
maximize() {
|
|
33
|
-
this.window.setMaximized(true);
|
|
34
|
-
}
|
|
35
|
-
minimize() {
|
|
36
|
-
this.window.setMinimized(true);
|
|
37
|
-
}
|
|
38
|
-
unMaximize() {
|
|
39
|
-
this.window.setMaximized(false);
|
|
40
|
-
}
|
|
41
|
-
unMinimize() {
|
|
42
|
-
this.window.setMinimized(false);
|
|
43
|
-
}
|
|
44
|
-
openDevTools() {
|
|
45
|
-
this.webview.openDevtools();
|
|
46
|
-
}
|
|
47
|
-
closeDevTools() {
|
|
48
|
-
this.webview.closeDevtools();
|
|
49
|
-
}
|
|
50
|
-
hide() {
|
|
51
|
-
this.window.hide();
|
|
52
|
-
this.isShow = false;
|
|
53
|
-
}
|
|
54
|
-
show() {
|
|
55
|
-
this.window.show();
|
|
56
|
-
this.isShow = true;
|
|
57
|
-
}
|
|
58
|
-
close() {
|
|
59
|
-
this.myPool.closeWindow(this);
|
|
60
|
-
}
|
|
61
|
-
async loadURL(url) {
|
|
62
|
-
await this.webview.loadUrl(url);
|
|
63
|
-
await this.myPool.__injectControlFunctions(this);
|
|
64
|
-
}
|
|
65
|
-
async loadHTML(html) {
|
|
66
|
-
await this.webview.loadHtml(html);
|
|
67
|
-
await this.myPool.__injectControlFunctions(this);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
class WindowPool {
|
|
71
|
-
onCustomMessage;
|
|
72
|
-
app;
|
|
73
|
-
windows;
|
|
74
|
-
handlers;
|
|
75
|
-
injectCount;
|
|
76
|
-
windowCount;
|
|
77
|
-
freeWindowCount;
|
|
78
|
-
global;
|
|
79
|
-
constructor(WindowsWebview2UserDataFolder = path.join(process.env.LOCALAPPDATA || os.homedir(), 'NexfepDevelopment.webview2-data')) {
|
|
80
|
-
if (os.platform() === 'win32') {
|
|
81
|
-
// 设置 WebView2 用户数据目录(仅 Windows 需要此配置)
|
|
82
|
-
const userDataDir = WindowsWebview2UserDataFolder;
|
|
83
|
-
if (!fs.existsSync(userDataDir)) {
|
|
84
|
-
fs.mkdirSync(userDataDir, { recursive: true });
|
|
85
|
-
}
|
|
86
|
-
process.env.WEBVIEW2_USER_DATA_FOLDER = userDataDir;
|
|
87
|
-
}
|
|
88
|
-
this.onCustomMessage = (window, data) => {
|
|
89
|
-
console.log('Get Custom Message:', data, "from window", window.id);
|
|
90
|
-
};
|
|
91
|
-
this.handlers = new Map();
|
|
92
|
-
this.app = new Application();
|
|
93
|
-
this.injectCount = 0;
|
|
94
|
-
this.windows = [];
|
|
95
|
-
this.windowCount = 0;
|
|
96
|
-
this.freeWindowCount = 0;
|
|
97
|
-
this.global = new Map();
|
|
98
|
-
}
|
|
99
|
-
async __injectCode(window, code) {
|
|
100
|
-
await window.webview.evaluateScript(code);
|
|
101
|
-
}
|
|
102
|
-
async __injectControlFunctions(windowObj) {
|
|
103
|
-
const INJECT_CSS = `
|
|
104
|
-
[nexfep-area-drag],
|
|
105
|
-
[nexfep-area-drag] * {
|
|
106
|
-
-webkit-app-region: drag;
|
|
107
|
-
app-region: drag;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
[nexfep-element-drag] {
|
|
111
|
-
-webkit-app-region: drag;
|
|
112
|
-
app-region: drag;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
[nexfep-no-drag],
|
|
116
|
-
[nexfep-no-drag] * {
|
|
117
|
-
-webkit-app-region: no-drag !important;
|
|
118
|
-
app-region: no-drag !important;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
[nexfep-auto-drag],
|
|
122
|
-
[nexfep-auto-drag] * {
|
|
123
|
-
-webkit-app-region: drag;
|
|
124
|
-
app-region: drag;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
[nexfep-auto-drag] button,
|
|
128
|
-
[nexfep-auto-drag] input,
|
|
129
|
-
[nexfep-auto-drag] select,
|
|
130
|
-
[nexfep-auto-drag] textarea,
|
|
131
|
-
[nexfep-auto-drag] a {
|
|
132
|
-
-webkit-app-region: no-drag;
|
|
133
|
-
app-region: no-drag;
|
|
134
|
-
}
|
|
135
|
-
`;
|
|
136
|
-
const INJECT_CODE = `
|
|
137
|
-
// 事件监听
|
|
138
|
-
window.addEventListener("beforeunload", () => {
|
|
139
|
-
const MessageBody = { type: 'NexfepBeforeUnload' }
|
|
140
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// 窗口控制函数
|
|
144
|
-
window.close = () => {
|
|
145
|
-
const MessageBody = { type: 'NexfepCloseWindow' }
|
|
146
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
window.minimize = () => {
|
|
150
|
-
const MessageBody = { type: 'NexfepMinimizeWindow' }
|
|
151
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
window.unminimize = () => {
|
|
155
|
-
const MessageBody = { type: 'NexfepUnMinimizeWindow' }
|
|
156
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
window.maximize = () => {
|
|
160
|
-
const MessageBody = { type: 'NexfepMaximizeWindow' }
|
|
161
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
window.unmaximize = () => {
|
|
165
|
-
const MessageBody = { type: 'NexfepUnMaximizeWindow' }
|
|
166
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
167
|
-
};
|
|
168
|
-
window.setTitle = (title) => {
|
|
169
|
-
const MessageBody = { type: 'NexfepSetTitle', title: title }
|
|
170
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
window.openDevTools = () => {
|
|
174
|
-
const MessageBody = { type: 'NexfepOpenDevTools' }
|
|
175
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
window.closeDevTools = () => {
|
|
179
|
-
const MessageBody = { type: 'NexfepCloseDevTools' }
|
|
180
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
window.postMessage = (data) => {
|
|
184
|
-
const MessageBody = { type: 'CustomMessage', data: data }
|
|
185
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
window.eventCount = 0;
|
|
189
|
-
|
|
190
|
-
window.invoke = async (event, data) => {
|
|
191
|
-
const MessageBody = { type: 'NexfepInvoke', eventId: [${this.injectCount}, ++window.eventCount], event: event, data: data }
|
|
192
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
193
|
-
return new Promise((resolve, reject) => {
|
|
194
|
-
window.addEventListener("nexfep-invoke-result-"+${this.injectCount}+"-"+window.eventCount, (event) => {
|
|
195
|
-
window.removeEventListener("nexfep-invoke-result-"+${this.injectCount}+"-"+window.eventCount, event);
|
|
196
|
-
if(event.detail){
|
|
197
|
-
resolve(event.detail);
|
|
198
|
-
}else{
|
|
199
|
-
resolve();
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
window.setGlobal = (name, value) => {
|
|
206
|
-
const MessageBody = { type: 'NexfepSetGlobal', name: name, value: value }
|
|
207
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
window.getGlobal = (name) => {
|
|
211
|
-
const MessageBody = { type: 'NexfepGetGlobal', eventId: [${this.injectCount}, ++window.eventCount], name: name }
|
|
212
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
213
|
-
return new Promise((resolve, reject) => {
|
|
214
|
-
window.addEventListener("nexfep-get-global-result-"+${this.injectCount}+"-"+window.eventCount, (event) => {
|
|
215
|
-
window.removeEventListener("nexfep-get-global-result-"+${this.injectCount}+"-"+window.eventCount, event);
|
|
216
|
-
if(event.detail){
|
|
217
|
-
resolve(event.detail);
|
|
218
|
-
}else{
|
|
219
|
-
resolve();
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// 注入 CSS 样式
|
|
226
|
-
const style = document.createElement('style');
|
|
227
|
-
style.textContent = \`${INJECT_CSS}\`;
|
|
228
|
-
document.head.appendChild(style);
|
|
229
|
-
|
|
230
|
-
// 标记加载完成
|
|
231
|
-
window.isNexfepLoadDone = true;
|
|
232
|
-
|
|
233
|
-
// 触发加载完成事件
|
|
234
|
-
window.dispatchEvent(new Event('nexfep-load-done'));
|
|
235
|
-
`;
|
|
236
|
-
await this.__injectCode(windowObj, INJECT_CODE);
|
|
237
|
-
}
|
|
238
|
-
async __createNewWindowObj() {
|
|
239
|
-
const window = this.app.createBrowserWindow({ title: "Nexfep" });
|
|
240
|
-
window.hide();
|
|
241
|
-
this.freeWindowCount++;
|
|
242
|
-
const webview = window.createWebview();
|
|
243
|
-
const windowObj = new Window(window, webview, ++this.windowCount, this);
|
|
244
|
-
this.windows.push(windowObj);
|
|
245
|
-
webview.onIpcMessage((data) => {
|
|
246
|
-
const dataText = data.body.toString();
|
|
247
|
-
const dataObj = JSON.parse(dataText);
|
|
248
|
-
if (dataObj.type == 'NexfepBeforeUnload') {
|
|
249
|
-
webview.evaluateScript(`if(window?.isNexfepLoadDone){
|
|
250
|
-
const MessageBody = { type: 'NexfepBeforeUnload' }
|
|
251
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
252
|
-
}else{
|
|
253
|
-
const MessageBody = { type: 'NexfepLoadFalse' }
|
|
254
|
-
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
255
|
-
}`);
|
|
256
|
-
}
|
|
257
|
-
else if (dataObj.type == 'NexfepLoadFalse') {
|
|
258
|
-
this.__injectControlFunctions(windowObj);
|
|
259
|
-
}
|
|
260
|
-
else if (dataObj.type == 'NexfepCloseWindow') {
|
|
261
|
-
this.closeWindow(windowObj);
|
|
262
|
-
}
|
|
263
|
-
else if (dataObj.type == 'NexfepMinimizeWindow') {
|
|
264
|
-
window.setMinimized(true);
|
|
265
|
-
}
|
|
266
|
-
else if (dataObj.type == 'NexfepUnMinimizeWindow') {
|
|
267
|
-
window.setMinimized(false);
|
|
268
|
-
}
|
|
269
|
-
else if (dataObj.type == 'NexfepMaximizeWindow') {
|
|
270
|
-
window.setMaximized(true);
|
|
271
|
-
}
|
|
272
|
-
else if (dataObj.type == 'NexfepUnMaximizeWindow') {
|
|
273
|
-
window.setMaximized(false);
|
|
274
|
-
}
|
|
275
|
-
else if (dataObj.type == 'NexfepSetTitle') {
|
|
276
|
-
window.setTitle(dataObj.title);
|
|
277
|
-
}
|
|
278
|
-
else if (dataObj.type == 'NexfepOpenDevTools') {
|
|
279
|
-
webview.openDevtools();
|
|
280
|
-
}
|
|
281
|
-
else if (dataObj.type == 'NexfepCloseDevTools') {
|
|
282
|
-
webview.closeDevtools();
|
|
283
|
-
}
|
|
284
|
-
else if (dataObj.type == 'CustomMessage') {
|
|
285
|
-
this.onCustomMessage(windowObj, dataObj.data);
|
|
286
|
-
}
|
|
287
|
-
else if (dataObj.type == 'NexfepInvoke') {
|
|
288
|
-
const handlers = this.handlers.get(dataObj.event) || [];
|
|
289
|
-
handlers.forEach(async (handler) => {
|
|
290
|
-
const result = await handler(dataObj.data);
|
|
291
|
-
if (result) {
|
|
292
|
-
webview.evaluateScript(`
|
|
293
|
-
window.dispatchEvent(new Event('nexfep-invoke-result-${dataObj.eventId[0]}-${dataObj.eventId[1]}', { detail: ${JSON.stringify(result)} }));
|
|
294
|
-
`);
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
webview.evaluateScript(`
|
|
298
|
-
window.dispatchEvent(new Event('nexfep-invoke-result-${dataObj.eventId[0]}-${dataObj.eventId[1]}', { detail: undefined }));
|
|
299
|
-
`);
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
else if (dataObj.type == 'NexfepSetGlobal') {
|
|
304
|
-
this.global.set(dataObj.name, dataObj.value);
|
|
305
|
-
}
|
|
306
|
-
else if (dataObj.type == 'NexfepGetGlobal') {
|
|
307
|
-
const value = this.global.get(dataObj.name);
|
|
308
|
-
webview.evaluateScript(`
|
|
309
|
-
window.dispatchEvent(new Event('nexfep-get-global-result-${dataObj.eventId[0]}-${dataObj.eventId[1]}', { detail: ${JSON.stringify(value)} }));
|
|
310
|
-
`);
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
return windowObj;
|
|
314
|
-
}
|
|
315
|
-
async createWindow(isShow = true, isDecorated = true) {
|
|
316
|
-
const window = this.windows.find(w => w.isOpen === false) || await this.__createNewWindowObj();
|
|
317
|
-
this.freeWindowCount--;
|
|
318
|
-
if (window) {
|
|
319
|
-
window.isOpen = true;
|
|
320
|
-
window.isShow = isShow;
|
|
321
|
-
window.setDecorated(isDecorated);
|
|
322
|
-
if (isShow) {
|
|
323
|
-
window.show();
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
if (this.freeWindowCount == 0) {
|
|
327
|
-
await this.__createNewWindowObj();
|
|
328
|
-
}
|
|
329
|
-
return window;
|
|
330
|
-
}
|
|
331
|
-
async closeWindow(window) {
|
|
332
|
-
if (window.isOpen) {
|
|
333
|
-
window.isOpen = false;
|
|
334
|
-
window.isShow = false;
|
|
335
|
-
window.setDecorated(true);
|
|
336
|
-
window.hide();
|
|
337
|
-
await window.loadHTML("<!DOCTYPE html><html><head></head><body></body></html>");
|
|
338
|
-
this.freeWindowCount++;
|
|
339
|
-
}
|
|
340
|
-
else {
|
|
341
|
-
throw new Error("Window is not open");
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
async closePool() {
|
|
345
|
-
this.app.exit();
|
|
346
|
-
}
|
|
347
|
-
async handle(event, callback) {
|
|
348
|
-
this.handlers.set(event, [...this.handlers.get(event) || [], callback]);
|
|
349
|
-
}
|
|
350
|
-
async unhandle(event, callback) {
|
|
351
|
-
this.handlers.set(event, (this.handlers.get(event) || []).filter(c => c !== callback));
|
|
352
|
-
}
|
|
353
|
-
mainloop() {
|
|
354
|
-
this.app.run();
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
export { WindowPool, Window };
|
|
1
|
+
export * from './src/WindowManager';
|
package/package.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"webview",
|
|
15
15
|
"typescript"
|
|
16
16
|
],
|
|
17
|
-
"version": "0.1.
|
|
17
|
+
"version": "0.1.6",
|
|
18
18
|
"type": "module",
|
|
19
19
|
"main": "./index.js",
|
|
20
20
|
"scripts": {
|
|
@@ -31,7 +31,9 @@
|
|
|
31
31
|
"README.md",
|
|
32
32
|
"README-CN.md",
|
|
33
33
|
"LICENSE",
|
|
34
|
-
"package.json"
|
|
34
|
+
"package.json",
|
|
35
|
+
"src/WindowManager.js",
|
|
36
|
+
"src/WindowManager.d.ts"
|
|
35
37
|
],
|
|
36
38
|
"dependencies": {
|
|
37
39
|
"@webviewjs/webview": "0.1.4"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { BrowserWindow, Webview } from "@webviewjs/webview";
|
|
2
|
+
declare class Window {
|
|
3
|
+
window: BrowserWindow;
|
|
4
|
+
webview: Webview;
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
isShow: boolean;
|
|
7
|
+
isDecorated: boolean;
|
|
8
|
+
id: number;
|
|
9
|
+
private myPool;
|
|
10
|
+
constructor(window: BrowserWindow, webview: Webview, id: number, myPool: WindowPool);
|
|
11
|
+
setDecorated(isDecorated: boolean): void;
|
|
12
|
+
setTitle(title: string): void;
|
|
13
|
+
resizable(resizable: boolean): void;
|
|
14
|
+
maximize(): void;
|
|
15
|
+
minimize(): void;
|
|
16
|
+
unMaximize(): void;
|
|
17
|
+
unMinimize(): void;
|
|
18
|
+
openDevTools(): void;
|
|
19
|
+
closeDevTools(): void;
|
|
20
|
+
hide(): void;
|
|
21
|
+
show(): void;
|
|
22
|
+
close(): void;
|
|
23
|
+
loadURL(url: string): Promise<void>;
|
|
24
|
+
loadHTML(html: string): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
declare class WindowPool {
|
|
27
|
+
onCustomMessage: (window: Window, data: string) => void;
|
|
28
|
+
private app;
|
|
29
|
+
private windows;
|
|
30
|
+
private handlers;
|
|
31
|
+
private injectCount;
|
|
32
|
+
private windowCount;
|
|
33
|
+
private freeWindowCount;
|
|
34
|
+
global: Map<string, any>;
|
|
35
|
+
constructor(WindowsWebview2UserDataFolder?: string);
|
|
36
|
+
__injectCode(window: Window, code: string): Promise<void>;
|
|
37
|
+
__injectControlFunctions(windowObj: Window): Promise<void>;
|
|
38
|
+
__createNewWindowObj(): Promise<Window>;
|
|
39
|
+
createWindow(isShow?: boolean, isDecorated?: boolean): Promise<Window>;
|
|
40
|
+
closeWindow(window: Window): Promise<void>;
|
|
41
|
+
closePool(): Promise<void>;
|
|
42
|
+
handle(event: string, callback: (data: any) => any): Promise<void>;
|
|
43
|
+
unhandle(event: string, callback: (data: any) => any): Promise<void>;
|
|
44
|
+
mainloop(): void;
|
|
45
|
+
}
|
|
46
|
+
export { WindowPool, Window };
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { Application } from "@webviewjs/webview";
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
class Window {
|
|
6
|
+
window;
|
|
7
|
+
webview;
|
|
8
|
+
isOpen;
|
|
9
|
+
isShow;
|
|
10
|
+
isDecorated;
|
|
11
|
+
id;
|
|
12
|
+
myPool;
|
|
13
|
+
constructor(window, webview, id, myPool) {
|
|
14
|
+
this.myPool = myPool;
|
|
15
|
+
this.window = window;
|
|
16
|
+
this.webview = webview;
|
|
17
|
+
this.isOpen = false;
|
|
18
|
+
this.isShow = false;
|
|
19
|
+
this.isDecorated = false;
|
|
20
|
+
this.id = id;
|
|
21
|
+
}
|
|
22
|
+
setDecorated(isDecorated) {
|
|
23
|
+
this.window.setDecorations(isDecorated);
|
|
24
|
+
this.isDecorated = isDecorated;
|
|
25
|
+
}
|
|
26
|
+
setTitle(title) {
|
|
27
|
+
this.window.setTitle(title);
|
|
28
|
+
}
|
|
29
|
+
resizable(resizable) {
|
|
30
|
+
this.window.setResizable(resizable);
|
|
31
|
+
}
|
|
32
|
+
maximize() {
|
|
33
|
+
this.window.setMaximized(true);
|
|
34
|
+
}
|
|
35
|
+
minimize() {
|
|
36
|
+
this.window.setMinimized(true);
|
|
37
|
+
}
|
|
38
|
+
unMaximize() {
|
|
39
|
+
this.window.setMaximized(false);
|
|
40
|
+
}
|
|
41
|
+
unMinimize() {
|
|
42
|
+
this.window.setMinimized(false);
|
|
43
|
+
}
|
|
44
|
+
openDevTools() {
|
|
45
|
+
this.webview.openDevtools();
|
|
46
|
+
}
|
|
47
|
+
closeDevTools() {
|
|
48
|
+
this.webview.closeDevtools();
|
|
49
|
+
}
|
|
50
|
+
hide() {
|
|
51
|
+
this.window.hide();
|
|
52
|
+
this.isShow = false;
|
|
53
|
+
}
|
|
54
|
+
show() {
|
|
55
|
+
this.window.show();
|
|
56
|
+
this.isShow = true;
|
|
57
|
+
}
|
|
58
|
+
close() {
|
|
59
|
+
this.myPool.closeWindow(this);
|
|
60
|
+
}
|
|
61
|
+
async loadURL(url) {
|
|
62
|
+
await this.webview.loadUrl(url);
|
|
63
|
+
await this.myPool.__injectControlFunctions(this);
|
|
64
|
+
}
|
|
65
|
+
async loadHTML(html) {
|
|
66
|
+
await this.webview.loadHtml(html);
|
|
67
|
+
await this.myPool.__injectControlFunctions(this);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
class WindowPool {
|
|
71
|
+
onCustomMessage;
|
|
72
|
+
app;
|
|
73
|
+
windows;
|
|
74
|
+
handlers;
|
|
75
|
+
injectCount;
|
|
76
|
+
windowCount;
|
|
77
|
+
freeWindowCount;
|
|
78
|
+
global;
|
|
79
|
+
constructor(WindowsWebview2UserDataFolder = path.join(process.env.LOCALAPPDATA || os.homedir(), 'NexfepDevelopment.webview2-data')) {
|
|
80
|
+
if (os.platform() === 'win32') {
|
|
81
|
+
// 设置 WebView2 用户数据目录(仅 Windows 需要此配置)
|
|
82
|
+
const userDataDir = WindowsWebview2UserDataFolder;
|
|
83
|
+
if (!fs.existsSync(userDataDir)) {
|
|
84
|
+
fs.mkdirSync(userDataDir, { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
process.env.WEBVIEW2_USER_DATA_FOLDER = userDataDir;
|
|
87
|
+
}
|
|
88
|
+
this.onCustomMessage = (window, data) => {
|
|
89
|
+
console.log('Get Custom Message:', data, "from window", window.id);
|
|
90
|
+
};
|
|
91
|
+
this.handlers = new Map();
|
|
92
|
+
this.app = new Application();
|
|
93
|
+
this.injectCount = 0;
|
|
94
|
+
this.windows = [];
|
|
95
|
+
this.windowCount = 0;
|
|
96
|
+
this.freeWindowCount = 0;
|
|
97
|
+
this.global = new Map();
|
|
98
|
+
}
|
|
99
|
+
async __injectCode(window, code) {
|
|
100
|
+
await window.webview.evaluateScript(code);
|
|
101
|
+
}
|
|
102
|
+
async __injectControlFunctions(windowObj) {
|
|
103
|
+
const INJECT_CSS = `
|
|
104
|
+
[nexfep-area-drag],
|
|
105
|
+
[nexfep-area-drag] * {
|
|
106
|
+
-webkit-app-region: drag;
|
|
107
|
+
app-region: drag;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
[nexfep-element-drag] {
|
|
111
|
+
-webkit-app-region: drag;
|
|
112
|
+
app-region: drag;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
[nexfep-no-drag],
|
|
116
|
+
[nexfep-no-drag] * {
|
|
117
|
+
-webkit-app-region: no-drag !important;
|
|
118
|
+
app-region: no-drag !important;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
[nexfep-auto-drag],
|
|
122
|
+
[nexfep-auto-drag] * {
|
|
123
|
+
-webkit-app-region: drag;
|
|
124
|
+
app-region: drag;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[nexfep-auto-drag] button,
|
|
128
|
+
[nexfep-auto-drag] input,
|
|
129
|
+
[nexfep-auto-drag] select,
|
|
130
|
+
[nexfep-auto-drag] textarea,
|
|
131
|
+
[nexfep-auto-drag] a {
|
|
132
|
+
-webkit-app-region: no-drag;
|
|
133
|
+
app-region: no-drag;
|
|
134
|
+
}
|
|
135
|
+
`;
|
|
136
|
+
const INJECT_CODE = `
|
|
137
|
+
// 事件监听
|
|
138
|
+
window.addEventListener("beforeunload", () => {
|
|
139
|
+
const MessageBody = { type: 'NexfepBeforeUnload' }
|
|
140
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// 窗口控制函数
|
|
144
|
+
window.close = () => {
|
|
145
|
+
const MessageBody = { type: 'NexfepCloseWindow' }
|
|
146
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
window.minimize = () => {
|
|
150
|
+
const MessageBody = { type: 'NexfepMinimizeWindow' }
|
|
151
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
window.unminimize = () => {
|
|
155
|
+
const MessageBody = { type: 'NexfepUnMinimizeWindow' }
|
|
156
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
window.maximize = () => {
|
|
160
|
+
const MessageBody = { type: 'NexfepMaximizeWindow' }
|
|
161
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
window.unmaximize = () => {
|
|
165
|
+
const MessageBody = { type: 'NexfepUnMaximizeWindow' }
|
|
166
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
167
|
+
};
|
|
168
|
+
window.setTitle = (title) => {
|
|
169
|
+
const MessageBody = { type: 'NexfepSetTitle', title: title }
|
|
170
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
window.openDevTools = () => {
|
|
174
|
+
const MessageBody = { type: 'NexfepOpenDevTools' }
|
|
175
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
window.closeDevTools = () => {
|
|
179
|
+
const MessageBody = { type: 'NexfepCloseDevTools' }
|
|
180
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
window.postMessage = (data) => {
|
|
184
|
+
const MessageBody = { type: 'CustomMessage', data: data }
|
|
185
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
window.eventCount = 0;
|
|
189
|
+
|
|
190
|
+
window.invoke = async (event, data = null) => {
|
|
191
|
+
const MessageBody = { type: 'NexfepInvoke', eventId: [${this.injectCount}, ++window.eventCount], event: event, data: data }
|
|
192
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
193
|
+
return new Promise((resolve, reject) => {
|
|
194
|
+
window.addEventListener("nexfep-invoke-result-"+${this.injectCount}+"-"+window.eventCount, (event) => {
|
|
195
|
+
window.removeEventListener("nexfep-invoke-result-"+${this.injectCount}+"-"+window.eventCount, event);
|
|
196
|
+
if(event.detail){
|
|
197
|
+
resolve(event.detail);
|
|
198
|
+
}else{
|
|
199
|
+
resolve();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
window.setGlobal = (name, value) => {
|
|
206
|
+
const MessageBody = { type: 'NexfepSetGlobal', name: name, value: value }
|
|
207
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
window.getGlobal = (name) => {
|
|
211
|
+
const MessageBody = { type: 'NexfepGetGlobal', eventId: [${this.injectCount}, ++window.eventCount], name: name }
|
|
212
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
213
|
+
return new Promise((resolve, reject) => {
|
|
214
|
+
window.addEventListener("nexfep-get-global-result-"+${this.injectCount}+"-"+window.eventCount, (event) => {
|
|
215
|
+
window.removeEventListener("nexfep-get-global-result-"+${this.injectCount}+"-"+window.eventCount, event);
|
|
216
|
+
if(event.detail){
|
|
217
|
+
resolve(event.detail);
|
|
218
|
+
}else{
|
|
219
|
+
resolve();
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
window.broadcast = (name, data = null) => {
|
|
226
|
+
const MessageBody = { type: 'NexfepBroadcast', name: name, data: data }
|
|
227
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
window.id = ${windowObj.id};
|
|
231
|
+
|
|
232
|
+
window.tell = (to, message, data = null) => {
|
|
233
|
+
const MessageBody = { type: 'NexfepTell', to: to, message: message, data: data }
|
|
234
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 注入 CSS 样式
|
|
238
|
+
const style = document.createElement('style');
|
|
239
|
+
style.textContent = \`${INJECT_CSS}\`;
|
|
240
|
+
document.head.appendChild(style);
|
|
241
|
+
|
|
242
|
+
// 标记加载完成
|
|
243
|
+
window.isNexfepLoadDone = true;
|
|
244
|
+
|
|
245
|
+
// 触发加载完成事件
|
|
246
|
+
window.dispatchEvent(new CustomEvent('nexfep-load-done'));
|
|
247
|
+
`;
|
|
248
|
+
await this.__injectCode(windowObj, INJECT_CODE);
|
|
249
|
+
}
|
|
250
|
+
async __createNewWindowObj() {
|
|
251
|
+
const window = this.app.createBrowserWindow({ title: "Nexfep" });
|
|
252
|
+
window.hide();
|
|
253
|
+
this.freeWindowCount++;
|
|
254
|
+
const webview = window.createWebview();
|
|
255
|
+
const windowObj = new Window(window, webview, ++this.windowCount, this);
|
|
256
|
+
this.windows.push(windowObj);
|
|
257
|
+
webview.onIpcMessage((data) => {
|
|
258
|
+
const dataText = data.body.toString();
|
|
259
|
+
const dataObj = JSON.parse(dataText);
|
|
260
|
+
if (dataObj.type == 'NexfepBeforeUnload') {
|
|
261
|
+
webview.evaluateScript(`if(window?.isNexfepLoadDone){
|
|
262
|
+
const MessageBody = { type: 'NexfepBeforeUnload' }
|
|
263
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
264
|
+
}else{
|
|
265
|
+
const MessageBody = { type: 'NexfepLoadFalse' }
|
|
266
|
+
window.ipc.postMessage(JSON.stringify(MessageBody));
|
|
267
|
+
}`);
|
|
268
|
+
}
|
|
269
|
+
else if (dataObj.type == 'NexfepLoadFalse') {
|
|
270
|
+
this.__injectControlFunctions(windowObj);
|
|
271
|
+
}
|
|
272
|
+
else if (dataObj.type == 'NexfepCloseWindow') {
|
|
273
|
+
this.closeWindow(windowObj);
|
|
274
|
+
}
|
|
275
|
+
else if (dataObj.type == 'NexfepMinimizeWindow') {
|
|
276
|
+
window.setMinimized(true);
|
|
277
|
+
}
|
|
278
|
+
else if (dataObj.type == 'NexfepUnMinimizeWindow') {
|
|
279
|
+
window.setMinimized(false);
|
|
280
|
+
}
|
|
281
|
+
else if (dataObj.type == 'NexfepMaximizeWindow') {
|
|
282
|
+
window.setMaximized(true);
|
|
283
|
+
}
|
|
284
|
+
else if (dataObj.type == 'NexfepUnMaximizeWindow') {
|
|
285
|
+
window.setMaximized(false);
|
|
286
|
+
}
|
|
287
|
+
else if (dataObj.type == 'NexfepSetTitle') {
|
|
288
|
+
window.setTitle(dataObj.title);
|
|
289
|
+
}
|
|
290
|
+
else if (dataObj.type == 'NexfepOpenDevTools') {
|
|
291
|
+
webview.openDevtools();
|
|
292
|
+
}
|
|
293
|
+
else if (dataObj.type == 'NexfepCloseDevTools') {
|
|
294
|
+
webview.closeDevtools();
|
|
295
|
+
}
|
|
296
|
+
else if (dataObj.type == 'CustomMessage') {
|
|
297
|
+
this.onCustomMessage(windowObj, dataObj.data);
|
|
298
|
+
}
|
|
299
|
+
else if (dataObj.type == 'NexfepInvoke') {
|
|
300
|
+
const handlers = this.handlers.get(dataObj.event) || [];
|
|
301
|
+
handlers.forEach(async (handler) => {
|
|
302
|
+
const result = await handler(dataObj.data);
|
|
303
|
+
if (result) {
|
|
304
|
+
webview.evaluateScript(`
|
|
305
|
+
window.dispatchEvent(new CustomEvent('nexfep-invoke-result-${dataObj.eventId[0]}-${dataObj.eventId[1]}', { detail: ${JSON.stringify(result)} }));
|
|
306
|
+
`);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
webview.evaluateScript(`
|
|
310
|
+
window.dispatchEvent(new CustomEvent('nexfep-invoke-result-${dataObj.eventId[0]}-${dataObj.eventId[1]}', { detail: undefined }));
|
|
311
|
+
`);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
else if (dataObj.type == 'NexfepSetGlobal') {
|
|
316
|
+
this.global.set(dataObj.name, dataObj.value);
|
|
317
|
+
}
|
|
318
|
+
else if (dataObj.type == 'NexfepGetGlobal') {
|
|
319
|
+
const value = this.global.get(dataObj.name);
|
|
320
|
+
webview.evaluateScript(`
|
|
321
|
+
window.dispatchEvent(new CustomEvent('nexfep-get-global-result-${dataObj.eventId[0]}-${dataObj.eventId[1]}', { detail: ${JSON.stringify(value)} }));
|
|
322
|
+
`);
|
|
323
|
+
}
|
|
324
|
+
else if (dataObj.type == 'NexfepBroadcast') {
|
|
325
|
+
this.windows.forEach(async (w) => {
|
|
326
|
+
if (w != windowObj && w.isOpen) {
|
|
327
|
+
w.webview.evaluateScript(`
|
|
328
|
+
window.dispatchEvent(new CustomEvent('${dataObj.name}', { detail: ${JSON.stringify(dataObj.data)} }));
|
|
329
|
+
`);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
else if (dataObj.type == 'NexfepTell') {
|
|
334
|
+
this.windows.forEach(async (w) => {
|
|
335
|
+
if (w.id == dataObj.to) {
|
|
336
|
+
w.webview.evaluateScript(`
|
|
337
|
+
window.dispatchEvent(new CustomEvent('${dataObj.message}', { detail: ${JSON.stringify(dataObj.data)} }));
|
|
338
|
+
`);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
return windowObj;
|
|
344
|
+
}
|
|
345
|
+
async createWindow(isShow = true, isDecorated = true) {
|
|
346
|
+
const window = this.windows.find(w => w.isOpen === false) || await this.__createNewWindowObj();
|
|
347
|
+
this.freeWindowCount--;
|
|
348
|
+
if (window) {
|
|
349
|
+
window.isOpen = true;
|
|
350
|
+
window.isShow = isShow;
|
|
351
|
+
window.setDecorated(isDecorated);
|
|
352
|
+
if (isShow) {
|
|
353
|
+
window.show();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (this.freeWindowCount == 0) {
|
|
357
|
+
await this.__createNewWindowObj();
|
|
358
|
+
}
|
|
359
|
+
return window;
|
|
360
|
+
}
|
|
361
|
+
async closeWindow(window) {
|
|
362
|
+
if (window.isOpen) {
|
|
363
|
+
window.isOpen = false;
|
|
364
|
+
window.isShow = false;
|
|
365
|
+
window.setDecorated(true);
|
|
366
|
+
window.hide();
|
|
367
|
+
await window.loadHTML("<!DOCTYPE html><html><head></head><body></body></html>");
|
|
368
|
+
this.freeWindowCount++;
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
throw new Error("Window is not open");
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
async closePool() {
|
|
375
|
+
this.app.exit();
|
|
376
|
+
}
|
|
377
|
+
async handle(event, callback) {
|
|
378
|
+
this.handlers.set(event, [...this.handlers.get(event) || [], callback]);
|
|
379
|
+
}
|
|
380
|
+
async unhandle(event, callback) {
|
|
381
|
+
this.handlers.set(event, (this.handlers.get(event) || []).filter(c => c !== callback));
|
|
382
|
+
}
|
|
383
|
+
mainloop() {
|
|
384
|
+
this.app.run();
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
export { WindowPool, Window };
|