@lynker-desktop/electron-window-manager 0.0.4-alpha.9 → 0.0.5-alpha.1

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/main/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const _ = require('lodash');
1
+ const lodash = require('lodash');
2
2
  const electron = require('electron');
3
3
  const remote = require('@electron/remote/main');
4
4
  const eIpc = require('@lynker-desktop/electron-ipc/main');
@@ -16,6 +16,18 @@ function _interopNamespaceDefault(e) {
16
16
 
17
17
  const remote__namespace = /*#__PURE__*/_interopNamespaceDefault(remote);
18
18
 
19
+ const getCustomSession = (() => {
20
+ let customSession;
21
+ return () => {
22
+ if (!customSession) {
23
+ customSession = electron.session.fromPartition('persist:__global_main_session__');
24
+ }
25
+ return customSession;
26
+ };
27
+ })();
28
+ electron.app.on('ready', () => {
29
+ getCustomSession();
30
+ });
19
31
  if (!remote__namespace.isInitialized()) {
20
32
  remote__namespace.initialize();
21
33
  }
@@ -23,50 +35,162 @@ const enable = (win) => {
23
35
  remote__namespace.enable(win);
24
36
  };
25
37
  class WindowsManager {
26
- constructor(preload) {
38
+ constructor(preload, loadingViewUrl, errorViewUrl) {
27
39
  this.preload = preload;
28
40
  this.windows = new Map();
41
+ this.loadingViewUrl = `${loadingViewUrl ?? ''}`;
42
+ this.errorViewUrl = `${errorViewUrl ?? ''}`;
29
43
  }
30
44
  create(options) {
31
- const { name = 'anonymous', loadingView, browserWindow: browserWindowOptions = {}, openDevTools = false, preventOriginClose = false, } = options;
32
- const window = new electron.BrowserWindow(_.merge({
33
- acceptFirstMouse: true,
34
- }, browserWindowOptions, {
35
- webPreferences: {
36
- plugins: true,
37
- nodeIntegration: true,
38
- contextIsolation: false,
39
- backgroundThrottling: false,
40
- nativeWindowOpen: false,
41
- webSecurity: false,
42
- preload: browserWindowOptions?.webPreferences?.preload || this.preload,
43
- }
44
- }));
45
- remote__namespace.enable(window.webContents);
46
- window._name = name;
47
- if (loadingView?.url) {
48
- this._setLoadingView(window, options);
49
- }
50
- window.on('close', (event) => {
51
- if (preventOriginClose) {
52
- event.preventDefault();
53
- return;
45
+ let window;
46
+ try {
47
+ const { type = 'BW', name = 'anonymous', url, loadingView = { url: undefined }, errorView = { url: undefined }, browserWindow: browserWindowOptions, openDevTools = false, preventOriginClose = false, } = options;
48
+ options.type = type;
49
+ try {
50
+ loadingView.url = `${loadingView?.url ?? this.loadingViewUrl}`;
51
+ lodash.merge(options, {
52
+ loadingView,
53
+ });
54
54
  }
55
- this.windows.delete(window.id);
56
- });
57
- window.webContents.on('dom-ready', () => {
58
- if (openDevTools) {
59
- window.webContents.openDevTools();
55
+ catch (error) {
56
+ log('error', 'loadingView error:', loadingView, this.loadingViewUrl);
60
57
  }
61
- });
62
- this.windows.set(window.id, window);
63
- if (/^file/gi.test(options.url)) {
64
- window.loadFile(options.url);
58
+ try {
59
+ errorView.url = `${errorView?.url ?? this.errorViewUrl}`;
60
+ lodash.merge(options, {
61
+ errorView,
62
+ });
63
+ }
64
+ catch (error) {
65
+ log('error', 'errorView error:', errorView, this.errorViewUrl);
66
+ }
67
+ let parentWin = undefined;
68
+ if (typeof browserWindowOptions?.parent === 'number') {
69
+ parentWin = electron.BrowserWindow.fromId(browserWindowOptions?.parent) || undefined;
70
+ if (parentWin) {
71
+ browserWindowOptions.parent = parentWin;
72
+ }
73
+ else {
74
+ browserWindowOptions.parent = undefined;
75
+ }
76
+ }
77
+ log('log', 'create 1: ', options);
78
+ log('log', 'create 2: ', `parentWin: ${parentWin?.id}`);
79
+ window = type === 'BV' ?
80
+ new electron.BrowserView(lodash.merge((browserWindowOptions || {}), {
81
+ parent: undefined,
82
+ webPreferences: {
83
+ // session: getCustomSession(),
84
+ plugins: true,
85
+ nodeIntegration: true,
86
+ contextIsolation: false,
87
+ backgroundThrottling: false,
88
+ nativeWindowOpen: false,
89
+ webSecurity: false,
90
+ preload: browserWindowOptions?.webPreferences?.preload || this.preload,
91
+ }
92
+ }))
93
+ : new electron.BrowserWindow(lodash.merge({
94
+ acceptFirstMouse: true,
95
+ }, (browserWindowOptions || {}), {
96
+ parent: parentWin,
97
+ webPreferences: {
98
+ // session: getCustomSession(),
99
+ plugins: true,
100
+ nodeIntegration: true,
101
+ contextIsolation: false,
102
+ backgroundThrottling: false,
103
+ nativeWindowOpen: false,
104
+ webSecurity: false,
105
+ preload: browserWindowOptions?.webPreferences?.preload || this.preload,
106
+ }
107
+ }));
108
+ try {
109
+ remote__namespace.enable(window.webContents);
110
+ }
111
+ catch (error) {
112
+ log('error', 'enable: ', error);
113
+ }
114
+ // @ts-ignore
115
+ try {
116
+ window.id = Number(`${window.id || window.webContents.id}`);
117
+ }
118
+ catch (error) {
119
+ // log('error', 'set id: ', error)
120
+ }
121
+ // @ts-ignore
122
+ try {
123
+ window._id = Number(`${window.id || window.webContents.id}`);
124
+ }
125
+ catch (error) {
126
+ // log('error', 'set id: ', error)
127
+ }
128
+ window._type = type;
129
+ window._name = name;
130
+ window._extraData = `${options?.extraData || ''}`;
131
+ log('log', 'create 5: ', window.id, window._id, window._name);
132
+ if (loadingView?.url) {
133
+ if (type === 'BW') {
134
+ // @ts-ignore
135
+ this._setLoadingView(window, options);
136
+ }
137
+ }
138
+ if (errorView?.url) {
139
+ const showErrorView = lodash.debounce(() => {
140
+ const _url = window?.webContents?.getURL?.() || url;
141
+ /**
142
+ * 判断是否是错误视图
143
+ */
144
+ const isErrorView = `${_url}`.toUpperCase().startsWith(`${errorView?.url}`.toUpperCase());
145
+ if (!isErrorView && _url) {
146
+ // @ts-ignore
147
+ window.loadURL ? window.loadURL(`${errorView?.url}`) : window.webContents.loadURL(`${errorView?.url}`);
148
+ window.webContents.executeJavaScript(`
149
+ var key = '__ELECTRON_WINDOW_MANAGER_DID_FAIL_LOAD_URL__';
150
+ window[key] = "${_url}";
151
+ sessionStorage.setItem(key, "${_url}");
152
+ `);
153
+ }
154
+ }, 300);
155
+ window.webContents.on('did-fail-load', () => {
156
+ showErrorView();
157
+ });
158
+ window.webContents.on('did-start-loading', () => {
159
+ showErrorView.cancel();
160
+ });
161
+ }
162
+ window.webContents.on('close', () => {
163
+ this.windows.delete(window.id || window._id);
164
+ });
165
+ window.webContents.on('destroyed', () => {
166
+ this.windows.delete(window.id || window._id);
167
+ });
168
+ window.webContents.on('dom-ready', () => {
169
+ if (openDevTools) {
170
+ window.webContents.openDevTools();
171
+ }
172
+ });
173
+ if (type === 'BW') {
174
+ // @ts-ignore
175
+ window.on('closed', () => {
176
+ log('log', 'closed', window.id, window._name);
177
+ this.windows.delete(window.id || window._id);
178
+ });
179
+ }
180
+ if (type === 'BV') {
181
+ parentWin?.addBrowserView(window);
182
+ log('log', 'create - addBrowserView');
183
+ }
184
+ // @ts-ignore
185
+ window.loadURL ? window.loadURL(options.url) : window.webContents.loadURL(options.url);
186
+ // @ts-ignore
187
+ window.focus ? window.focus() : window.webContents.focus();
188
+ this.windows.set(window.id || window._id || window.webContents.id, window);
189
+ log('log', 'create', this.windows.keys());
65
190
  }
66
- else {
67
- window.loadURL(options.url);
191
+ catch (error) {
192
+ log('error', 'create', error);
68
193
  }
69
- window.focus();
70
194
  return window;
71
195
  }
72
196
  _setLoadingView(window, createOptions) {
@@ -74,6 +198,7 @@ class WindowsManager {
74
198
  const { loadingView, preventOriginNavigate = false, } = createOptions;
75
199
  let _loadingView = new electron.BrowserView({
76
200
  webPreferences: {
201
+ // session: getCustomSession(),
77
202
  contextIsolation: false,
78
203
  nodeIntegration: true,
79
204
  // 允许loadURL与文件路径在开发环境
@@ -92,9 +217,10 @@ class WindowsManager {
92
217
  width: viewWidth || 10,
93
218
  height: viewHeight || 10,
94
219
  });
220
+ log('log', 'loadLoadingView', window._name);
95
221
  _loadingView.webContents.loadURL(loadingView?.url || '');
96
222
  };
97
- const onFailure = () => {
223
+ const onFailure = lodash.debounce(() => {
98
224
  if (_loadingView.webContents && !_loadingView.webContents.isDestroyed()) {
99
225
  _loadingView.webContents.close();
100
226
  }
@@ -104,9 +230,9 @@ class WindowsManager {
104
230
  if (window) {
105
231
  window.removeBrowserView(_loadingView);
106
232
  }
107
- };
233
+ }, 300);
108
234
  loadLoadingView();
109
- window.on('resize', _.debounce(() => {
235
+ window.on('resize', lodash.debounce(() => {
110
236
  if (_loadingView.webContents && !_loadingView.webContents.isDestroyed()) {
111
237
  if (window.isDestroyed()) {
112
238
  return;
@@ -136,61 +262,133 @@ class WindowsManager {
136
262
  window.webContents.on('crashed', onFailure);
137
263
  window.webContents.on('unresponsive', onFailure);
138
264
  window.webContents.on('did-fail-load', onFailure);
265
+ window.webContents.on('did-finish-load', onFailure);
266
+ window.webContents.on('did-stop-loading', onFailure);
139
267
  }
140
268
  }
141
- get(name) {
142
- let win = undefined;
143
- this.windows.forEach((i) => {
144
- if (i._name === name) {
145
- win = i;
269
+ get(idOrName) {
270
+ log('log', 'get', idOrName);
271
+ let win;
272
+ this.windows.forEach((i, key) => {
273
+ try {
274
+ if (!(i && i?.webContents?.isDestroyed && !i?.webContents?.isDestroyed?.())) {
275
+ this.windows.delete(key);
276
+ }
277
+ }
278
+ catch (error) {
279
+ log('error', 'get');
280
+ }
281
+ if (typeof idOrName === 'number') {
282
+ if (i?.id === idOrName || i?._id === idOrName) {
283
+ win = i;
284
+ }
285
+ }
286
+ else if (typeof idOrName === 'string') {
287
+ if (i?._name === idOrName) {
288
+ win = i;
289
+ }
146
290
  }
147
291
  });
148
- return win;
292
+ // @ts-ignore
293
+ if (win && win?.webContents?.isDestroyed && !win?.webContents?.isDestroyed?.()) {
294
+ return win;
295
+ }
296
+ return undefined;
149
297
  }
150
- getById(id) {
151
- let win = undefined;
152
- this.windows.forEach((i) => {
153
- if (i.id === id) {
154
- win = i;
298
+ getAll(type) {
299
+ log('log', 'getAll');
300
+ const bwWindows = new Map();
301
+ const bvWindows = new Map();
302
+ this.windows.forEach((win, key) => {
303
+ if (!(win && win?.webContents?.isDestroyed && !win?.webContents?.isDestroyed?.())) {
304
+ this.windows.delete(key);
305
+ }
306
+ if (win?._type === 'BW') {
307
+ bwWindows.set(key, win);
308
+ }
309
+ if (win?._type === 'BV') {
310
+ bvWindows.set(key, win);
155
311
  }
156
312
  });
157
- return win;
158
- }
159
- getAll() {
313
+ if (type === 'BW') {
314
+ return bwWindows;
315
+ }
316
+ if (type === 'BV') {
317
+ return bvWindows;
318
+ }
160
319
  return this.windows;
161
320
  }
162
- close(name) {
321
+ close(idOrName) {
322
+ log('log', 'close', idOrName);
163
323
  let win = undefined;
164
324
  this.windows.forEach((i) => {
165
- if (i._name === name) {
166
- win = i;
325
+ if (typeof idOrName === 'number') {
326
+ if (i?.id === idOrName || i?._id === idOrName) {
327
+ win = i;
328
+ }
329
+ }
330
+ else if (typeof idOrName === 'string') {
331
+ if (i?._name === idOrName) {
332
+ win = i;
333
+ }
167
334
  }
168
335
  });
169
336
  // @ts-ignore
170
337
  win && this.windows.delete(win?.id);
171
338
  // @ts-ignore
172
- return win && win?.destroy();
339
+ if (win) {
340
+ // @ts-ignore
341
+ if (win._type === 'BV') {
342
+ this.windows.forEach(i => {
343
+ if (i?._type === 'BW') {
344
+ const _win = i;
345
+ _win.removeBrowserView(win);
346
+ }
347
+ });
348
+ }
349
+ // @ts-ignore
350
+ win?.webContent?.close?.();
351
+ // @ts-ignore
352
+ win?.close?.();
353
+ // @ts-ignore
354
+ win?.destroy?.();
355
+ }
356
+ return true;
173
357
  }
174
- closeById(id) {
175
- let win = undefined;
176
- this.windows.forEach((i) => {
177
- if (i.id === id) {
178
- win = i;
358
+ closeAll() {
359
+ log('log', 'closeAll');
360
+ this.windows.forEach((win) => {
361
+ try {
362
+ win && this.windows.delete(win?.id);
363
+ // @ts-ignore
364
+ if (win._type === 'BV') {
365
+ this.windows.forEach(i => {
366
+ if (i?._type === 'BW') {
367
+ const _win = i;
368
+ _win.removeBrowserView(win);
369
+ }
370
+ });
371
+ }
372
+ // @ts-ignore
373
+ win?.webContent?.close?.();
374
+ // @ts-ignore
375
+ win?.close?.();
376
+ // @ts-ignore
377
+ win?.destroy?.();
378
+ }
379
+ catch (error) {
179
380
  }
180
381
  });
181
- // @ts-ignore
182
- win && this.windows.delete(win?.id);
183
- // @ts-ignore
184
- return win && win?.destroy();
185
382
  }
186
383
  getPreload() {
384
+ log('log', 'getPreload');
187
385
  return this.preload;
188
386
  }
189
387
  }
190
388
  // @ts-ignore
191
389
  global['__ELECTRON_WINDOWS_MANAGER__'] = undefined;
192
390
  exports.isInitialized = false;
193
- const initialize = (preload) => {
391
+ const initialize = (preload, loadingViewUrl, errorViewUrl) => {
194
392
  // @ts-ignore
195
393
  if (exports.isInitialized && global['__ELECTRON_WINDOWS_MANAGER__']) {
196
394
  // @ts-ignore
@@ -198,38 +396,45 @@ const initialize = (preload) => {
198
396
  }
199
397
  exports.isInitialized = true;
200
398
  // @ts-ignore
201
- const wm = global['__ELECTRON_WINDOWS_MANAGER__'] = new WindowsManager(preload);
399
+ const wm = global['__ELECTRON_WINDOWS_MANAGER__'] = new WindowsManager(preload, loadingViewUrl, errorViewUrl);
202
400
  eIpc.mainIPC.handleRenderer('__ELECTRON_WINDOW_MANAGER_IPC_CHANNEL__', async (data) => {
203
401
  if (data?.type === 'create') {
204
402
  const opt = data;
205
403
  const findWin = wm.get(opt.data.name);
206
404
  if (findWin) {
207
- findWin.focus();
405
+ // @ts-ignore
406
+ findWin?.focus?.();
407
+ findWin?.webContents.focus?.();
408
+ if (opt.data.url && findWin.webContents.getURL() !== opt.data.url) {
409
+ findWin.webContents.loadURL(opt.data.url);
410
+ /** fix: url hash 无法正常加载 */
411
+ setTimeout(() => {
412
+ findWin.webContents.reload();
413
+ }, 100);
414
+ }
208
415
  return {
209
- winId: findWin?.id,
210
- winName: findWin?._name,
416
+ winId: Number(`${findWin?.id || findWin?._id || -1}`),
417
+ winName: `${findWin?._name || ''}`,
418
+ winType: `${findWin?._type || ''}`,
419
+ winExtraData: `${findWin?._extraData || ''}`,
211
420
  };
212
421
  }
213
422
  const res = wm.create(opt.data);
214
423
  return {
215
- winId: Number(res.id),
216
- winName: res._name,
424
+ winId: Number(`${res.id || res._id || -1}`),
425
+ winName: `${res?._name || ''}`,
426
+ winType: `${res?._type || ''}`,
427
+ winExtraData: `${res?._extraData || ''}`,
217
428
  };
218
429
  }
219
430
  if (data?.type === 'get') {
220
431
  const opt = data;
221
432
  const res = wm.get(opt?.data);
222
433
  return {
223
- winId: res?.id ? Number(res?.id) : -1,
224
- winName: res?._name ? res?._name : '',
225
- };
226
- }
227
- if (data?.type === 'getById') {
228
- const opt = data;
229
- const res = wm.getById(opt?.data);
230
- return {
231
- winId: res?.id ? Number(res?.id) : -1,
232
- winName: res?._name ? res?._name : '',
434
+ winId: Number(`${res?.id || res?._id || -1}`),
435
+ winName: `${res?._name || ''}`,
436
+ winType: `${res?._type || ''}`,
437
+ winExtraData: `${res?._extraData || ''}`,
233
438
  };
234
439
  }
235
440
  if (data?.type === 'getAll') {
@@ -237,9 +442,11 @@ const initialize = (preload) => {
237
442
  const obj = {};
238
443
  res.forEach(i => {
239
444
  // @ts-ignore
240
- obj[i.id] = {
241
- winId: i?.id ? Number(i?.id) : -1,
242
- winName: i?._name ? i?._name : '',
445
+ obj[i.id || i._id] = {
446
+ winId: Number(`${i?.id || i?._id || -1}`),
447
+ winName: `${i?._name || ''}`,
448
+ winType: `${i?._type || ''}`,
449
+ winExtraData: `${i?._extraData || ''}`,
243
450
  };
244
451
  });
245
452
  return obj;
@@ -249,21 +456,89 @@ const initialize = (preload) => {
249
456
  const res = wm.close(opt?.data);
250
457
  return res;
251
458
  }
252
- if (data?.type === 'closeById') {
253
- const opt = data;
254
- const res = wm.closeById(opt?.data);
459
+ if (data?.type === 'closeAll') {
460
+ const res = wm.closeAll();
255
461
  return res;
256
462
  }
463
+ if (data?.type === 'getWindowForWebContentId') {
464
+ const opt = data;
465
+ const targetWebContents = electron.webContents.fromId(opt.data);
466
+ if (targetWebContents) {
467
+ let win = electron.BrowserWindow.fromWebContents(targetWebContents);
468
+ if (!win) {
469
+ // 获取所有的 BrowserWindows
470
+ let allWindows = electron.BrowserWindow.getAllWindows();
471
+ // 遍历所有窗口,检查每个窗口的 BrowserView
472
+ for (let _win of allWindows) {
473
+ let views = _win.getBrowserViews();
474
+ // 遍历窗口的所有 BrowserView
475
+ for (let view of views) {
476
+ if (view.webContents === targetWebContents) {
477
+ win = _win;
478
+ break;
479
+ }
480
+ }
481
+ if (win)
482
+ break;
483
+ }
484
+ }
485
+ // @ts-ignore
486
+ return win?.id || win?._id;
487
+ }
488
+ return undefined;
489
+ }
257
490
  if (data?.type === 'getPreload') {
258
491
  const res = wm.getPreload();
259
492
  return res;
260
493
  }
494
+ if (data?.type === 'borrowView_getBounds') {
495
+ const opt = data;
496
+ const bv = wm.get(opt.data.webContentId);
497
+ if (bv) {
498
+ return bv.getBounds();
499
+ }
500
+ return undefined;
501
+ }
502
+ if (data?.type === 'borrowView_setBounds') {
503
+ const opt = data;
504
+ const bv = wm.get(opt.data.webContentId);
505
+ if (bv) {
506
+ bv.setBounds(opt.data.options);
507
+ }
508
+ return undefined;
509
+ }
510
+ if (data?.type === 'borrowView_setAutoResize') {
511
+ const opt = data;
512
+ const bv = wm.get(opt.data.webContentId);
513
+ if (bv) {
514
+ bv.setAutoResize(opt.data.options);
515
+ }
516
+ return undefined;
517
+ }
518
+ if (data?.type === 'borrowView_setBackgroundColor') {
519
+ const opt = data;
520
+ const bv = wm.get(opt.data.webContentId);
521
+ if (bv) {
522
+ bv.setBackgroundColor(opt.data.options);
523
+ }
524
+ return undefined;
525
+ }
261
526
  return undefined;
262
527
  });
263
528
  return wm;
264
529
  };
530
+ const log = (type, ...data) => {
531
+ const key = `[electron-window-manager]: `;
532
+ try {
533
+ console[type](key, ...data);
534
+ }
535
+ catch (error) {
536
+ console.error(key, error);
537
+ }
538
+ };
265
539
 
266
540
  exports.WindowsManager = WindowsManager;
267
541
  exports.enable = enable;
542
+ exports.getCustomSession = getCustomSession;
268
543
  exports.initialize = initialize;
269
544
  //# sourceMappingURL=index.js.map