chuijs 4.0.0 → 4.0.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/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  // === ИНСТРУМЕНТЫ ===
2
- const {app, BrowserWindow, Menu, Tray, ipcMain, ipcRenderer, shell, nativeTheme, session, webContents, systemPreferences} = require('electron');
3
- const { dialog } = require('@electron/remote/main');
2
+ const {app, BrowserWindow, Menu, Tray, ipcMain, ipcRenderer, shell, nativeTheme, session, webContents, systemPreferences, dialog} = require('electron');
4
3
  // Одно хранилище настроек на модуль: его получает приложение через `require('chuijs').store`,
5
4
  // из него читают тему, язык и история буфера, а `Settings` берёт его для своих значений по умолчанию
6
5
  const {store} = require("./framework/modules/chui_store/chui_store");
@@ -50,6 +49,7 @@ const {Descriptions} = require('./framework/components/chui_descriptions/descrip
50
49
  const {Statistic} = require('./framework/components/chui_statistic/statistic');
51
50
  const {Backtop} = require('./framework/components/chui_backtop/backtop');
52
51
  const {Affix} = require('./framework/components/chui_affix/affix');
52
+ const {StickyBar} = require('./framework/components/chui_sticky_bar/sticky_bar');
53
53
  const {Watermark} = require('./framework/components/chui_watermark/watermark');
54
54
  const {ShortcutHelp} = require('./framework/components/chui_shortcut_help/shortcut_help');
55
55
  const {Tooltip} = require('./framework/components/chui_tooltip/tooltip');
@@ -78,7 +78,7 @@ const {CodeBlock} = require('./framework/components/chui_code/code')
78
78
  const {HtmlBlock} = require('./framework/components/chui_html_block/html_block')
79
79
  const {sleep, render, getDefaultIcon, formatBytes} = require('./framework/modules/chui_functions');
80
80
  const {Shortcuts, Clipboard, RecentDocuments, TaskbarProgress} = require('./framework/modules/chui_services/chui_services');
81
- const {SERVICES_CHANNELS, BRIDGE_CHANNELS, BRIDGE_ARGS} = require('./framework/modules/chui_services/chui_channels');
81
+ const {SERVICES_CHANNELS, BRIDGE_CHANNELS, BRIDGE_ARGS, APP_PATH_NAMES} = require('./framework/modules/chui_services/chui_channels');
82
82
  const {Desktop} = require('./framework/modules/chui_services/desktop');
83
83
  const {I18n} = require('./framework/modules/chui_i18n/chui_i18n');
84
84
  const {Shell, Theme, Locale, ClipboardHistory: ClipboardHistoryService, Print} = require('./framework/modules/chui_services/chui_services');
@@ -150,6 +150,11 @@ const {QRCode} = require("./framework/components/chui_qrcode/qrcode");
150
150
  const {Log} = require("./framework/modules/chui_logger/chui_logger");
151
151
  const url = require("node:url");
152
152
 
153
+ /** Код исполняется на странице (renderer), а не в main: от этого зависит доступ к модулям Electron */
154
+ function inRenderer() {
155
+ return process !== undefined && process.type === "renderer";
156
+ }
157
+
153
158
  //VARS
154
159
  let isQuiting = false;
155
160
 
@@ -236,6 +241,7 @@ class Main {
236
241
  #security = {contextIsolation: false, csp: false, channels: []};
237
242
  #secure_contents = new Set();
238
243
  #bridge_enabled = false;
244
+ #window_actions_bound = false;
239
245
  #theme_bound = false;
240
246
  #page_message_handlers = new Map();
241
247
  #onUncaughtException = (error) => {
@@ -431,7 +437,6 @@ class Main {
431
437
  plugins: false,
432
438
  nodeIntegration: false,
433
439
  contextIsolation: true,
434
- enableRemoteModule: false,
435
440
  sandbox: false,
436
441
  preload: Main.SECURE_PRELOAD,
437
442
  additionalArguments: Main.#bridgeArguments(options.render, security),
@@ -448,7 +453,6 @@ class Main {
448
453
  preload: options.render === undefined ? this.#renderer : options.render,
449
454
  spellcheck: false,
450
455
  webviewTag: true,
451
- enableRemoteModule: true,
452
456
  webSecurity: this.#webSecurity,
453
457
  nodeIntegrationInSubFrames: true,
454
458
  },
@@ -627,6 +631,9 @@ class Main {
627
631
  enableServices() {
628
632
  if (this.#services_enabled) return this;
629
633
  this.#services_enabled = true;
634
+ // Кнопки окна: каналы нужны и обычным окнам — в них `AppLayout` зовёт их по IPC,
635
+ // потому что `@electron/remote` в рендерере больше нет
636
+ this.#enableWindowActions();
630
637
  this.services = {
631
638
  shortcuts: new Shortcuts(),
632
639
  shell: new Shell(),
@@ -686,6 +693,25 @@ class Main {
686
693
  this.services.clipboard.clear();
687
694
  return true;
688
695
  });
696
+ // Приложение и системные диалоги для страницы: Electron советует IPC вместо `remote`.
697
+ // Путь — только из белого списка, диалог и сессия — у окна-отправителя.
698
+ this.#handle(SERVICES_CHANNELS.APP_PATH, (event, name) => {
699
+ if (APP_PATH_NAMES.includes(name) === false) throw new Error(`App.path: имя «${name}» вне белого списка`);
700
+ return app.getPath(name);
701
+ });
702
+ this.#handle(SERVICES_CHANNELS.APP_INFO, () => ({
703
+ name: app.getName(),
704
+ version: app.getVersion(),
705
+ locale: app.getLocale(),
706
+ systemLocale: app.getSystemLocale(),
707
+ isPackaged: app.isPackaged
708
+ }));
709
+ this.#handle(SERVICES_CHANNELS.DIALOG_OPEN, (event, options) => Main.#showDialog(event, "showOpenDialog", options));
710
+ this.#handle(SERVICES_CHANNELS.DIALOG_SAVE, (event, options) => Main.#showDialog(event, "showSaveDialog", options));
711
+ this.#handle(SERVICES_CHANNELS.DIALOG_MESSAGE, (event, options) => Main.#showDialog(event, "showMessageBox", options));
712
+ this.#handle(SERVICES_CHANNELS.SESSION_CACHE_SIZE, (event) => event.sender.session.getCacheSize());
713
+ this.#handle(SERVICES_CHANNELS.SESSION_CLEAR_CACHE, (event) => event.sender.session.clearCache());
714
+ this.#handle(SERVICES_CHANNELS.SESSION_CLEAR_STORAGE, (event, options) => event.sender.session.clearStorageData(options));
689
715
  this.#handle(SERVICES_CHANNELS.RECENT_ADD, (event, path, name) => {
690
716
  this.services.recent.add(path, name);
691
717
  return true;
@@ -745,9 +771,19 @@ class Main {
745
771
  * Включает мост безопасных окон (`contextBridge`): управление окном, тема и прикладные
746
772
  * сообщения по белому списку каналов. Вызывается сам при создании безопасного окна.
747
773
  */
748
- enableBridge() {
749
- if (this.#bridge_enabled) return this;
750
- this.#bridge_enabled = true;
774
+ /** Диалог в окне отправителя: без окна (уже закрыто) Electron зовётся без родителя */
775
+ static #showDialog(event, method = String(), options = Object()) {
776
+ const window = BrowserWindow.fromWebContents(event.sender);
777
+ return window === null ? dialog[method](options) : dialog[method](window, options);
778
+ }
779
+
780
+ /**
781
+ * Каналы кнопок окна. Ими пользуются оба режима: безопасное окно — через мост
782
+ * `window.chui.window`, обычное — прямым `ipcRenderer.invoke`. Регистрируются один раз на приложение.
783
+ */
784
+ #enableWindowActions() {
785
+ if (this.#window_actions_bound) return this;
786
+ this.#window_actions_bound = true;
751
787
  this.#handle(BRIDGE_CHANNELS.WINDOW_ACTION, (event, action) => Main.#applyWindowAction(event.sender, action));
752
788
  this.#handle(BRIDGE_CHANNELS.WINDOW_STATE, (event) => {
753
789
  const window = BrowserWindow.fromWebContents(event.sender);
@@ -759,6 +795,13 @@ class Main {
759
795
  isFocused: window.isFocused()
760
796
  };
761
797
  });
798
+ return this;
799
+ }
800
+
801
+ enableBridge() {
802
+ if (this.#bridge_enabled) return this;
803
+ this.#bridge_enabled = true;
804
+ this.#enableWindowActions();
762
805
  this.#handle(BRIDGE_CHANNELS.THEME_GET, () => (nativeTheme.shouldUseDarkColors ? "dark" : "light"));
763
806
  this.#handle(BRIDGE_CHANNELS.LOCALE_GET, () => this.services.locale.get());
764
807
  this.#handle(BRIDGE_CHANNELS.MESSAGE, (event, channel, ...args) => {
@@ -790,7 +833,7 @@ class Main {
790
833
  return this.#send(BRIDGE_CHANNELS.MESSAGE, [channel, payload], windowName);
791
834
  }
792
835
 
793
- /** Действия кнопок окна для безопасного режима (там нет @electron/remote) */
836
+ /** Действия кнопок окна: и обычные окна, и безопасные зовут их по IPC */
794
837
  static #applyWindowAction(sender, action = String()) {
795
838
  const window = BrowserWindow.fromWebContents(sender);
796
839
  if (window === null || window.isDestroyed()) return false;
@@ -1021,6 +1064,7 @@ class Main {
1021
1064
  this.#on_theme_updated = undefined;
1022
1065
  this.#page_message_handlers.clear();
1023
1066
  this.#bridge_enabled = false;
1067
+ this.#window_actions_bound = false;
1024
1068
  if (this.#updaterListening) {
1025
1069
  this.#updaterListening = false;
1026
1070
  require("electron-updater").autoUpdater.removeListener('update-downloaded', this.#onUpdateDownloaded);
@@ -1074,9 +1118,7 @@ class Main {
1074
1118
  Menu.setApplicationMenu(null)
1075
1119
  }
1076
1120
  this.enableServices();
1077
- const window = this.#buildWindow({name: Main.MAIN_WINDOW, hideOnClose: options.hideOnClose});
1078
- require("@electron/remote/main").initialize();
1079
- require("@electron/remote/main").enable(window.webContents);
1121
+ this.#buildWindow({name: Main.MAIN_WINDOW, hideOnClose: options.hideOnClose});
1080
1122
  })
1081
1123
  }
1082
1124
 
@@ -1170,25 +1212,16 @@ class Styles {
1170
1212
 
1171
1213
  class Application {
1172
1214
  getApp() {
1173
- if (process && process.type === 'renderer') {
1174
- return require("@electron/remote").app;
1175
- } else {
1176
- return app;
1177
- }
1215
+ if (inRenderer()) throw new Error("App.get(): странице не отдают модули main — возьмите Desktop.app.path()/info() или свой канал из security.channels");
1216
+ return app;
1178
1217
  }
1179
1218
  getSession() {
1180
- if (process && process.type === 'renderer') {
1181
- return require("@electron/remote").session;
1182
- } else {
1183
- return session;
1184
- }
1219
+ if (inRenderer()) throw new Error("App.getSession(): странице не отдают сессию main — возьмите Desktop.session.*");
1220
+ return session;
1185
1221
  }
1186
1222
  getWebContents() {
1187
- if (process && process.type === 'renderer') {
1188
- return require("@electron/remote").webContents;
1189
- } else {
1190
- return webContents;
1191
- }
1223
+ if (inRenderer()) throw new Error("App.getWebContents(): странице не отдают webContents main — действия идут через Desktop или свой канал из security.channels");
1224
+ return webContents;
1192
1225
  }
1193
1226
  }
1194
1227
 
@@ -1246,6 +1279,7 @@ module.exports = {
1246
1279
  Statistic: Statistic,
1247
1280
  Backtop: Backtop,
1248
1281
  Affix: Affix,
1282
+ StickyBar: StickyBar,
1249
1283
  Watermark: Watermark,
1250
1284
  ShortcutHelp: ShortcutHelp,
1251
1285
  Alert: Alert,
@@ -1388,7 +1422,12 @@ module.exports = {
1388
1422
  //
1389
1423
  downloadSession: downloadSession,
1390
1424
  Log: Log,
1391
- chooseFile: dialog,
1425
+ chooseFile: {
1426
+ // Диалоги: странице — по IPC (окно берётся у отправителя), в main — обычный dialog Electron
1427
+ showOpenDialog: (options = {}) => (inRenderer() ? Desktop.dialog.open(options) : dialog.showOpenDialog(options)),
1428
+ showSaveDialog: (options = {}) => (inRenderer() ? Desktop.dialog.save(options) : dialog.showSaveDialog(options)),
1429
+ showMessageBox: (options = {}) => (inRenderer() ? Desktop.dialog.message(options) : dialog.showMessageBox(options))
1430
+ },
1392
1431
  //
1393
1432
  systemPreferences: systemPreferences
1394
1433
  }
package/package.json CHANGED
@@ -2,20 +2,35 @@
2
2
  "name": "chuijs",
3
3
  "productName": "chuijs",
4
4
  "description": "component framework chUiJS",
5
- "version": "4.0.0",
5
+ "version": "4.0.1",
6
6
  "private": false,
7
7
  "main": "index.js",
8
+ "type": "commonjs",
8
9
  "author": {
9
10
  "name": "saintdizen",
10
11
  "email": "saintdizen@gmail.com"
11
12
  },
12
13
  "homepage": "https://dethmond.gitverse.site/chuijs",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://gitverse.ru/DethMond/chuijs.git"
17
+ },
18
+ "bugs": {
19
+ "url": "https://gitverse.ru/DethMond/chuijs/issues"
20
+ },
13
21
  "files": [
14
22
  "framework/**/*",
15
23
  "index.js",
16
24
  "package.json",
17
- "README.md"
25
+ "README.md",
26
+ "CHANGELOG.md"
18
27
  ],
28
+ "exports": {
29
+ ".": "./index.js",
30
+ "./package.json": "./package.json",
31
+ "./framework/*": "./framework/*.js",
32
+ "./framework/*.js": "./framework/*.js"
33
+ },
19
34
  "keywords": [
20
35
  "Electron",
21
36
  "Framework",
@@ -30,18 +45,21 @@
30
45
  "format": "prettier --write .",
31
46
  "format:check": "prettier --check ."
32
47
  },
48
+ "engines": {
49
+ "node": ">=18"
50
+ },
33
51
  "license": "MIT",
34
52
  "dependencies": {
35
53
  "@cypress/request": "~4.0.1",
36
- "@electron/remote": "~2.1.3",
37
- "dataurl": "~0.1.0",
38
54
  "electron": "~44.4.5",
39
55
  "electron-store": "~8.2.0",
40
56
  "electron-updater": "~6.8.9",
41
57
  "image-size": "~2.0.4",
58
+ "markdown-it": "^15.0.2",
59
+ "markdown-it-task-lists": "^2.1.1",
42
60
  "randomstring": "~1.3.0",
43
- "showdown": "~2.1.0",
44
- "transliteration": "~2.6.1"
61
+ "transliteration": "~2.6.1",
62
+ "turndown": "^7.2.4"
45
63
  },
46
64
  "devDependencies": {
47
65
  "@eslint/js": "^10.0.1",