chuijs 4.0.1 → 4.0.3
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/CHANGELOG.md +113 -0
- package/README.md +43 -632
- package/framework/appLayout/default/chui_app_layout.js +314 -273
- package/framework/appLayout/default/global_style.css +93 -53
- package/framework/components/chui_accordion/accordion.js +29 -26
- package/framework/components/chui_accordion/styles.css +6 -5
- package/framework/components/chui_action_sheet/action_sheet.js +59 -33
- package/framework/components/chui_action_sheet/styles.css +2 -1
- package/framework/components/chui_affix/affix.js +11 -6
- package/framework/components/chui_alert/alert.js +23 -14
- package/framework/components/chui_avatar/avatar.js +23 -22
- package/framework/components/chui_avatar_group/avatar_group.js +21 -19
- package/framework/components/chui_backtop/backtop.js +35 -19
- package/framework/components/chui_badge/badge.js +15 -13
- package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
- package/framework/components/chui_button/button.js +42 -22
- package/framework/components/chui_button/styles.css +2 -2
- package/framework/components/chui_calendar/calendar.js +12 -10
- package/framework/components/chui_card/card.js +43 -23
- package/framework/components/chui_chat/chat.js +72 -33
- package/framework/components/chui_clipboard_history/clipboard_history.js +30 -21
- package/framework/components/chui_clipboard_history/styles.css +4 -2
- package/framework/components/chui_code/code.js +2 -2
- package/framework/components/chui_code/styles.css +2 -2
- package/framework/components/chui_code_editor/code_editor.js +47 -31
- package/framework/components/chui_code_editor/styles.css +3 -2
- package/framework/components/chui_command_palette/command_palette.js +60 -37
- package/framework/components/chui_console/console.js +5 -5
- package/framework/components/chui_console/styles.css +1 -1
- package/framework/components/chui_content_block/content_block.js +33 -19
- package/framework/components/chui_content_block/styles.css +2 -2
- package/framework/components/chui_context_menu/context_menu.js +9 -4
- package/framework/components/chui_custom_element/custom_element.js +22 -15
- package/framework/components/chui_data_grid/data_grid.js +396 -234
- package/framework/components/chui_data_grid/styles.css +10 -8
- package/framework/components/chui_descriptions/descriptions.js +34 -17
- package/framework/components/chui_details/details.js +32 -26
- package/framework/components/chui_details/styles.css +5 -4
- package/framework/components/chui_diff_viewer/diff_viewer.js +91 -66
- package/framework/components/chui_diff_viewer/styles.css +1 -1
- package/framework/components/chui_divider/divider.js +13 -11
- package/framework/components/chui_drawer/drawer.js +27 -25
- package/framework/components/chui_drop_zone/drop_zone.js +31 -21
- package/framework/components/chui_empty_state/empty_state.js +20 -15
- package/framework/components/chui_fieldset/fieldset.js +37 -20
- package/framework/components/chui_fieldset/styles.css +1 -1
- package/framework/components/chui_file_explorer/file_explorer.js +157 -86
- package/framework/components/chui_file_explorer/styles.css +2 -1
- package/framework/components/chui_form/form.js +31 -19
- package/framework/components/chui_form/styles.css +1 -1
- package/framework/components/chui_gantt/gantt.js +64 -40
- package/framework/components/chui_graphs/graphs.js +301 -200
- package/framework/components/chui_graphs/styles.css +1 -1
- package/framework/components/chui_hero/hero.js +40 -22
- package/framework/components/chui_html_block/html_block.js +6 -6
- package/framework/components/chui_html_block/styles.css +2 -2
- package/framework/components/chui_hx/hx.js +3 -3
- package/framework/components/chui_hx/styles.css +11 -4
- package/framework/components/chui_icons/icons.js +2109 -2109
- package/framework/components/chui_icons/styles.css +2 -2
- package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
- package/framework/components/chui_inputs/chui_check_box/styles.css +18 -18
- package/framework/components/chui_inputs/chui_chips/chips.js +50 -40
- package/framework/components/chui_inputs/chui_chips/styles.css +4 -2
- package/framework/components/chui_inputs/chui_color_picker/color_picker.js +36 -24
- package/framework/components/chui_inputs/chui_combo_box/combo_box.js +100 -82
- package/framework/components/chui_inputs/chui_combo_box/styles.css +14 -12
- package/framework/components/chui_inputs/chui_date/date.js +102 -66
- package/framework/components/chui_inputs/chui_date/styles.css +12 -11
- package/framework/components/chui_inputs/chui_date_range/date_range.js +40 -29
- package/framework/components/chui_inputs/chui_datetime/datetime.js +35 -27
- package/framework/components/chui_inputs/chui_email/email.js +43 -31
- package/framework/components/chui_inputs/chui_email/styles.css +5 -5
- package/framework/components/chui_inputs/chui_file/file.js +68 -41
- package/framework/components/chui_inputs/chui_file/styles.css +13 -12
- package/framework/components/chui_inputs/chui_hotkey/hotkey.js +61 -36
- package/framework/components/chui_inputs/chui_masked/masked.js +39 -28
- package/framework/components/chui_inputs/chui_mention/mention.js +77 -30
- package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +173 -153
- package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +9 -7
- package/framework/components/chui_inputs/chui_number/number.js +58 -41
- package/framework/components/chui_inputs/chui_number/styles.css +7 -7
- package/framework/components/chui_inputs/chui_otp/otp.js +38 -29
- package/framework/components/chui_inputs/chui_password/password.js +58 -36
- package/framework/components/chui_inputs/chui_password/styles.css +8 -8
- package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
- package/framework/components/chui_inputs/chui_radio_button/styles.css +20 -20
- package/framework/components/chui_inputs/chui_rating/rating.js +26 -22
- package/framework/components/chui_inputs/chui_select_box/select_box.js +102 -78
- package/framework/components/chui_inputs/chui_select_box/styles.css +11 -11
- package/framework/components/chui_inputs/chui_slider/slider.js +29 -26
- package/framework/components/chui_inputs/chui_slider/styles.css +2 -1
- package/framework/components/chui_inputs/chui_text/styles.css +8 -8
- package/framework/components/chui_inputs/chui_text/text.js +65 -44
- package/framework/components/chui_inputs/chui_text_area/styles.css +6 -6
- package/framework/components/chui_inputs/chui_text_area/text_area.js +51 -28
- package/framework/components/chui_inputs/chui_time/styles.css +5 -3
- package/framework/components/chui_inputs/chui_time/time.js +38 -27
- package/framework/components/chui_inputs/chui_toggle/styles.css +3 -3
- package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
- package/framework/components/chui_json_editor/json_editor.js +53 -43
- package/framework/components/chui_json_viewer/json_viewer.js +52 -33
- package/framework/components/chui_json_viewer/styles.css +3 -2
- package/framework/components/chui_kanban/kanban.js +52 -34
- package/framework/components/chui_kbd/kbd.js +12 -10
- package/framework/components/chui_label/label.js +14 -12
- package/framework/components/chui_label/styles.css +2 -2
- package/framework/components/chui_link/link.js +27 -20
- package/framework/components/chui_list/list.js +31 -27
- package/framework/components/chui_list/styles.css +2 -1
- package/framework/components/chui_markdown_editor/markdown_editor.js +60 -44
- package/framework/components/chui_media/audio.js +326 -227
- package/framework/components/chui_media/audio_styles.css +40 -21
- package/framework/components/chui_media/image.js +70 -38
- package/framework/components/chui_media/image_compare.js +52 -21
- package/framework/components/chui_media/image_styles.css +3 -3
- package/framework/components/chui_media/video.js +155 -62
- package/framework/components/chui_media/video_styles.css +33 -16
- package/framework/components/chui_menu_bar/menu_bar.js +26 -24
- package/framework/components/chui_menu_bar/styles.css +4 -2
- package/framework/components/chui_modal/modal.js +44 -43
- package/framework/components/chui_modal/styles.css +3 -2
- package/framework/components/chui_notification/notification.js +50 -34
- package/framework/components/chui_notification/notification_download.js +31 -25
- package/framework/components/chui_notification/notification_download_progress.css +3 -2
- package/framework/components/chui_notification/notification_download_progress.js +47 -41
- package/framework/components/chui_notification/notification_update.js +23 -16
- package/framework/components/chui_notification/status_plate.js +2 -2
- package/framework/components/chui_notification/styles_download.css +1 -1
- package/framework/components/chui_notification/styles_update.css +1 -1
- package/framework/components/chui_org_chart/org_chart.js +74 -35
- package/framework/components/chui_pagination/pagination.js +62 -27
- package/framework/components/chui_paragraph/paragraph.js +2 -2
- package/framework/components/chui_paragraph/styles.css +1 -1
- package/framework/components/chui_popover/popover.js +49 -28
- package/framework/components/chui_popups/popups.js +137 -108
- package/framework/components/chui_popups/styles.css +2 -2
- package/framework/components/chui_print_button/print_button.js +33 -23
- package/framework/components/chui_progress_bar/progress_bar.js +23 -15
- package/framework/components/chui_progress_bar/styles.css +2 -2
- package/framework/components/chui_progress_ring/progress_ring.js +17 -15
- package/framework/components/chui_qrcode/qrcode.js +75 -31
- package/framework/components/chui_query_builder/query_builder.js +216 -123
- package/framework/components/chui_radio_group/radio_group.js +36 -26
- package/framework/components/chui_radio_group/styles.css +1 -1
- package/framework/components/chui_result/result.js +26 -16
- package/framework/components/chui_scheduler/scheduler.js +57 -35
- package/framework/components/chui_scheduler/styles.css +6 -2
- package/framework/components/chui_segmented_control/segmented_control.js +27 -21
- package/framework/components/chui_settings/settings.js +122 -48
- package/framework/components/chui_shortcut_help/shortcut_help.js +55 -32
- package/framework/components/chui_sidebar_nav/sidebar_nav.js +33 -23
- package/framework/components/chui_skeleton/skeleton.js +29 -24
- package/framework/components/chui_slideshow/slideshow.js +60 -41
- package/framework/components/chui_slideshow/styles.css +18 -12
- package/framework/components/chui_spinner/spinner.js +8 -8
- package/framework/components/chui_spinner/styles.css +0 -1
- package/framework/components/chui_split_button/split_button.js +23 -18
- package/framework/components/chui_split_button/styles.css +1 -1
- package/framework/components/chui_splitter/splitter.js +35 -28
- package/framework/components/chui_statistic/statistic.js +65 -38
- package/framework/components/chui_status_bar/status_bar.js +11 -9
- package/framework/components/chui_stepper/stepper.js +27 -22
- package/framework/components/chui_sticky_bar/sticky_bar.js +9 -4
- package/framework/components/chui_sticky_bar/styles.css +3 -1
- package/framework/components/chui_tabs/chui_tabs.js +28 -22
- package/framework/components/chui_tabs/styles.css +3 -3
- package/framework/components/chui_text_editor/styles.css +20 -19
- package/framework/components/chui_text_editor/text_editor.js +85 -61
- package/framework/components/chui_text_editor/text_editor_panel.js +346 -284
- package/framework/components/chui_theme_toggle/theme_toggle.js +27 -22
- package/framework/components/chui_timeline/timeline.js +14 -12
- package/framework/components/chui_toast_queue/toast_queue.js +52 -46
- package/framework/components/chui_toolbar/toolbar.js +20 -13
- package/framework/components/chui_tooltip/tooltip.js +37 -24
- package/framework/components/chui_tour/styles.css +8 -3
- package/framework/components/chui_tour/tour.js +61 -27
- package/framework/components/chui_transfer/styles.css +2 -1
- package/framework/components/chui_transfer/transfer.js +75 -42
- package/framework/components/chui_tree_table/tree_table.js +43 -29
- package/framework/components/chui_tree_view/styles.css +4 -2
- package/framework/components/chui_tree_view/tree_view.js +142 -99
- package/framework/components/chui_watermark/watermark.js +24 -16
- package/framework/components/chui_webview/styles.css +2 -2
- package/framework/components/chui_webview/webview.js +62 -50
- package/framework/components/telegram_bot/chui_telegram_bot.js +71 -64
- package/framework/modules/chui_a11y/chui_a11y.js +77 -46
- package/framework/modules/chui_animations/animations.js +42 -42
- package/framework/modules/chui_animations/styles.css +1 -1
- package/framework/modules/chui_bridge/preload.js +56 -26
- package/framework/modules/chui_functions.js +52 -50
- package/framework/modules/chui_highlight/chui_highlight.js +25 -22
- package/framework/modules/chui_i18n/chui_i18n.js +9 -7
- package/framework/modules/chui_i18n/locales/a11y.js +5 -5
- package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
- package/framework/modules/chui_i18n/locales/calendar.js +3 -3
- package/framework/modules/chui_i18n/locales/common.js +3 -3
- package/framework/modules/chui_i18n/locales/data.js +36 -26
- package/framework/modules/chui_i18n/locales/editors.js +40 -13
- package/framework/modules/chui_i18n/locales/feedback.js +3 -3
- package/framework/modules/chui_i18n/locales/forms.js +8 -8
- package/framework/modules/chui_i18n/locales/graphics.js +8 -8
- package/framework/modules/chui_i18n/locales/media.js +4 -4
- package/framework/modules/chui_i18n/locales/navigation.js +8 -8
- package/framework/modules/chui_i18n/locales/validate.js +3 -3
- package/framework/modules/chui_json/chui_json.js +9 -9
- package/framework/modules/chui_layout/chui_layout.js +12 -10
- package/framework/modules/chui_logger/chui_logger.js +29 -25
- package/framework/modules/chui_page/page.js +33 -27
- package/framework/modules/chui_page/styles.css +3 -26
- package/framework/modules/chui_qr/chui_qr.js +158 -67
- package/framework/modules/chui_scrollbar/chui_scrollbar.js +35 -24
- package/framework/modules/chui_scrollbar/styles.css +3 -1
- package/framework/modules/chui_services/chui_channels.js +76 -11
- package/framework/modules/chui_services/chui_services.js +39 -31
- package/framework/modules/chui_services/desktop.js +149 -30
- package/framework/modules/chui_sortable/chui_sortable.js +17 -12
- package/framework/modules/chui_validate/chui_validate.js +7 -4
- package/framework/tray_bar/chui_menu_items.js +136 -46
- package/index.d.ts +4814 -0
- package/index.js +449 -334
- package/package.json +79 -68
package/index.js
CHANGED
|
@@ -1,153 +1,194 @@
|
|
|
1
1
|
// === ИНСТРУМЕНТЫ ===
|
|
2
|
-
const {
|
|
2
|
+
const {
|
|
3
|
+
app,
|
|
4
|
+
BrowserWindow,
|
|
5
|
+
Menu,
|
|
6
|
+
Tray,
|
|
7
|
+
ipcMain,
|
|
8
|
+
ipcRenderer,
|
|
9
|
+
shell,
|
|
10
|
+
nativeTheme,
|
|
11
|
+
session,
|
|
12
|
+
webContents,
|
|
13
|
+
systemPreferences,
|
|
14
|
+
dialog,
|
|
15
|
+
} = require("electron");
|
|
3
16
|
// Одно хранилище настроек на модуль: его получает приложение через `require('chuijs').store`,
|
|
4
17
|
// из него читают тему, язык и история буфера, а `Settings` берёт его для своих значений по умолчанию
|
|
5
|
-
const {store} = require("./framework/modules/chui_store/chui_store");
|
|
18
|
+
const { store } = require("./framework/modules/chui_store/chui_store");
|
|
6
19
|
const path = require("path");
|
|
7
20
|
const fs = require("fs");
|
|
8
21
|
const os = require("os");
|
|
9
22
|
|
|
10
|
-
const request = require(
|
|
11
|
-
const {transliterate} = require("transliteration");
|
|
23
|
+
const request = require("@cypress/request");
|
|
24
|
+
const { transliterate } = require("transliteration");
|
|
12
25
|
let downloadSession = undefined;
|
|
13
26
|
// === === ===
|
|
14
27
|
// process.env
|
|
15
|
-
process.env[
|
|
28
|
+
process.env["ELECTRON_DISABLE_SECURITY_WARNINGS"] = "true";
|
|
16
29
|
// === === ===
|
|
17
30
|
|
|
18
31
|
//ПОЛЯ ВВОДА
|
|
19
|
-
const {TextInput} = require(
|
|
20
|
-
const {DateInput} = require(
|
|
21
|
-
const {NumberInput} = require(
|
|
22
|
-
const {EmailInput} = require(
|
|
23
|
-
const {PasswordInput} = require(
|
|
24
|
-
const {Select} = require(
|
|
25
|
-
const {ComboBox} = require(
|
|
26
|
-
const {TextArea} = require(
|
|
27
|
-
const {RadioButton} = require(
|
|
28
|
-
const {CheckBox} = require(
|
|
29
|
-
const {RadioGroup} = require(
|
|
30
|
-
const {Slider} = require(
|
|
31
|
-
const {Chips} = require(
|
|
32
|
+
const { TextInput } = require("./framework/components/chui_inputs/chui_text/text");
|
|
33
|
+
const { DateInput } = require("./framework/components/chui_inputs/chui_date/date");
|
|
34
|
+
const { NumberInput } = require("./framework/components/chui_inputs/chui_number/number");
|
|
35
|
+
const { EmailInput } = require("./framework/components/chui_inputs/chui_email/email");
|
|
36
|
+
const { PasswordInput } = require("./framework/components/chui_inputs/chui_password/password");
|
|
37
|
+
const { Select } = require("./framework/components/chui_inputs/chui_select_box/select_box");
|
|
38
|
+
const { ComboBox } = require("./framework/components/chui_inputs/chui_combo_box/combo_box");
|
|
39
|
+
const { TextArea } = require("./framework/components/chui_inputs/chui_text_area/text_area");
|
|
40
|
+
const { RadioButton } = require("./framework/components/chui_inputs/chui_radio_button/radio_button");
|
|
41
|
+
const { CheckBox } = require("./framework/components/chui_inputs/chui_check_box/check_box");
|
|
42
|
+
const { RadioGroup } = require("./framework/components/chui_radio_group/radio_group");
|
|
43
|
+
const { Slider } = require("./framework/components/chui_inputs/chui_slider/slider");
|
|
44
|
+
const { Chips } = require("./framework/components/chui_inputs/chui_chips/chips");
|
|
32
45
|
//==========
|
|
33
|
-
const {MenuItem} = require(
|
|
34
|
-
const {AppLayout, Route} = require(
|
|
35
|
-
const {Page} = require(
|
|
36
|
-
const {WebView} = require(
|
|
37
|
-
const {Button} = require(
|
|
38
|
-
const {Spinner} = require(
|
|
39
|
-
const {Icon, Icons} = require(
|
|
40
|
-
const {TextEditor} = require(
|
|
41
|
-
const {Badge} = require(
|
|
42
|
-
const {Divider} = require(
|
|
43
|
-
const {Link} = require(
|
|
44
|
-
const {Avatar} = require(
|
|
45
|
-
const {AvatarGroup} = require(
|
|
46
|
-
const {EmptyState} = require(
|
|
47
|
-
const {Result} = require(
|
|
48
|
-
const {Descriptions} = require(
|
|
49
|
-
const {Statistic} = require(
|
|
50
|
-
const {Backtop} = require(
|
|
51
|
-
const {Affix} = require(
|
|
52
|
-
const {StickyBar} = require(
|
|
53
|
-
const {Watermark} = require(
|
|
54
|
-
const {ShortcutHelp} = require(
|
|
55
|
-
const {Tooltip} = require(
|
|
56
|
-
const {Calendar} = require(
|
|
57
|
-
const {Notification} = require(
|
|
58
|
-
const {UpdateNotification} = require("./framework/components/chui_notification/notification_update");
|
|
59
|
-
const {DownloadNotification} = require("./framework/components/chui_notification/notification_download");
|
|
60
|
-
const {Tabs, Tab} = require(
|
|
61
|
-
const {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const {
|
|
73
|
-
const {
|
|
74
|
-
const {
|
|
75
|
-
const {
|
|
76
|
-
const {
|
|
77
|
-
const {
|
|
78
|
-
const {
|
|
79
|
-
const {
|
|
80
|
-
const {
|
|
81
|
-
const {
|
|
82
|
-
const {
|
|
83
|
-
const {
|
|
84
|
-
const {
|
|
85
|
-
const {
|
|
86
|
-
const {
|
|
87
|
-
const {
|
|
88
|
-
const {
|
|
89
|
-
const {
|
|
90
|
-
const {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const {
|
|
103
|
-
const {
|
|
104
|
-
const {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const {
|
|
112
|
-
const {
|
|
113
|
-
const {
|
|
114
|
-
const {
|
|
115
|
-
const {
|
|
116
|
-
const {
|
|
117
|
-
const {
|
|
118
|
-
const {
|
|
119
|
-
const {
|
|
120
|
-
const {
|
|
121
|
-
const {
|
|
122
|
-
const {
|
|
123
|
-
const {
|
|
124
|
-
const {
|
|
125
|
-
const {
|
|
126
|
-
const {
|
|
127
|
-
const {
|
|
128
|
-
const {
|
|
129
|
-
const {
|
|
130
|
-
const {
|
|
131
|
-
const {
|
|
132
|
-
const {
|
|
133
|
-
const {
|
|
134
|
-
const {
|
|
135
|
-
const {
|
|
46
|
+
const { MenuItem } = require("./framework/tray_bar/chui_menu_items");
|
|
47
|
+
const { AppLayout, Route } = require("./framework/appLayout/default/chui_app_layout");
|
|
48
|
+
const { Page } = require("./framework/modules/chui_page/page");
|
|
49
|
+
const { WebView } = require("./framework/components/chui_webview/webview");
|
|
50
|
+
const { Button } = require("./framework/components/chui_button/button");
|
|
51
|
+
const { Spinner } = require("./framework/components/chui_spinner/spinner");
|
|
52
|
+
const { Icon, Icons } = require("./framework/components/chui_icons/icons");
|
|
53
|
+
const { TextEditor } = require("./framework/components/chui_text_editor/text_editor");
|
|
54
|
+
const { Badge } = require("./framework/components/chui_badge/badge");
|
|
55
|
+
const { Divider } = require("./framework/components/chui_divider/divider");
|
|
56
|
+
const { Link } = require("./framework/components/chui_link/link");
|
|
57
|
+
const { Avatar } = require("./framework/components/chui_avatar/avatar");
|
|
58
|
+
const { AvatarGroup } = require("./framework/components/chui_avatar_group/avatar_group");
|
|
59
|
+
const { EmptyState } = require("./framework/components/chui_empty_state/empty_state");
|
|
60
|
+
const { Result } = require("./framework/components/chui_result/result");
|
|
61
|
+
const { Descriptions } = require("./framework/components/chui_descriptions/descriptions");
|
|
62
|
+
const { Statistic } = require("./framework/components/chui_statistic/statistic");
|
|
63
|
+
const { Backtop } = require("./framework/components/chui_backtop/backtop");
|
|
64
|
+
const { Affix } = require("./framework/components/chui_affix/affix");
|
|
65
|
+
const { StickyBar } = require("./framework/components/chui_sticky_bar/sticky_bar");
|
|
66
|
+
const { Watermark } = require("./framework/components/chui_watermark/watermark");
|
|
67
|
+
const { ShortcutHelp } = require("./framework/components/chui_shortcut_help/shortcut_help");
|
|
68
|
+
const { Tooltip } = require("./framework/components/chui_tooltip/tooltip");
|
|
69
|
+
const { Calendar } = require("./framework/components/chui_calendar/calendar");
|
|
70
|
+
const { Notification } = require("./framework/components/chui_notification/notification");
|
|
71
|
+
const { UpdateNotification } = require("./framework/components/chui_notification/notification_update");
|
|
72
|
+
const { DownloadNotification } = require("./framework/components/chui_notification/notification_download");
|
|
73
|
+
const { Tabs, Tab } = require("./framework/components/chui_tabs/chui_tabs");
|
|
74
|
+
const {
|
|
75
|
+
BarGraph,
|
|
76
|
+
PieGraph,
|
|
77
|
+
LineGraph,
|
|
78
|
+
AreaGraph,
|
|
79
|
+
ScatterGraph,
|
|
80
|
+
Gauge,
|
|
81
|
+
Sparkline,
|
|
82
|
+
RadarGraph,
|
|
83
|
+
HeatmapGraph,
|
|
84
|
+
} = require("./framework/components/chui_graphs/graphs");
|
|
85
|
+
const { Toggle } = require("./framework/components/chui_inputs/chui_toggle/toggle");
|
|
86
|
+
const { ContentBlock } = require("./framework/components/chui_content_block/content_block");
|
|
87
|
+
const { Card } = require("./framework/components/chui_card/card");
|
|
88
|
+
const { Hero } = require("./framework/components/chui_hero/hero");
|
|
89
|
+
const { Skeleton } = require("./framework/components/chui_skeleton/skeleton");
|
|
90
|
+
const { Drawer } = require("./framework/components/chui_drawer/drawer");
|
|
91
|
+
const { ToastQueue, Toast } = require("./framework/components/chui_toast_queue/toast_queue");
|
|
92
|
+
const { ProgressBar } = require("./framework/components/chui_progress_bar/progress_bar");
|
|
93
|
+
const { Label } = require("./framework/components/chui_label/label");
|
|
94
|
+
const { Dialog } = require("./framework/components/chui_modal/modal");
|
|
95
|
+
const { Paragraph } = require("./framework/components/chui_paragraph/paragraph");
|
|
96
|
+
const { H } = require("./framework/components/chui_hx/hx");
|
|
97
|
+
const { DataGrid } = require("./framework/components/chui_data_grid/data_grid");
|
|
98
|
+
const { Details } = require("./framework/components/chui_details/details");
|
|
99
|
+
const { Accordion } = require("./framework/components/chui_accordion/accordion");
|
|
100
|
+
const { CodeBlock } = require("./framework/components/chui_code/code");
|
|
101
|
+
const { HtmlBlock } = require("./framework/components/chui_html_block/html_block");
|
|
102
|
+
const { sleep, render, getDefaultIcon, formatBytes } = require("./framework/modules/chui_functions");
|
|
103
|
+
const {
|
|
104
|
+
Shortcuts,
|
|
105
|
+
Clipboard,
|
|
106
|
+
RecentDocuments,
|
|
107
|
+
TaskbarProgress,
|
|
108
|
+
} = require("./framework/modules/chui_services/chui_services");
|
|
109
|
+
const {
|
|
110
|
+
SERVICES_CHANNELS,
|
|
111
|
+
BRIDGE_CHANNELS,
|
|
112
|
+
BRIDGE_ARGS,
|
|
113
|
+
APP_PATH_NAMES,
|
|
114
|
+
} = require("./framework/modules/chui_services/chui_channels");
|
|
115
|
+
const { Desktop } = require("./framework/modules/chui_services/desktop");
|
|
116
|
+
const { I18n } = require("./framework/modules/chui_i18n/chui_i18n");
|
|
117
|
+
const {
|
|
118
|
+
Shell,
|
|
119
|
+
Theme,
|
|
120
|
+
Locale,
|
|
121
|
+
ClipboardHistory: ClipboardHistoryService,
|
|
122
|
+
Print,
|
|
123
|
+
} = require("./framework/modules/chui_services/chui_services");
|
|
124
|
+
const { FileInput, AcceptTypes } = require("./framework/components/chui_inputs/chui_file/file");
|
|
125
|
+
const { TreeView } = require("./framework/components/chui_tree_view/tree_view");
|
|
126
|
+
const { ThemeToggle } = require("./framework/components/chui_theme_toggle/theme_toggle");
|
|
127
|
+
const { SegmentedControl } = require("./framework/components/chui_segmented_control/segmented_control");
|
|
128
|
+
const { Alert } = require("./framework/components/chui_alert/alert");
|
|
129
|
+
const { Kbd } = require("./framework/components/chui_kbd/kbd");
|
|
130
|
+
const { List, ListItem } = require("./framework/components/chui_list/list");
|
|
131
|
+
const { Popover } = require("./framework/components/chui_popover/popover");
|
|
132
|
+
const { Tour } = require("./framework/components/chui_tour/tour");
|
|
133
|
+
const { SplitButton } = require("./framework/components/chui_split_button/split_button");
|
|
134
|
+
const { Pagination } = require("./framework/components/chui_pagination/pagination");
|
|
135
|
+
const { Breadcrumb } = require("./framework/components/chui_breadcrumb/breadcrumb");
|
|
136
|
+
const { Stepper } = require("./framework/components/chui_stepper/stepper");
|
|
137
|
+
const { Timeline } = require("./framework/components/chui_timeline/timeline");
|
|
138
|
+
const { Rating } = require("./framework/components/chui_inputs/chui_rating/rating");
|
|
139
|
+
const { ColorPicker } = require("./framework/components/chui_inputs/chui_color_picker/color_picker");
|
|
140
|
+
const { TimeInput } = require("./framework/components/chui_inputs/chui_time/time");
|
|
141
|
+
const { DateTimeInput } = require("./framework/components/chui_inputs/chui_datetime/datetime");
|
|
142
|
+
const { DateRangeInput } = require("./framework/components/chui_inputs/chui_date_range/date_range");
|
|
143
|
+
const { HotkeyInput } = require("./framework/components/chui_inputs/chui_hotkey/hotkey");
|
|
144
|
+
const { MaskedInput } = require("./framework/components/chui_inputs/chui_masked/masked");
|
|
145
|
+
const { OtpInput } = require("./framework/components/chui_inputs/chui_otp/otp");
|
|
146
|
+
const { Transfer } = require("./framework/components/chui_transfer/transfer");
|
|
147
|
+
const { TreeTable } = require("./framework/components/chui_tree_table/tree_table");
|
|
148
|
+
const { SidebarNav } = require("./framework/components/chui_sidebar_nav/sidebar_nav");
|
|
149
|
+
const { MarkdownEditor } = require("./framework/components/chui_markdown_editor/markdown_editor");
|
|
150
|
+
const { DiffViewer } = require("./framework/components/chui_diff_viewer/diff_viewer");
|
|
151
|
+
const { JsonViewer } = require("./framework/components/chui_json_viewer/json_viewer");
|
|
152
|
+
const { JsonEditor } = require("./framework/components/chui_json_editor/json_editor");
|
|
153
|
+
const { QueryBuilder } = require("./framework/components/chui_query_builder/query_builder");
|
|
154
|
+
const { FileExplorer } = require("./framework/components/chui_file_explorer/file_explorer");
|
|
155
|
+
const { Settings } = require("./framework/components/chui_settings/settings");
|
|
156
|
+
const { DropZone } = require("./framework/components/chui_drop_zone/drop_zone");
|
|
157
|
+
const { ClipboardHistory } = require("./framework/components/chui_clipboard_history/clipboard_history");
|
|
158
|
+
const { PrintButton } = require("./framework/components/chui_print_button/print_button");
|
|
159
|
+
const { Splitter } = require("./framework/components/chui_splitter/splitter");
|
|
160
|
+
const { Scheduler } = require("./framework/components/chui_scheduler/scheduler");
|
|
161
|
+
const { Gantt } = require("./framework/components/chui_gantt/gantt");
|
|
162
|
+
const { Kanban } = require("./framework/components/chui_kanban/kanban");
|
|
163
|
+
const { CodeEditor } = require("./framework/components/chui_code_editor/code_editor");
|
|
164
|
+
const { ProgressRing } = require("./framework/components/chui_progress_ring/progress_ring");
|
|
165
|
+
const { Toolbar } = require("./framework/components/chui_toolbar/toolbar");
|
|
166
|
+
const { StatusBar } = require("./framework/components/chui_status_bar/status_bar");
|
|
167
|
+
const { Sortable } = require("./framework/modules/chui_sortable/chui_sortable");
|
|
168
|
+
const { Form } = require("./framework/components/chui_form/form");
|
|
169
|
+
const { SlideShow } = require("./framework/components/chui_slideshow/slideshow");
|
|
170
|
+
const { FieldSet } = require("./framework/components/chui_fieldset/fieldset");
|
|
171
|
+
const { Popup } = require("./framework/components/chui_popups/popups");
|
|
172
|
+
const { TelegramBot } = require("./framework/components/telegram_bot/chui_telegram_bot");
|
|
173
|
+
const { MenuBar } = require("./framework/components/chui_menu_bar/menu_bar");
|
|
174
|
+
const { CommandPalette } = require("./framework/components/chui_command_palette/command_palette");
|
|
136
175
|
const { ContextMenu } = require("./framework/components/chui_context_menu/context_menu");
|
|
137
|
-
const {Image} = require(
|
|
138
|
-
const {Audio} = require("./framework/components/chui_media/audio");
|
|
139
|
-
const {Video} = require("./framework/components/chui_media/video");
|
|
140
|
-
const {CustomElement} = require("./framework/components/chui_custom_element/custom_element");
|
|
141
|
-
const {Console} = require("./framework/components/chui_console/console");
|
|
142
|
-
const {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const {
|
|
146
|
-
const {
|
|
147
|
-
const {
|
|
148
|
-
const {
|
|
149
|
-
const {
|
|
150
|
-
const {
|
|
176
|
+
const { Image } = require("./framework/components/chui_media/image");
|
|
177
|
+
const { Audio } = require("./framework/components/chui_media/audio");
|
|
178
|
+
const { Video } = require("./framework/components/chui_media/video");
|
|
179
|
+
const { CustomElement } = require("./framework/components/chui_custom_element/custom_element");
|
|
180
|
+
const { Console } = require("./framework/components/chui_console/console");
|
|
181
|
+
const {
|
|
182
|
+
DownloadProgressNotification,
|
|
183
|
+
} = require("./framework/components/chui_notification/notification_download_progress");
|
|
184
|
+
const { MultiComboBox } = require("./framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box");
|
|
185
|
+
const { Mention } = require("./framework/components/chui_inputs/chui_mention/mention");
|
|
186
|
+
const { Chat } = require("./framework/components/chui_chat/chat");
|
|
187
|
+
const { ActionSheet } = require("./framework/components/chui_action_sheet/action_sheet");
|
|
188
|
+
const { ImageCompare } = require("./framework/components/chui_media/image_compare");
|
|
189
|
+
const { OrgChart } = require("./framework/components/chui_org_chart/org_chart");
|
|
190
|
+
const { QRCode } = require("./framework/components/chui_qrcode/qrcode");
|
|
191
|
+
const { Log } = require("./framework/modules/chui_logger/chui_logger");
|
|
151
192
|
const url = require("node:url");
|
|
152
193
|
|
|
153
194
|
/** Код исполняется на странице (renderer), а не в main: от этого зависит доступ к модулям Electron */
|
|
@@ -155,6 +196,18 @@ function inRenderer() {
|
|
|
155
196
|
return process !== undefined && process.type === "renderer";
|
|
156
197
|
}
|
|
157
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Путь приложения по имени из белого списка.
|
|
201
|
+
*
|
|
202
|
+
* Одно правило на два канала (`APP_PATH` и `APP_PATH_SYNC`): странице не должен быть доступен
|
|
203
|
+
* произвольный каталог системы, поэтому всё, что вне `APP_PATH_NAMES`, main отклоняет. Сам
|
|
204
|
+
* `app.getPath` синхронный и без диска — именно поэтому путь можно отдавать значением.
|
|
205
|
+
*/
|
|
206
|
+
function appPathByName(name = String()) {
|
|
207
|
+
if (APP_PATH_NAMES.includes(name) === false) throw new Error(`Desktop.app.path: имя «${name}» вне белого списка`);
|
|
208
|
+
return app.getPath(name);
|
|
209
|
+
}
|
|
210
|
+
|
|
158
211
|
//VARS
|
|
159
212
|
let isQuiting = false;
|
|
160
213
|
|
|
@@ -167,7 +220,8 @@ class Main {
|
|
|
167
220
|
* Строгая политика для безопасных окон: скрипты и стили только свои (и файлы приложения),
|
|
168
221
|
* никаких внешних источников, `connect-src 'none'` — окну не нужна сеть.
|
|
169
222
|
*/
|
|
170
|
-
static SECURE_CSP =
|
|
223
|
+
static SECURE_CSP =
|
|
224
|
+
"default-src 'none'; script-src 'self' file:; style-src 'self' file: 'unsafe-inline'; img-src 'self' file: data: blob:; font-src 'self' file: data:; media-src 'self' file: data: blob:; connect-src 'none'";
|
|
171
225
|
/**
|
|
172
226
|
* Разметка страницы окна: пустая оболочка без собственного кода — всё приходит из
|
|
173
227
|
* preload'а приложения (обычный режим) или из моста (`security: {contextIsolation: true}`,
|
|
@@ -203,42 +257,46 @@ class Main {
|
|
|
203
257
|
#updaterListening = false;
|
|
204
258
|
#lastUpdateInfo = undefined;
|
|
205
259
|
#onShowSystemNotification = (e, title, body) => {
|
|
206
|
-
let {Notification} = require(
|
|
207
|
-
new Notification({title, body}).show();
|
|
208
|
-
}
|
|
260
|
+
let { Notification } = require("electron");
|
|
261
|
+
new Notification({ title, body }).show();
|
|
262
|
+
};
|
|
209
263
|
#onSendLogText = (e, text, type) => {
|
|
210
264
|
if (type === "info") {
|
|
211
|
-
console.info(text)
|
|
265
|
+
console.info(text);
|
|
212
266
|
} else if (type === "error") {
|
|
213
|
-
console.error(text)
|
|
267
|
+
console.error(text);
|
|
214
268
|
}
|
|
215
|
-
this.#writeLog(text)
|
|
216
|
-
}
|
|
269
|
+
this.#writeLog(text);
|
|
270
|
+
};
|
|
217
271
|
#onUpdateInstallConfirm = (e, check) => {
|
|
218
272
|
if (check) {
|
|
219
273
|
Log.info("Установка обновления...");
|
|
220
274
|
require("electron-updater").autoUpdater.quitAndInstall();
|
|
221
275
|
}
|
|
222
|
-
}
|
|
276
|
+
};
|
|
223
277
|
#onUpdateDownloaded = async () => {
|
|
224
278
|
await this.#sendNotificationUpdateLoadClose();
|
|
225
279
|
await this.#sendNotificationUpdate(this.#appName, I18n.t("appLayout.update.downloaded"));
|
|
226
280
|
setTimeout(async () => await this.#sendNotificationUpdateClose(), 3000);
|
|
227
281
|
Log.info("Обновление скачано!");
|
|
228
|
-
const version =
|
|
282
|
+
const version =
|
|
283
|
+
this.#lastUpdateInfo === undefined ? app.getVersion() : this.#lastUpdateInfo.versionInfo.version;
|
|
229
284
|
this.#window.webContents.send("checkUpdatesTrue", true, version);
|
|
230
|
-
}
|
|
285
|
+
};
|
|
231
286
|
// Глобальные обработчики ошибок процесса: регистрируются один раз, снимаются в stop()/restart()
|
|
232
287
|
#processHandlersRegistered = false;
|
|
233
288
|
// Десктоп-сервисы (буфер, недавние, прогресс, глобальные клавиши) и их подписки по окнам
|
|
234
289
|
#services_enabled = false;
|
|
235
290
|
#service_handlers = [];
|
|
291
|
+
// Синхронные каналы снимаются не `removeHandler`, а `removeListener`: они зарегистрированы
|
|
292
|
+
// через `ipcMain.on` — см. `#handleSync`
|
|
293
|
+
#service_sync_handlers = [];
|
|
236
294
|
#shortcut_subscribers = new Map();
|
|
237
295
|
#shortcut_watchers = new Map();
|
|
238
296
|
#progress_windows = new Map();
|
|
239
297
|
#on_theme_updated = undefined;
|
|
240
298
|
// Безопасный режим: preload-мост, contextIsolation и CSP вместо Node в рендерере
|
|
241
|
-
#security = {contextIsolation: false, csp: false, channels: []};
|
|
299
|
+
#security = { contextIsolation: false, csp: false, channels: [] };
|
|
242
300
|
#secure_contents = new Set();
|
|
243
301
|
#bridge_enabled = false;
|
|
244
302
|
#window_actions_bound = false;
|
|
@@ -246,17 +304,17 @@ class Main {
|
|
|
246
304
|
#page_message_handlers = new Map();
|
|
247
305
|
#onUncaughtException = (error) => {
|
|
248
306
|
Main.#logProcessError("Необработанное исключение", error);
|
|
249
|
-
}
|
|
307
|
+
};
|
|
250
308
|
#onUnhandledRejection = (reason) => {
|
|
251
309
|
Main.#logProcessError("Необработанный reject промиса", reason);
|
|
252
|
-
}
|
|
310
|
+
};
|
|
253
311
|
static #logProcessError(prefix, value) {
|
|
254
312
|
const text = `${prefix}: ${Main.#formatError(value)}`;
|
|
255
313
|
try {
|
|
256
|
-
Log.error(text)
|
|
314
|
+
Log.error(text);
|
|
257
315
|
} catch (e) {
|
|
258
316
|
// Сам обработчик ошибок падать не должен (например, недоступен userData для лога)
|
|
259
|
-
console.error(text, e)
|
|
317
|
+
console.error(text, e);
|
|
260
318
|
}
|
|
261
319
|
}
|
|
262
320
|
static #formatError(value) {
|
|
@@ -274,51 +332,53 @@ class Main {
|
|
|
274
332
|
const target = path.join(this.#downloadPath, item.getFilename());
|
|
275
333
|
if (fs.existsSync(target)) return;
|
|
276
334
|
try {
|
|
277
|
-
if (!fs.existsSync(this.#downloadPath)) fs.mkdirSync(this.#downloadPath, {recursive: true});
|
|
335
|
+
if (!fs.existsSync(this.#downloadPath)) fs.mkdirSync(this.#downloadPath, { recursive: true });
|
|
278
336
|
item.setSavePath(target);
|
|
279
337
|
} catch (error) {
|
|
280
338
|
Log.error(`Не удалось сохранить загрузку в ${this.#downloadPath}: ${Main.#formatError(error)}`);
|
|
281
339
|
}
|
|
282
|
-
}
|
|
340
|
+
};
|
|
283
341
|
|
|
284
|
-
constructor(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
342
|
+
constructor(
|
|
343
|
+
options = {
|
|
344
|
+
name: String(),
|
|
345
|
+
sizes: { height: Number(), width: Number(), minHeight: Number(), minWidth: Number() },
|
|
346
|
+
render: String(),
|
|
347
|
+
devTools: Boolean(),
|
|
348
|
+
webSecurity: Boolean(),
|
|
349
|
+
resizable: Boolean(),
|
|
350
|
+
security: { contextIsolation: Boolean(), csp: Boolean(), channels: [] },
|
|
351
|
+
paths: {
|
|
352
|
+
downloadPath: String(),
|
|
353
|
+
},
|
|
294
354
|
}
|
|
295
|
-
|
|
355
|
+
) {
|
|
296
356
|
this.#app_icon = options.icon;
|
|
297
357
|
if (this.#app_icon === undefined) {
|
|
298
358
|
if (process.platform === "darwin") {
|
|
299
|
-
this.#app_icon = Main.#resizeIconTray(getDefaultIcon())
|
|
359
|
+
this.#app_icon = Main.#resizeIconTray(getDefaultIcon());
|
|
300
360
|
} else {
|
|
301
361
|
this.#app_icon = getDefaultIcon();
|
|
302
362
|
}
|
|
303
363
|
} else {
|
|
304
364
|
if (process.platform === "darwin") {
|
|
305
|
-
this.#app_icon = Main.#resizeIconTray(options.icon)
|
|
365
|
+
this.#app_icon = Main.#resizeIconTray(options.icon);
|
|
306
366
|
} else {
|
|
307
367
|
this.#app_icon = options.icon;
|
|
308
368
|
}
|
|
309
369
|
}
|
|
310
370
|
// app.commandLine.appendSwitch('--enable-features', 'OverlayScrollbar')
|
|
311
|
-
app.commandLine.appendSwitch(
|
|
312
|
-
app.commandLine.appendSwitch(
|
|
371
|
+
app.commandLine.appendSwitch("disable-hid-blocklist");
|
|
372
|
+
app.commandLine.appendSwitch("enable-features=OverlayScrollbar");
|
|
313
373
|
// app.commandLine.appendSwitch("disable-http-cache");
|
|
314
|
-
app.commandLine.appendSwitch(
|
|
315
|
-
app.commandLine.appendSwitch(
|
|
316
|
-
app.commandLine.appendSwitch(
|
|
317
|
-
app.commandLine.appendSwitch(
|
|
318
|
-
app.commandLine.appendSwitch(
|
|
319
|
-
app.commandLine.appendSwitch(
|
|
320
|
-
app.commandLine.appendSwitch(
|
|
321
|
-
app.commandLine.appendSwitch(
|
|
374
|
+
app.commandLine.appendSwitch("enable-transparent-visuals");
|
|
375
|
+
app.commandLine.appendSwitch("enable-gpu-rasterization", "true");
|
|
376
|
+
app.commandLine.appendSwitch("enable-native-gpu-memory-buffers", "true");
|
|
377
|
+
app.commandLine.appendSwitch("high-dpi-support", "true");
|
|
378
|
+
app.commandLine.appendSwitch("device-scale-factor", "true");
|
|
379
|
+
app.commandLine.appendSwitch("disable-touch-adjustment", "true");
|
|
380
|
+
app.commandLine.appendSwitch("main-frame-resizes-are-orientation-changes", "true");
|
|
381
|
+
app.commandLine.appendSwitch("disable-pinch", "true");
|
|
322
382
|
|
|
323
383
|
// Без опции загрузки идут обычным путём Electron: раньше значение вычислялось и не использовалось
|
|
324
384
|
this.#downloadPath = options.paths === undefined ? undefined : options.paths.downloadPath;
|
|
@@ -339,7 +399,7 @@ class Main {
|
|
|
339
399
|
}
|
|
340
400
|
|
|
341
401
|
static #resizeIconTray(image) {
|
|
342
|
-
return require(
|
|
402
|
+
return require("electron").nativeImage.createFromPath(image).resize({ width: 16, height: 16 });
|
|
343
403
|
}
|
|
344
404
|
|
|
345
405
|
/** Опции безопасности окна: по умолчанию включён привычный режим (Node в рендерере) */
|
|
@@ -347,7 +407,7 @@ class Main {
|
|
|
347
407
|
return {
|
|
348
408
|
contextIsolation: security.contextIsolation === true,
|
|
349
409
|
csp: security.csp === undefined ? true : security.csp,
|
|
350
|
-
channels: security.channels === undefined ? [] : security.channels
|
|
410
|
+
channels: security.channels === undefined ? [] : security.channels,
|
|
351
411
|
};
|
|
352
412
|
}
|
|
353
413
|
|
|
@@ -409,10 +469,19 @@ class Main {
|
|
|
409
469
|
* (`createWindow()`) собираются одним кодом: у всех окон одинаковые webPreferences,
|
|
410
470
|
* иконка, поведение закрытия и подписка на `chui_resizable_false`.
|
|
411
471
|
*/
|
|
412
|
-
#buildWindow(
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
472
|
+
#buildWindow(
|
|
473
|
+
options = {
|
|
474
|
+
name: String(),
|
|
475
|
+
title: String(),
|
|
476
|
+
sizes: Object(),
|
|
477
|
+
render: String(),
|
|
478
|
+
parent: undefined,
|
|
479
|
+
security: Object(),
|
|
480
|
+
hideOnClose: Boolean(),
|
|
481
|
+
resizable: Boolean(),
|
|
482
|
+
devTools: Boolean(),
|
|
483
|
+
}
|
|
484
|
+
) {
|
|
416
485
|
const sizes = options.sizes === undefined ? {} : options.sizes;
|
|
417
486
|
const name = options.name === undefined ? Main.MAIN_WINDOW : options.name;
|
|
418
487
|
const resizable = options.resizable === undefined ? this.#resizable : options.resizable;
|
|
@@ -434,35 +503,35 @@ class Main {
|
|
|
434
503
|
// выполняется как обычный <script> документа (см. chui_bridge/preload.js)
|
|
435
504
|
webPreferences: secure
|
|
436
505
|
? {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
506
|
+
plugins: false,
|
|
507
|
+
nodeIntegration: false,
|
|
508
|
+
contextIsolation: true,
|
|
509
|
+
sandbox: false,
|
|
510
|
+
preload: Main.SECURE_PRELOAD,
|
|
511
|
+
additionalArguments: Main.#bridgeArguments(options.render, security),
|
|
512
|
+
spellcheck: false,
|
|
513
|
+
webviewTag: false,
|
|
514
|
+
webSecurity: this.#webSecurity,
|
|
515
|
+
nodeIntegrationInSubFrames: false,
|
|
516
|
+
}
|
|
448
517
|
: {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
518
|
+
plugins: false,
|
|
519
|
+
nodeIntegration: true,
|
|
520
|
+
contextIsolation: false,
|
|
521
|
+
// Рендерер окна: у дополнительных окон может быть свой скрипт
|
|
522
|
+
preload: options.render === undefined ? this.#renderer : options.render,
|
|
523
|
+
spellcheck: false,
|
|
524
|
+
webviewTag: true,
|
|
525
|
+
webSecurity: this.#webSecurity,
|
|
526
|
+
nodeIntegrationInSubFrames: true,
|
|
527
|
+
},
|
|
459
528
|
frame: false,
|
|
460
529
|
resizable: resizable,
|
|
461
530
|
minimizable: true,
|
|
462
531
|
maximizable: true,
|
|
463
532
|
center: true,
|
|
464
533
|
hasShadow: true,
|
|
465
|
-
parent: options.parent
|
|
534
|
+
parent: options.parent,
|
|
466
535
|
});
|
|
467
536
|
const window = this.#window;
|
|
468
537
|
const webContentsId = window.webContents.id;
|
|
@@ -497,7 +566,7 @@ class Main {
|
|
|
497
566
|
setTimeout(() => {
|
|
498
567
|
if (!window.isDestroyed()) window.show();
|
|
499
568
|
}, 650)
|
|
500
|
-
)
|
|
569
|
+
);
|
|
501
570
|
// Подписки глобальных клавиш привязаны к отправителю: окно закрылось — снимаем их
|
|
502
571
|
window.on("closed", () => {
|
|
503
572
|
if (this.#windows.get(name) === window) this.#windows.delete(name);
|
|
@@ -507,7 +576,7 @@ class Main {
|
|
|
507
576
|
});
|
|
508
577
|
|
|
509
578
|
if (options.hideOnClose === true) {
|
|
510
|
-
window.on(
|
|
579
|
+
window.on("close", (evt) => {
|
|
511
580
|
if (!isQuiting) evt.preventDefault();
|
|
512
581
|
window.hide();
|
|
513
582
|
});
|
|
@@ -522,7 +591,7 @@ class Main {
|
|
|
522
591
|
#bindBeforeQuit() {
|
|
523
592
|
if (this.#before_quit_bound) return;
|
|
524
593
|
this.#before_quit_bound = true;
|
|
525
|
-
app.on(
|
|
594
|
+
app.on("before-quit", () => {
|
|
526
595
|
isQuiting = true;
|
|
527
596
|
});
|
|
528
597
|
}
|
|
@@ -532,18 +601,19 @@ class Main {
|
|
|
532
601
|
if (this.#webSecurity || this.#web_request_bound) return;
|
|
533
602
|
this.#web_request_bound = true;
|
|
534
603
|
window.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
|
|
535
|
-
const {requestHeaders} = details;
|
|
536
|
-
Main.#keyToChangeLower(requestHeaders,
|
|
537
|
-
Main.#keyToChangeLower(requestHeaders,
|
|
538
|
-
callback({requestHeaders});
|
|
539
|
-
}
|
|
604
|
+
const { requestHeaders } = details;
|
|
605
|
+
Main.#keyToChangeLower(requestHeaders, "Access-Control-Allow-Origin", ["*"]);
|
|
606
|
+
Main.#keyToChangeLower(requestHeaders, "X-Frame-Options", ["*"]);
|
|
607
|
+
callback({ requestHeaders });
|
|
608
|
+
});
|
|
540
609
|
window.webContents.session.webRequest.onHeadersReceived((details, callback) => {
|
|
541
|
-
const {responseHeaders} = details;
|
|
542
|
-
Main.#keyToChangeLower(responseHeaders,
|
|
543
|
-
Main.#keyToChangeLower(responseHeaders,
|
|
544
|
-
Main.#keyToChangeLower(responseHeaders,
|
|
610
|
+
const { responseHeaders } = details;
|
|
611
|
+
Main.#keyToChangeLower(responseHeaders, "Access-Control-Allow-Origin", ["*"]);
|
|
612
|
+
Main.#keyToChangeLower(responseHeaders, "Access-Control-Allow-Headers", ["*"]);
|
|
613
|
+
Main.#keyToChangeLower(responseHeaders, "X-Frame-Options", ["*"]);
|
|
545
614
|
callback({
|
|
546
|
-
responseHeaders,
|
|
615
|
+
responseHeaders,
|
|
616
|
+
cancel: false,
|
|
547
617
|
});
|
|
548
618
|
});
|
|
549
619
|
}
|
|
@@ -560,10 +630,19 @@ class Main {
|
|
|
560
630
|
* main.sendTo('preview', 'preview_update', payload);
|
|
561
631
|
* ```
|
|
562
632
|
*/
|
|
563
|
-
async createWindow(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
633
|
+
async createWindow(
|
|
634
|
+
options = {
|
|
635
|
+
name: String(),
|
|
636
|
+
title: String(),
|
|
637
|
+
sizes: Object(),
|
|
638
|
+
render: String(),
|
|
639
|
+
parent: undefined,
|
|
640
|
+
security: Object(),
|
|
641
|
+
hideOnClose: Boolean(),
|
|
642
|
+
resizable: Boolean(),
|
|
643
|
+
devTools: Boolean(),
|
|
644
|
+
}
|
|
645
|
+
) {
|
|
567
646
|
await app.whenReady();
|
|
568
647
|
this.enableServices();
|
|
569
648
|
return this.#buildWindow(options);
|
|
@@ -584,7 +663,7 @@ class Main {
|
|
|
584
663
|
return [...this.#windows].map(([name, window]) => ({
|
|
585
664
|
name: name,
|
|
586
665
|
window: window,
|
|
587
|
-
secure: this.#secure_contents.has(window.webContents.id)
|
|
666
|
+
secure: this.#secure_contents.has(window.webContents.id),
|
|
588
667
|
}));
|
|
589
668
|
}
|
|
590
669
|
|
|
@@ -642,8 +721,8 @@ class Main {
|
|
|
642
721
|
progress: new TaskbarProgress(),
|
|
643
722
|
theme: new Theme(store),
|
|
644
723
|
locale: new Locale(store),
|
|
645
|
-
clipboard_history: new ClipboardHistoryService({store: store}),
|
|
646
|
-
print: new Print()
|
|
724
|
+
clipboard_history: new ClipboardHistoryService({ store: store }),
|
|
725
|
+
print: new Print(),
|
|
647
726
|
};
|
|
648
727
|
// Сохранённая тема применяется до создания окна: иначе при запуске была бы видна
|
|
649
728
|
// вспышка системной палитры
|
|
@@ -695,23 +774,57 @@ class Main {
|
|
|
695
774
|
});
|
|
696
775
|
// Приложение и системные диалоги для страницы: Electron советует IPC вместо `remote`.
|
|
697
776
|
// Путь — только из белого списка, диалог и сессия — у окна-отправителя.
|
|
698
|
-
this.#handle(SERVICES_CHANNELS.APP_PATH, (event, name) =>
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
777
|
+
this.#handle(SERVICES_CHANNELS.APP_PATH, (event, name) => appPathByName(name));
|
|
778
|
+
// `Desktop.app.path` отвечает значением, а не промисом, поэтому у пути есть второй,
|
|
779
|
+
// синхронный канал: `sendSync` ждёт `event.returnValue`, а не ответ `handle`.
|
|
780
|
+
// Асинхронный канал выше оставлен — его ключ есть в карте `window.chui.services`
|
|
781
|
+
this.#handleSync(SERVICES_CHANNELS.APP_PATH_SYNC, (event, name) => appPathByName(name));
|
|
702
782
|
this.#handle(SERVICES_CHANNELS.APP_INFO, () => ({
|
|
703
783
|
name: app.getName(),
|
|
704
784
|
version: app.getVersion(),
|
|
705
785
|
locale: app.getLocale(),
|
|
706
786
|
systemLocale: app.getSystemLocale(),
|
|
707
|
-
isPackaged: app.isPackaged
|
|
787
|
+
isPackaged: app.isPackaged,
|
|
708
788
|
}));
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
789
|
+
// Закрытие и перезапуск со страницы: страница — код самого приложения, поэтому кнопке
|
|
790
|
+
// «Выход» не нужен свой канал в каждом проекте. Идут через `Main.stop()`/`restart()` —
|
|
791
|
+
// те же шаги, что у пункта меню: снимаются обработчики сервисов, глобальные клавиши и
|
|
792
|
+
// подписки, а не просто закрывается окно. Ответ уходит странице до выхода
|
|
793
|
+
// (`setImmediate`): иначе промис отваливался бы с «Render frame was disposed», и
|
|
794
|
+
// `await Desktop.app.quit()` со страницы выглядел бы ошибкой
|
|
795
|
+
this.#handle(SERVICES_CHANNELS.APP_QUIT, () => {
|
|
796
|
+
setImmediate(() => this.stop());
|
|
797
|
+
return true;
|
|
798
|
+
});
|
|
799
|
+
this.#handle(SERVICES_CHANNELS.APP_RESTART, () => {
|
|
800
|
+
setImmediate(() => this.restart());
|
|
801
|
+
return true;
|
|
802
|
+
});
|
|
803
|
+
// У закрытия и перезапуска есть и синхронные каналы: `Desktop.app.quit()`/`restart()`
|
|
804
|
+
// отвечают значением, а не промисом — как `Desktop.app.path`. Выход по-прежнему
|
|
805
|
+
// откладывается `setImmediate`, чтобы `event.returnValue` успел уйти странице.
|
|
806
|
+
this.#handleSync(SERVICES_CHANNELS.APP_QUIT_SYNC, () => {
|
|
807
|
+
setImmediate(() => this.stop());
|
|
808
|
+
return true;
|
|
809
|
+
});
|
|
810
|
+
this.#handleSync(SERVICES_CHANNELS.APP_RESTART_SYNC, () => {
|
|
811
|
+
setImmediate(() => this.restart());
|
|
812
|
+
return true;
|
|
813
|
+
});
|
|
814
|
+
this.#handle(SERVICES_CHANNELS.DIALOG_OPEN, (event, options) =>
|
|
815
|
+
Main.#showDialog(event, "showOpenDialog", options)
|
|
816
|
+
);
|
|
817
|
+
this.#handle(SERVICES_CHANNELS.DIALOG_SAVE, (event, options) =>
|
|
818
|
+
Main.#showDialog(event, "showSaveDialog", options)
|
|
819
|
+
);
|
|
820
|
+
this.#handle(SERVICES_CHANNELS.DIALOG_MESSAGE, (event, options) =>
|
|
821
|
+
Main.#showDialog(event, "showMessageBox", options)
|
|
822
|
+
);
|
|
712
823
|
this.#handle(SERVICES_CHANNELS.SESSION_CACHE_SIZE, (event) => event.sender.session.getCacheSize());
|
|
713
824
|
this.#handle(SERVICES_CHANNELS.SESSION_CLEAR_CACHE, (event) => event.sender.session.clearCache());
|
|
714
|
-
this.#handle(SERVICES_CHANNELS.SESSION_CLEAR_STORAGE, (event, options) =>
|
|
825
|
+
this.#handle(SERVICES_CHANNELS.SESSION_CLEAR_STORAGE, (event, options) =>
|
|
826
|
+
event.sender.session.clearStorageData(options)
|
|
827
|
+
);
|
|
715
828
|
this.#handle(SERVICES_CHANNELS.RECENT_ADD, (event, path, name) => {
|
|
716
829
|
this.services.recent.add(path, name);
|
|
717
830
|
return true;
|
|
@@ -730,17 +843,26 @@ class Main {
|
|
|
730
843
|
return true;
|
|
731
844
|
});
|
|
732
845
|
this.#handle(SERVICES_CHANNELS.SHELL_OPEN_EXTERNAL, (event, url) => this.services.shell.openExternal(url));
|
|
733
|
-
this.#handle(SERVICES_CHANNELS.PRINT_PAGE, (event, options) =>
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
this.#handle(SERVICES_CHANNELS.
|
|
846
|
+
this.#handle(SERVICES_CHANNELS.PRINT_PAGE, (event, options) =>
|
|
847
|
+
this.services.print.page(BrowserWindow.fromWebContents(event.sender), this.#printOptions(event, options))
|
|
848
|
+
);
|
|
849
|
+
this.#handle(SERVICES_CHANNELS.PRINT_HTML, (event, html, options) =>
|
|
850
|
+
this.services.print.html(html, this.#printOptions(event, options))
|
|
851
|
+
);
|
|
852
|
+
this.#handle(SERVICES_CHANNELS.PRINT_PDF, (event, html, options) =>
|
|
853
|
+
this.services.print.pdf(html, this.#printOptions(event, options))
|
|
854
|
+
);
|
|
855
|
+
this.#handle(SERVICES_CHANNELS.THEME_GET, () => ({
|
|
856
|
+
theme: this.services.theme.get(),
|
|
857
|
+
source: this.services.theme.getSource(),
|
|
858
|
+
}));
|
|
737
859
|
this.#handle(SERVICES_CHANNELS.THEME_SET, (event, source) => {
|
|
738
860
|
this.services.theme.set(source);
|
|
739
|
-
return {theme: this.services.theme.get(), source: this.services.theme.getSource()};
|
|
861
|
+
return { theme: this.services.theme.get(), source: this.services.theme.getSource() };
|
|
740
862
|
});
|
|
741
863
|
this.#handle(SERVICES_CHANNELS.THEME_TOGGLE, () => {
|
|
742
864
|
this.services.theme.toggle();
|
|
743
|
-
return {theme: this.services.theme.get(), source: this.services.theme.getSource()};
|
|
865
|
+
return { theme: this.services.theme.get(), source: this.services.theme.getSource() };
|
|
744
866
|
});
|
|
745
867
|
this.#handle(SERVICES_CHANNELS.LOCALE_GET, () => this.services.locale.get());
|
|
746
868
|
this.#handle(SERVICES_CHANNELS.LOCALE_SET, (event, locale) => {
|
|
@@ -752,7 +874,9 @@ class Main {
|
|
|
752
874
|
this.#emitLocale(applied);
|
|
753
875
|
return applied;
|
|
754
876
|
});
|
|
755
|
-
this.#handle(SERVICES_CHANNELS.SHORTCUT_SUBSCRIBE, (event, accelerator) =>
|
|
877
|
+
this.#handle(SERVICES_CHANNELS.SHORTCUT_SUBSCRIBE, (event, accelerator) =>
|
|
878
|
+
this.#subscribeShortcut(event, accelerator)
|
|
879
|
+
);
|
|
756
880
|
this.#handle(SERVICES_CHANNELS.SHORTCUT_UNSUBSCRIBE, (event, accelerator) => {
|
|
757
881
|
this.#unsubscribeShortcut(event, accelerator);
|
|
758
882
|
return true;
|
|
@@ -767,6 +891,25 @@ class Main {
|
|
|
767
891
|
return this;
|
|
768
892
|
}
|
|
769
893
|
|
|
894
|
+
/**
|
|
895
|
+
* Синхронный канал: `ipcRenderer.sendSync` в странице ждёт `event.returnValue`, а не ответ
|
|
896
|
+
* `handle`, поэтому здесь `ipcMain.on`. Ответ — конверт `{value}`/`{error}`: у синхронного
|
|
897
|
+
* канала нет способа передать исключение, и без конверта страница получила бы `undefined`
|
|
898
|
+
* вместо причины отказа (см. `SERVICES_SYNC_CALLS` в chui_channels.js).
|
|
899
|
+
*/
|
|
900
|
+
#handleSync(channel = String(), handler = () => {}) {
|
|
901
|
+
const listener = (event, ...args) => {
|
|
902
|
+
try {
|
|
903
|
+
event.returnValue = { value: handler(event, ...args) };
|
|
904
|
+
} catch (error) {
|
|
905
|
+
event.returnValue = { error: error instanceof Error ? error.message : String(error) };
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
ipcMain.on(channel, listener);
|
|
909
|
+
this.#service_sync_handlers.push([channel, listener]);
|
|
910
|
+
return this;
|
|
911
|
+
}
|
|
912
|
+
|
|
770
913
|
/**
|
|
771
914
|
* Включает мост безопасных окон (`contextBridge`): управление окном, тема и прикладные
|
|
772
915
|
* сообщения по белому списку каналов. Вызывается сам при создании безопасного окна.
|
|
@@ -792,7 +935,7 @@ class Main {
|
|
|
792
935
|
isMaximized: window.isMaximized(),
|
|
793
936
|
isMinimized: window.isMinimized(),
|
|
794
937
|
isFullScreen: window.isFullScreen(),
|
|
795
|
-
isFocused: window.isFocused()
|
|
938
|
+
isFocused: window.isFocused(),
|
|
796
939
|
};
|
|
797
940
|
});
|
|
798
941
|
return this;
|
|
@@ -806,7 +949,7 @@ class Main {
|
|
|
806
949
|
this.#handle(BRIDGE_CHANNELS.LOCALE_GET, () => this.services.locale.get());
|
|
807
950
|
this.#handle(BRIDGE_CHANNELS.MESSAGE, (event, channel, ...args) => {
|
|
808
951
|
const handler = this.#page_message_handlers.get(channel);
|
|
809
|
-
if (handler === undefined) return {handled: false};
|
|
952
|
+
if (handler === undefined) return { handled: false };
|
|
810
953
|
return handler(...args, event);
|
|
811
954
|
});
|
|
812
955
|
this.#bindThemeEvents();
|
|
@@ -956,7 +1099,7 @@ class Main {
|
|
|
956
1099
|
* поэтому `parent` берём из события, а не из запроса страницы.
|
|
957
1100
|
*/
|
|
958
1101
|
#printOptions(event, options = Object()) {
|
|
959
|
-
return {...options, parent: BrowserWindow.fromWebContents(event.sender)};
|
|
1102
|
+
return { ...options, parent: BrowserWindow.fromWebContents(event.sender) };
|
|
960
1103
|
}
|
|
961
1104
|
|
|
962
1105
|
#emitShortcut(accelerator = String()) {
|
|
@@ -1000,15 +1143,15 @@ class Main {
|
|
|
1000
1143
|
#hideAndShow() {
|
|
1001
1144
|
const window = this.#targetWindow();
|
|
1002
1145
|
if (window === undefined) return;
|
|
1003
|
-
let visible = window.isVisible()
|
|
1004
|
-
let focus = window.isFocused()
|
|
1146
|
+
let visible = window.isVisible();
|
|
1147
|
+
let focus = window.isFocused();
|
|
1005
1148
|
|
|
1006
1149
|
if (visible && focus) {
|
|
1007
|
-
window.hide()
|
|
1150
|
+
window.hide();
|
|
1008
1151
|
} else if (!visible && !focus) {
|
|
1009
|
-
window.show()
|
|
1152
|
+
window.show();
|
|
1010
1153
|
} else {
|
|
1011
|
-
window.focus()
|
|
1154
|
+
window.focus();
|
|
1012
1155
|
}
|
|
1013
1156
|
}
|
|
1014
1157
|
|
|
@@ -1026,17 +1169,17 @@ class Main {
|
|
|
1026
1169
|
|
|
1027
1170
|
stop() {
|
|
1028
1171
|
this.#removeGlobalHandlers();
|
|
1029
|
-
if (process.platform !==
|
|
1172
|
+
if (process.platform !== "darwin") {
|
|
1030
1173
|
app.quit();
|
|
1031
1174
|
} else {
|
|
1032
|
-
app.exit(0)
|
|
1175
|
+
app.exit(0);
|
|
1033
1176
|
}
|
|
1034
1177
|
}
|
|
1035
1178
|
|
|
1036
1179
|
restart() {
|
|
1037
1180
|
this.#removeGlobalHandlers();
|
|
1038
1181
|
app.relaunch();
|
|
1039
|
-
app.exit(0)
|
|
1182
|
+
app.exit(0);
|
|
1040
1183
|
}
|
|
1041
1184
|
|
|
1042
1185
|
#removeGlobalHandlers() {
|
|
@@ -1051,6 +1194,8 @@ class Main {
|
|
|
1051
1194
|
// Десктоп-сервисы: снимаем обработчики IPC, подписки клавиш и сами клавиши
|
|
1052
1195
|
for (const [channel] of this.#service_handlers) ipcMain.removeHandler(channel);
|
|
1053
1196
|
this.#service_handlers = [];
|
|
1197
|
+
for (const [channel, listener] of this.#service_sync_handlers) ipcMain.removeListener(channel, listener);
|
|
1198
|
+
this.#service_sync_handlers = [];
|
|
1054
1199
|
this.#shortcut_subscribers.clear();
|
|
1055
1200
|
this.#shortcut_watchers.clear();
|
|
1056
1201
|
this.#progress_windows.clear();
|
|
@@ -1067,7 +1212,7 @@ class Main {
|
|
|
1067
1212
|
this.#window_actions_bound = false;
|
|
1068
1213
|
if (this.#updaterListening) {
|
|
1069
1214
|
this.#updaterListening = false;
|
|
1070
|
-
require("electron-updater").autoUpdater.removeListener(
|
|
1215
|
+
require("electron-updater").autoUpdater.removeListener("update-downloaded", this.#onUpdateDownloaded);
|
|
1071
1216
|
}
|
|
1072
1217
|
if (this.#processHandlersRegistered) {
|
|
1073
1218
|
this.#processHandlersRegistered = false;
|
|
@@ -1077,7 +1222,7 @@ class Main {
|
|
|
1077
1222
|
this.#ipcRegistered = false;
|
|
1078
1223
|
}
|
|
1079
1224
|
|
|
1080
|
-
start(options = {hideOnClose: Boolean(), globalMenu: [], tray: [], extensions: []}) {
|
|
1225
|
+
start(options = { hideOnClose: Boolean(), globalMenu: [], tray: [], extensions: [] }) {
|
|
1081
1226
|
nativeTheme.themeSource = "system";
|
|
1082
1227
|
// Обработчики процесса — один раз на экземпляр Main (иначе копились при повторном start())
|
|
1083
1228
|
if (this.#ipcRegistered === false) {
|
|
@@ -1094,7 +1239,7 @@ class Main {
|
|
|
1094
1239
|
|
|
1095
1240
|
app.whenReady().then(() => {
|
|
1096
1241
|
session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) => {
|
|
1097
|
-
if (permission ===
|
|
1242
|
+
if (permission === "media") {
|
|
1098
1243
|
callback(true); // Approve microphone/camera access
|
|
1099
1244
|
} else {
|
|
1100
1245
|
callback(false);
|
|
@@ -1102,49 +1247,53 @@ class Main {
|
|
|
1102
1247
|
});
|
|
1103
1248
|
|
|
1104
1249
|
if (options.extensions) {
|
|
1105
|
-
for (let extension of options.extensions)
|
|
1250
|
+
for (let extension of options.extensions)
|
|
1251
|
+
session.defaultSession
|
|
1252
|
+
.loadExtension(extension)
|
|
1253
|
+
.then((r) => Log.info(r))
|
|
1254
|
+
.catch((e) => Log.error(e));
|
|
1106
1255
|
}
|
|
1107
1256
|
if (options.tray) {
|
|
1108
1257
|
this.#tray = new Tray(this.#app_icon);
|
|
1109
1258
|
const context = Menu.buildFromTemplate(options.tray);
|
|
1110
1259
|
this.#tray.setContextMenu(context);
|
|
1111
1260
|
|
|
1112
|
-
this.#tray.on("click", () => this.#hideAndShow())
|
|
1261
|
+
this.#tray.on("click", () => this.#hideAndShow());
|
|
1113
1262
|
}
|
|
1114
1263
|
if (options.globalMenu) {
|
|
1115
|
-
const menu = Menu.buildFromTemplate(options.globalMenu)
|
|
1116
|
-
Menu.setApplicationMenu(menu)
|
|
1264
|
+
const menu = Menu.buildFromTemplate(options.globalMenu);
|
|
1265
|
+
Menu.setApplicationMenu(menu);
|
|
1117
1266
|
} else {
|
|
1118
|
-
Menu.setApplicationMenu(null)
|
|
1267
|
+
Menu.setApplicationMenu(null);
|
|
1119
1268
|
}
|
|
1120
1269
|
this.enableServices();
|
|
1121
|
-
this.#buildWindow({name: Main.MAIN_WINDOW, hideOnClose: options.hideOnClose});
|
|
1122
|
-
})
|
|
1270
|
+
this.#buildWindow({ name: Main.MAIN_WINDOW, hideOnClose: options.hideOnClose });
|
|
1271
|
+
});
|
|
1123
1272
|
}
|
|
1124
1273
|
|
|
1125
1274
|
#writeLog(text) {
|
|
1126
|
-
let today = new Date().toLocaleDateString().replace("/", ".")
|
|
1127
|
-
let log_dir_path = path.join(app.getPath("userData"), "logs")
|
|
1128
|
-
let log_file_path = path.join(log_dir_path, `app_${today}.log`)
|
|
1275
|
+
let today = new Date().toLocaleDateString().replace("/", ".");
|
|
1276
|
+
let log_dir_path = path.join(app.getPath("userData"), "logs");
|
|
1277
|
+
let log_file_path = path.join(log_dir_path, `app_${today}.log`);
|
|
1129
1278
|
|
|
1130
1279
|
if (!fs.existsSync(log_dir_path)) {
|
|
1131
1280
|
fs.mkdirSync(log_dir_path, { recursive: true });
|
|
1132
1281
|
fs.writeFileSync(log_file_path, "", "utf-8");
|
|
1133
1282
|
}
|
|
1134
1283
|
|
|
1135
|
-
fs.writeFile(log_file_path, `${text}\n`, { flag:
|
|
1284
|
+
fs.writeFile(log_file_path, `${text}\n`, { flag: "a+" }, (err) => {
|
|
1136
1285
|
if (err) console.error(err);
|
|
1137
1286
|
});
|
|
1138
1287
|
}
|
|
1139
1288
|
|
|
1140
1289
|
enableAutoUpdateApp(start = Number()) {
|
|
1141
|
-
const {autoUpdater} = require("electron-updater");
|
|
1290
|
+
const { autoUpdater } = require("electron-updater");
|
|
1142
1291
|
// Подписки на апдейтер и подтверждение установки — один раз на экземпляр Main:
|
|
1143
1292
|
// раньше ipcMain.on("updateInstallConfirm") и autoUpdater.on добавлялись
|
|
1144
1293
|
// внутри update-downloaded, то есть на каждое событие.
|
|
1145
1294
|
if (this.#updaterListening === false) {
|
|
1146
1295
|
this.#updaterListening = true;
|
|
1147
|
-
autoUpdater.on(
|
|
1296
|
+
autoUpdater.on("update-downloaded", this.#onUpdateDownloaded);
|
|
1148
1297
|
ipcMain.on("updateInstallConfirm", this.#onUpdateInstallConfirm);
|
|
1149
1298
|
}
|
|
1150
1299
|
setTimeout(async () => {
|
|
@@ -1153,7 +1302,10 @@ class Main {
|
|
|
1153
1302
|
if (updates !== null) {
|
|
1154
1303
|
this.#lastUpdateInfo = updates;
|
|
1155
1304
|
if (updates.versionInfo.version > app.getVersion()) {
|
|
1156
|
-
await this.#sendNotificationUpdateLoad(
|
|
1305
|
+
await this.#sendNotificationUpdateLoad(
|
|
1306
|
+
this.#appName,
|
|
1307
|
+
I18n.t("appLayout.update.downloading", { version: updates.versionInfo.version })
|
|
1308
|
+
);
|
|
1157
1309
|
}
|
|
1158
1310
|
}
|
|
1159
1311
|
}, start);
|
|
@@ -1173,81 +1325,43 @@ class Main {
|
|
|
1173
1325
|
|
|
1174
1326
|
/** Уведомление о загрузке; последним аргументом можно указать окно реестра */
|
|
1175
1327
|
sendDownload(text, body, windowName = undefined) {
|
|
1176
|
-
setTimeout(() => this.#send("sendNotificationDownload", [text, body], windowName), 1)
|
|
1328
|
+
setTimeout(() => this.#send("sendNotificationDownload", [text, body], windowName), 1);
|
|
1177
1329
|
}
|
|
1178
1330
|
sendDownloadUpdate(text, body, windowName = undefined) {
|
|
1179
|
-
setTimeout(() => this.#send("sendNotificationDownloadUpdate", [text, body], windowName), 1)
|
|
1331
|
+
setTimeout(() => this.#send("sendNotificationDownloadUpdate", [text, body], windowName), 1);
|
|
1180
1332
|
}
|
|
1181
1333
|
sendDownloadComplete(text, body, windowName = undefined) {
|
|
1182
|
-
setTimeout(() => this.#send("sendNotificationDownloadComplete", [text, body], windowName), 250)
|
|
1334
|
+
setTimeout(() => this.#send("sendNotificationDownloadComplete", [text, body], windowName), 250);
|
|
1183
1335
|
}
|
|
1184
1336
|
sendDownloadError(text, body, windowName = undefined) {
|
|
1185
|
-
setTimeout(() => this.#send("sendNotificationDownloadError", [text, body], windowName), 250)
|
|
1337
|
+
setTimeout(() => this.#send("sendNotificationDownloadError", [text, body], windowName), 250);
|
|
1186
1338
|
}
|
|
1187
1339
|
}
|
|
1188
1340
|
|
|
1189
1341
|
class Styles {
|
|
1190
|
-
static WORD_BREAK = {NORMAL: "normal", BREAK_ALL: "break-all", KEEP_ALL: "keep-all", BREAK_WORD: "break-word"}
|
|
1191
|
-
static TEXT_ALIGN = {CENTER:
|
|
1192
|
-
static ALIGN = {CENTER:
|
|
1342
|
+
static WORD_BREAK = { NORMAL: "normal", BREAK_ALL: "break-all", KEEP_ALL: "keep-all", BREAK_WORD: "break-word" };
|
|
1343
|
+
static TEXT_ALIGN = { CENTER: "center", END: "end", START: "start" };
|
|
1344
|
+
static ALIGN = { CENTER: "center", END: "flex-end", START: "flex-start", BASELINE: "baseline", STRETCH: "stretch" };
|
|
1193
1345
|
static JUSTIFY = {
|
|
1194
|
-
CENTER:
|
|
1195
|
-
END:
|
|
1196
|
-
START:
|
|
1197
|
-
SPACE_AROUND:
|
|
1198
|
-
SPACE_BEETWEEN:
|
|
1199
|
-
SPACE_EVENLY:
|
|
1346
|
+
CENTER: "center",
|
|
1347
|
+
END: "flex-end",
|
|
1348
|
+
START: "flex-start",
|
|
1349
|
+
SPACE_AROUND: "space-around",
|
|
1350
|
+
SPACE_BEETWEEN: "space-between",
|
|
1351
|
+
SPACE_EVENLY: "space-evenly",
|
|
1200
1352
|
};
|
|
1201
|
-
static DIRECTION = {ROW:
|
|
1202
|
-
static WRAP = {NOWRAP:
|
|
1353
|
+
static DIRECTION = { ROW: "row", COLUMN: "column" };
|
|
1354
|
+
static WRAP = { NOWRAP: "nowrap", WRAP: "wrap" };
|
|
1203
1355
|
static SIZE = {
|
|
1204
|
-
AUTO:
|
|
1205
|
-
FIT_CONTENT:
|
|
1206
|
-
MAX_CONTENT:
|
|
1207
|
-
MIN_CONTENT:
|
|
1208
|
-
WEBKIT_FILL:
|
|
1209
|
-
INHERIT:
|
|
1356
|
+
AUTO: "auto",
|
|
1357
|
+
FIT_CONTENT: "fit-content",
|
|
1358
|
+
MAX_CONTENT: "max-content",
|
|
1359
|
+
MIN_CONTENT: "min-content",
|
|
1360
|
+
WEBKIT_FILL: "-webkit-fill-available",
|
|
1361
|
+
INHERIT: "inherit",
|
|
1210
1362
|
};
|
|
1211
1363
|
}
|
|
1212
1364
|
|
|
1213
|
-
class Application {
|
|
1214
|
-
getApp() {
|
|
1215
|
-
if (inRenderer()) throw new Error("App.get(): странице не отдают модули main — возьмите Desktop.app.path()/info() или свой канал из security.channels");
|
|
1216
|
-
return app;
|
|
1217
|
-
}
|
|
1218
|
-
getSession() {
|
|
1219
|
-
if (inRenderer()) throw new Error("App.getSession(): странице не отдают сессию main — возьмите Desktop.session.*");
|
|
1220
|
-
return session;
|
|
1221
|
-
}
|
|
1222
|
-
getWebContents() {
|
|
1223
|
-
if (inRenderer()) throw new Error("App.getWebContents(): странице не отдают webContents main — действия идут через Desktop или свой канал из security.channels");
|
|
1224
|
-
return webContents;
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
class App {
|
|
1229
|
-
static get() { return new Application().getApp() }
|
|
1230
|
-
static getSession() { return new Application().getSession() }
|
|
1231
|
-
static getWebContents() { return new Application().getWebContents() }
|
|
1232
|
-
// ПУТИ
|
|
1233
|
-
static homePath() { return new Application().getApp().getPath("home") }
|
|
1234
|
-
static appDataPath() { return new Application().getApp().getPath("appData") }
|
|
1235
|
-
static userDataPath() { return new Application().getApp().getPath("userData") }
|
|
1236
|
-
static sessionDataPath() { return new Application().getApp().getPath("sessionData") }
|
|
1237
|
-
static logsPath() { return new Application().getApp().getPath("logs") }
|
|
1238
|
-
static tempPath() { return new Application().getApp().getPath("temp") }
|
|
1239
|
-
static exePath() { return new Application().getApp().getPath("exe") }
|
|
1240
|
-
static modulePath() { return new Application().getApp().getPath("module") }
|
|
1241
|
-
static desktopPath() { return new Application().getApp().getPath("desktop") }
|
|
1242
|
-
static documentsPath() { return new Application().getApp().getPath("documents") }
|
|
1243
|
-
static downloadsPath() { return new Application().getApp().getPath("downloads") }
|
|
1244
|
-
static musicPath() { return new Application().getApp().getPath("music") }
|
|
1245
|
-
static picturesPath() { return new Application().getApp().getPath("pictures") }
|
|
1246
|
-
static videosPath() { return new Application().getApp().getPath("videos") }
|
|
1247
|
-
static recentPath() { return new Application().getApp().getPath("recent") }
|
|
1248
|
-
static crashDumpsPath() { return new Application().getApp().getPath("crashDumps") }
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
1365
|
module.exports = {
|
|
1252
1366
|
Main: Main,
|
|
1253
1367
|
sleep: sleep,
|
|
@@ -1405,8 +1519,6 @@ module.exports = {
|
|
|
1405
1519
|
transliterate: transliterate,
|
|
1406
1520
|
store: store,
|
|
1407
1521
|
//
|
|
1408
|
-
App: App,
|
|
1409
|
-
//
|
|
1410
1522
|
// Десктоп-сервисы: классы main-процесса и доступ из страницы
|
|
1411
1523
|
Shortcuts: Shortcuts,
|
|
1412
1524
|
Shell: Shell,
|
|
@@ -1424,10 +1536,13 @@ module.exports = {
|
|
|
1424
1536
|
Log: Log,
|
|
1425
1537
|
chooseFile: {
|
|
1426
1538
|
// Диалоги: странице — по IPC (окно берётся у отправителя), в main — обычный dialog Electron
|
|
1427
|
-
showOpenDialog: (options = {}) =>
|
|
1428
|
-
|
|
1429
|
-
|
|
1539
|
+
showOpenDialog: (options = {}) =>
|
|
1540
|
+
inRenderer() ? Desktop.dialog.open(options) : dialog.showOpenDialog(options),
|
|
1541
|
+
showSaveDialog: (options = {}) =>
|
|
1542
|
+
inRenderer() ? Desktop.dialog.save(options) : dialog.showSaveDialog(options),
|
|
1543
|
+
showMessageBox: (options = {}) =>
|
|
1544
|
+
inRenderer() ? Desktop.dialog.message(options) : dialog.showMessageBox(options),
|
|
1430
1545
|
},
|
|
1431
1546
|
//
|
|
1432
|
-
systemPreferences: systemPreferences
|
|
1433
|
-
}
|
|
1547
|
+
systemPreferences: systemPreferences,
|
|
1548
|
+
};
|