nexfep 0.1.5 → 0.1.7

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/index.d.ts CHANGED
@@ -1,46 +1 @@
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 };
1
+ export * from './src/WindowManager.js';
package/index.js CHANGED
@@ -1,387 +1 @@
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 };
1
+ export * from './src/WindowManager.js';
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "webview",
15
15
  "typescript"
16
16
  ],
17
- "version": "0.1.5",
17
+ "version": "0.1.7",
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 };