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
|
@@ -33,63 +33,119 @@ const LEVELS = {
|
|
|
33
33
|
LOW: "L",
|
|
34
34
|
MEDIUM: "M",
|
|
35
35
|
QUARTILE: "Q",
|
|
36
|
-
HIGH: "H"
|
|
36
|
+
HIGH: "H",
|
|
37
37
|
};
|
|
38
38
|
const MODES = {
|
|
39
39
|
AUTO: "auto",
|
|
40
40
|
NUMERIC: "numeric",
|
|
41
41
|
ALPHANUMERIC: "alphanumeric",
|
|
42
|
-
BYTE: "byte"
|
|
42
|
+
BYTE: "byte",
|
|
43
43
|
};
|
|
44
44
|
/** Знаки, которые кодируются в алфавитно-цифровом режиме (45 значений) */
|
|
45
45
|
const ALPHANUMERIC_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
|
|
46
46
|
/** Биты режима, разрядность счётчика символов по диапазонам версий (1–9, 10–26, 27–40) */
|
|
47
47
|
const MODE_INFO = {
|
|
48
|
-
numeric: {bits: 0b0001, count: [10, 12, 14]},
|
|
49
|
-
alphanumeric: {bits: 0b0010, count: [9, 11, 13]},
|
|
50
|
-
byte: {bits: 0b0100, count: [8, 16, 16]}
|
|
48
|
+
numeric: { bits: 0b0001, count: [10, 12, 14] },
|
|
49
|
+
alphanumeric: { bits: 0b0010, count: [9, 11, 13] },
|
|
50
|
+
byte: { bits: 0b0100, count: [8, 16, 16] },
|
|
51
51
|
};
|
|
52
52
|
/** Биты уровня в информации о формате (порядок в таблицах блоков — L, M, Q, H) */
|
|
53
53
|
const LEVEL_INFO = {
|
|
54
|
-
L: {format: 0b01, index: 0},
|
|
55
|
-
M: {format: 0b00, index: 1},
|
|
56
|
-
Q: {format: 0b11, index: 2},
|
|
57
|
-
H: {format: 0b10, index: 3}
|
|
54
|
+
L: { format: 0b01, index: 0 },
|
|
55
|
+
M: { format: 0b00, index: 1 },
|
|
56
|
+
Q: { format: 0b11, index: 2 },
|
|
57
|
+
H: { format: 0b10, index: 3 },
|
|
58
58
|
};
|
|
59
59
|
/** Кодовых слов коррекции в блоке по версиям 1…40 (строки — L, M, Q, H) */
|
|
60
60
|
const EC_CODEWORDS = [
|
|
61
|
-
[
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
[
|
|
62
|
+
7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30,
|
|
63
|
+
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
|
64
|
+
],
|
|
65
|
+
[
|
|
66
|
+
10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28,
|
|
67
|
+
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
|
68
|
+
],
|
|
69
|
+
[
|
|
70
|
+
13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30,
|
|
71
|
+
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
|
72
|
+
],
|
|
73
|
+
[
|
|
74
|
+
17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30,
|
|
75
|
+
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
|
76
|
+
],
|
|
65
77
|
];
|
|
66
78
|
/** Число блоков коррекции по версиям 1…40 (строки — L, M, Q, H) */
|
|
67
79
|
const EC_BLOCKS = [
|
|
68
|
-
[
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
80
|
+
[
|
|
81
|
+
1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19,
|
|
82
|
+
19, 20, 21, 22, 24, 25,
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31,
|
|
86
|
+
33, 35, 37, 38, 40, 43, 45, 47, 49,
|
|
87
|
+
],
|
|
88
|
+
[
|
|
89
|
+
1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43,
|
|
90
|
+
45, 48, 51, 53, 56, 59, 62, 65, 68,
|
|
91
|
+
],
|
|
92
|
+
[
|
|
93
|
+
1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48,
|
|
94
|
+
51, 54, 57, 60, 63, 66, 70, 74, 77, 81,
|
|
95
|
+
],
|
|
72
96
|
];
|
|
73
97
|
/** Центры узоров выравнивания по версиям 1…40 (пусто у первой версии) */
|
|
74
98
|
const ALIGNMENT_POSITIONS = [
|
|
75
|
-
[],
|
|
76
|
-
[6,
|
|
77
|
-
[6,
|
|
78
|
-
[6,
|
|
79
|
-
[6,
|
|
80
|
-
[6,
|
|
81
|
-
[6,
|
|
82
|
-
[6,
|
|
99
|
+
[],
|
|
100
|
+
[6, 18],
|
|
101
|
+
[6, 22],
|
|
102
|
+
[6, 26],
|
|
103
|
+
[6, 30],
|
|
104
|
+
[6, 34],
|
|
105
|
+
[6, 22, 38],
|
|
106
|
+
[6, 24, 42],
|
|
107
|
+
[6, 26, 46],
|
|
108
|
+
[6, 28, 50],
|
|
109
|
+
[6, 30, 54],
|
|
110
|
+
[6, 32, 58],
|
|
111
|
+
[6, 34, 62],
|
|
112
|
+
[6, 26, 46, 66],
|
|
113
|
+
[6, 26, 48, 70],
|
|
114
|
+
[6, 26, 50, 74],
|
|
115
|
+
[6, 30, 54, 78],
|
|
116
|
+
[6, 30, 56, 82],
|
|
117
|
+
[6, 30, 58, 86],
|
|
118
|
+
[6, 34, 62, 90],
|
|
119
|
+
[6, 28, 50, 72, 94],
|
|
120
|
+
[6, 26, 50, 74, 98],
|
|
121
|
+
[6, 30, 54, 78, 102],
|
|
122
|
+
[6, 28, 54, 80, 106],
|
|
123
|
+
[6, 32, 58, 84, 110],
|
|
124
|
+
[6, 30, 58, 86, 114],
|
|
125
|
+
[6, 34, 62, 90, 118],
|
|
126
|
+
[6, 26, 50, 74, 98, 122],
|
|
127
|
+
[6, 30, 54, 78, 102, 126],
|
|
128
|
+
[6, 26, 52, 78, 104, 130],
|
|
129
|
+
[6, 30, 56, 82, 108, 134],
|
|
130
|
+
[6, 34, 60, 86, 112, 138],
|
|
131
|
+
[6, 30, 58, 86, 114, 142],
|
|
132
|
+
[6, 34, 62, 90, 118, 146],
|
|
133
|
+
[6, 30, 54, 78, 102, 126, 150],
|
|
134
|
+
[6, 24, 50, 76, 102, 128, 154],
|
|
135
|
+
[6, 28, 54, 80, 106, 132, 158],
|
|
136
|
+
[6, 32, 58, 84, 110, 136, 162],
|
|
137
|
+
[6, 26, 54, 82, 110, 138, 166],
|
|
138
|
+
[6, 30, 58, 86, 114, 142, 170],
|
|
83
139
|
];
|
|
84
140
|
const MIN_VERSION = 1;
|
|
85
141
|
const MAX_VERSION = 40;
|
|
86
142
|
/** Полином поля Галуа и порождающий полином модуля `x^8 + x^4 + x^3 + x^2 + 1` */
|
|
87
|
-
const GF_PRIME =
|
|
88
|
-
const PAD_BYTES = [
|
|
89
|
-
const PENALTY = {N1: 3, N2: 3, N3: 40, N4: 10};
|
|
143
|
+
const GF_PRIME = 0x11d;
|
|
144
|
+
const PAD_BYTES = [0xec, 0x11];
|
|
145
|
+
const PENALTY = { N1: 3, N2: 3, N3: 40, N4: 10 };
|
|
90
146
|
const FORMAT_POLYNOMIAL = 0x537;
|
|
91
147
|
const FORMAT_MASK = 0x5412;
|
|
92
|
-
const VERSION_POLYNOMIAL =
|
|
148
|
+
const VERSION_POLYNOMIAL = 0x1f25;
|
|
93
149
|
|
|
94
150
|
class QR {
|
|
95
151
|
static LEVEL = LEVELS;
|
|
@@ -134,9 +190,15 @@ class QR {
|
|
|
134
190
|
for (const char of String(text)) {
|
|
135
191
|
const code = char.codePointAt(0);
|
|
136
192
|
if (code < 0x80) bytes.push(code);
|
|
137
|
-
else if (code < 0x800) bytes.push(
|
|
138
|
-
else if (code < 0x10000) bytes.push(
|
|
139
|
-
else
|
|
193
|
+
else if (code < 0x800) bytes.push(0xc0 | (code >> 6), 0x80 | (code & 0x3f));
|
|
194
|
+
else if (code < 0x10000) bytes.push(0xe0 | (code >> 12), 0x80 | ((code >> 6) & 0x3f), 0x80 | (code & 0x3f));
|
|
195
|
+
else
|
|
196
|
+
bytes.push(
|
|
197
|
+
0xf0 | (code >> 18),
|
|
198
|
+
0x80 | ((code >> 12) & 0x3f),
|
|
199
|
+
0x80 | ((code >> 6) & 0x3f),
|
|
200
|
+
0x80 | (code & 0x3f)
|
|
201
|
+
);
|
|
140
202
|
}
|
|
141
203
|
return bytes;
|
|
142
204
|
}
|
|
@@ -150,7 +212,7 @@ class QR {
|
|
|
150
212
|
*/
|
|
151
213
|
static encode(value = String(), options = {}) {
|
|
152
214
|
const text = value === undefined || value === null ? "" : String(value);
|
|
153
|
-
if (text === "") return {ok: false, error: {code: "empty"}};
|
|
215
|
+
if (text === "") return { ok: false, error: { code: "empty" } };
|
|
154
216
|
// Пустая строка в опции значит «не задана» — общее правило фреймворка
|
|
155
217
|
const level = QR.#checkLevel(QR.#option(options.level));
|
|
156
218
|
const requested = QR.#option(options.mode);
|
|
@@ -164,7 +226,7 @@ class QR {
|
|
|
164
226
|
|
|
165
227
|
const chosen = mode === MODES.AUTO ? QR.modeOf(text) : mode;
|
|
166
228
|
const payload = QR.#payload(text, chosen);
|
|
167
|
-
if (payload === undefined) return {ok: false, error: {code: "mode", mode: chosen}};
|
|
229
|
+
if (payload === undefined) return { ok: false, error: { code: "mode", mode: chosen } };
|
|
168
230
|
|
|
169
231
|
// Версия — наименьшая, в которую влезает заголовок (4 бита режима и счётчик) и данные
|
|
170
232
|
let version = undefined;
|
|
@@ -176,24 +238,34 @@ class QR {
|
|
|
176
238
|
}
|
|
177
239
|
}
|
|
178
240
|
if (version === undefined) {
|
|
179
|
-
return {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
241
|
+
return {
|
|
242
|
+
ok: false,
|
|
243
|
+
error: {
|
|
244
|
+
code: "tooLong",
|
|
245
|
+
mode: payload.mode,
|
|
246
|
+
length: payload.length,
|
|
247
|
+
needed: payload.length,
|
|
248
|
+
capacity: QR.#capacity(last, level, payload.mode),
|
|
249
|
+
},
|
|
250
|
+
};
|
|
183
251
|
}
|
|
184
252
|
|
|
185
253
|
const codewords = QR.#codewords(payload, version, level);
|
|
186
254
|
const size = QR.size(version);
|
|
187
255
|
const pattern = QR.#functionPatterns(version, level);
|
|
188
256
|
QR.#placeData(pattern.modules, pattern.isFunction, codewords, size);
|
|
189
|
-
const chosen_mask = mask === undefined
|
|
190
|
-
? QR.#bestMask(pattern.modules, pattern.isFunction, size, level)
|
|
191
|
-
: mask;
|
|
257
|
+
const chosen_mask = mask === undefined ? QR.#bestMask(pattern.modules, pattern.isFunction, size, level) : mask;
|
|
192
258
|
QR.#applyMask(pattern.modules, pattern.isFunction, size, chosen_mask);
|
|
193
259
|
QR.#drawFormat(pattern.modules, pattern.isFunction, size, level, chosen_mask);
|
|
194
260
|
return {
|
|
195
|
-
ok: true,
|
|
196
|
-
|
|
261
|
+
ok: true,
|
|
262
|
+
matrix: pattern.modules,
|
|
263
|
+
size: size,
|
|
264
|
+
version: version,
|
|
265
|
+
mask: chosen_mask,
|
|
266
|
+
level: level,
|
|
267
|
+
mode: payload.mode,
|
|
268
|
+
length: payload.length,
|
|
197
269
|
};
|
|
198
270
|
}
|
|
199
271
|
|
|
@@ -207,23 +279,24 @@ class QR {
|
|
|
207
279
|
const group = text.slice(i, i + 3);
|
|
208
280
|
QR.#append(bits, Number(group), group.length * 3 + 1);
|
|
209
281
|
}
|
|
210
|
-
return {mode: mode, length: text.length, bits: bits};
|
|
282
|
+
return { mode: mode, length: text.length, bits: bits };
|
|
211
283
|
}
|
|
212
284
|
if (mode === MODES.ALPHANUMERIC) {
|
|
213
285
|
if (!QR.isAlphanumeric(text)) return undefined;
|
|
214
286
|
const bits = [];
|
|
215
287
|
let i = 0;
|
|
216
288
|
for (; i + 2 <= text.length; i += 2) {
|
|
217
|
-
const value =
|
|
289
|
+
const value =
|
|
290
|
+
ALPHANUMERIC_CHARS.indexOf(text.charAt(i)) * 45 + ALPHANUMERIC_CHARS.indexOf(text.charAt(i + 1));
|
|
218
291
|
QR.#append(bits, value, 11);
|
|
219
292
|
}
|
|
220
293
|
if (i < text.length) QR.#append(bits, ALPHANUMERIC_CHARS.indexOf(text.charAt(i)), 6);
|
|
221
|
-
return {mode: mode, length: text.length, bits: bits};
|
|
294
|
+
return { mode: mode, length: text.length, bits: bits };
|
|
222
295
|
}
|
|
223
296
|
const bytes = QR.toBytes(text);
|
|
224
297
|
const bits = [];
|
|
225
298
|
for (const byte of bytes) QR.#append(bits, byte, 8);
|
|
226
|
-
return {mode: MODES.BYTE, length: bytes.length, bits: bits};
|
|
299
|
+
return { mode: MODES.BYTE, length: bytes.length, bits: bits };
|
|
227
300
|
}
|
|
228
301
|
|
|
229
302
|
/** Сколько символов влезает в версию при уровне и режиме */
|
|
@@ -281,7 +354,7 @@ class QR {
|
|
|
281
354
|
const length = short_length + (index < short_blocks ? 0 : 1);
|
|
282
355
|
const chunk = data.slice(offset, offset + length);
|
|
283
356
|
offset += length;
|
|
284
|
-
chunks.push({data: chunk, ec: QR.#remainder(chunk, divisor)});
|
|
357
|
+
chunks.push({ data: chunk, ec: QR.#remainder(chunk, divisor) });
|
|
285
358
|
}
|
|
286
359
|
const result = [];
|
|
287
360
|
const longest = short_length + 1;
|
|
@@ -358,8 +431,8 @@ class QR {
|
|
|
358
431
|
/** Матрица со служебными узорами: где можно ставить данные, отмечено в `isFunction` */
|
|
359
432
|
static #functionPatterns(version = MIN_VERSION, level = LEVELS.MEDIUM) {
|
|
360
433
|
const size = QR.size(version);
|
|
361
|
-
const modules = Array.from({length: size}, () => new Array(size).fill(false));
|
|
362
|
-
const isFunction = Array.from({length: size}, () => new Array(size).fill(false));
|
|
434
|
+
const modules = Array.from({ length: size }, () => new Array(size).fill(false));
|
|
435
|
+
const isFunction = Array.from({ length: size }, () => new Array(size).fill(false));
|
|
363
436
|
const set = (x, y, dark) => {
|
|
364
437
|
if (x < 0 || y < 0 || x >= size || y >= size) return;
|
|
365
438
|
modules[y][x] = dark;
|
|
@@ -371,7 +444,11 @@ class QR {
|
|
|
371
444
|
set(i, 6, i % 2 === 0);
|
|
372
445
|
}
|
|
373
446
|
// Поисковые узоры 7×7 с разделителем: расстояние Чебышёва до центра 3 — тёмное, 2 и 4 — светлое
|
|
374
|
-
for (const center of [
|
|
447
|
+
for (const center of [
|
|
448
|
+
[3, 3],
|
|
449
|
+
[size - 4, 3],
|
|
450
|
+
[3, size - 4],
|
|
451
|
+
]) {
|
|
375
452
|
for (let dy = -4; dy <= 4; dy += 1) {
|
|
376
453
|
for (let dx = -4; dx <= 4; dx += 1) {
|
|
377
454
|
const distance = Math.max(Math.abs(dx), Math.abs(dy));
|
|
@@ -383,7 +460,8 @@ class QR {
|
|
|
383
460
|
const centers = ALIGNMENT_POSITIONS[version - 1];
|
|
384
461
|
for (let row = 0; row < centers.length; row += 1) {
|
|
385
462
|
for (let column = 0; column < centers.length; column += 1) {
|
|
386
|
-
const corner =
|
|
463
|
+
const corner =
|
|
464
|
+
(row === 0 && column === 0) ||
|
|
387
465
|
(row === 0 && column === centers.length - 1) ||
|
|
388
466
|
(row === centers.length - 1 && column === 0);
|
|
389
467
|
if (corner) continue;
|
|
@@ -398,7 +476,7 @@ class QR {
|
|
|
398
476
|
// считаются сразу — данные туда не попадут
|
|
399
477
|
QR.#drawFormat(modules, isFunction, size, level, 0);
|
|
400
478
|
QR.#drawVersion(modules, isFunction, size, version);
|
|
401
|
-
return {modules: modules, isFunction: isFunction};
|
|
479
|
+
return { modules: modules, isFunction: isFunction };
|
|
402
480
|
}
|
|
403
481
|
|
|
404
482
|
/** Информация о формате: 5 битов данных, 10 битов BCH-остатка и маска 0x5412 */
|
|
@@ -467,15 +545,24 @@ class QR {
|
|
|
467
545
|
/** Маска: `true` — модуль инвертируется */
|
|
468
546
|
static #maskAt(mask = 0, x = Number(), y = Number()) {
|
|
469
547
|
switch (mask) {
|
|
470
|
-
case 0:
|
|
471
|
-
|
|
472
|
-
case
|
|
473
|
-
|
|
474
|
-
case
|
|
475
|
-
|
|
476
|
-
case
|
|
477
|
-
|
|
478
|
-
|
|
548
|
+
case 0:
|
|
549
|
+
return (x + y) % 2 === 0;
|
|
550
|
+
case 1:
|
|
551
|
+
return y % 2 === 0;
|
|
552
|
+
case 2:
|
|
553
|
+
return x % 3 === 0;
|
|
554
|
+
case 3:
|
|
555
|
+
return (x + y) % 3 === 0;
|
|
556
|
+
case 4:
|
|
557
|
+
return (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0;
|
|
558
|
+
case 5:
|
|
559
|
+
return ((x * y) % 2) + ((x * y) % 3) === 0;
|
|
560
|
+
case 6:
|
|
561
|
+
return (((x * y) % 2) + ((x * y) % 3)) % 2 === 0;
|
|
562
|
+
case 7:
|
|
563
|
+
return (((x + y) % 2) + ((x * y) % 3)) % 2 === 0;
|
|
564
|
+
default:
|
|
565
|
+
throw new RangeError("QR: маска вне диапазона 0…7");
|
|
479
566
|
}
|
|
480
567
|
}
|
|
481
568
|
|
|
@@ -520,7 +607,8 @@ class QR {
|
|
|
520
607
|
for (let y = 0; y < size - 1; y += 1) {
|
|
521
608
|
for (let x = 0; x < size - 1; x += 1) {
|
|
522
609
|
const dark = modules[y][x];
|
|
523
|
-
if (dark === modules[y][x + 1] && dark === modules[y + 1][x] && dark === modules[y + 1][x + 1])
|
|
610
|
+
if (dark === modules[y][x + 1] && dark === modules[y + 1][x] && dark === modules[y + 1][x + 1])
|
|
611
|
+
score += PENALTY.N2;
|
|
524
612
|
}
|
|
525
613
|
}
|
|
526
614
|
// Правило 4: доля тёмных модулей вне 45…55 %, шаг — 5 %
|
|
@@ -581,10 +669,13 @@ class QR {
|
|
|
581
669
|
/** Узор 1:1:3:1:1 в истории полос: тёмная полоса шириной 3 единицы в тёмной рамке */
|
|
582
670
|
static #finderRuns(history = []) {
|
|
583
671
|
const unit = history[1];
|
|
584
|
-
const core =
|
|
672
|
+
const core =
|
|
673
|
+
unit > 0 && history[2] === unit && history[3] === unit * 3 && history[4] === unit && history[5] === unit;
|
|
585
674
|
if (!core) return 0;
|
|
586
|
-
return (
|
|
587
|
-
(history[
|
|
675
|
+
return (
|
|
676
|
+
(history[0] >= unit * 4 && history[6] >= unit ? 1 : 0) +
|
|
677
|
+
(history[6] >= unit * 4 && history[0] >= unit ? 1 : 0)
|
|
678
|
+
);
|
|
588
679
|
}
|
|
589
680
|
|
|
590
681
|
/** Число, записанное `length` битами, в конец потока */
|
|
@@ -622,4 +713,4 @@ class QR {
|
|
|
622
713
|
}
|
|
623
714
|
}
|
|
624
715
|
|
|
625
|
-
exports.QR = QR
|
|
716
|
+
exports.QR = QR;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {setStyles} = require("../chui_functions");
|
|
1
|
+
const { setStyles } = require("../chui_functions");
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Полосы прокрутки поверх содержимого (overlay), автоматически на все прокручиваемые узлы.
|
|
@@ -36,7 +36,7 @@ const {setStyles} = require("../chui_functions");
|
|
|
36
36
|
*/
|
|
37
37
|
const AXIS = {
|
|
38
38
|
VERTICAL: "vertical",
|
|
39
|
-
HORIZONTAL: "horizontal"
|
|
39
|
+
HORIZONTAL: "horizontal",
|
|
40
40
|
};
|
|
41
41
|
const AXES = [AXIS.VERTICAL, AXIS.HORIZONTAL];
|
|
42
42
|
/** Толщина глифа и зазор от края узла: глиф ложится в отступ узла, а не на содержимое */
|
|
@@ -239,7 +239,7 @@ class Scrollbar {
|
|
|
239
239
|
top: read("--scrollbar_inset_top"),
|
|
240
240
|
right: read("--scrollbar_inset_right"),
|
|
241
241
|
bottom: read("--scrollbar_inset_bottom"),
|
|
242
|
-
left: read("--scrollbar_inset_left")
|
|
242
|
+
left: read("--scrollbar_inset_left"),
|
|
243
243
|
};
|
|
244
244
|
return this.#inset_cache;
|
|
245
245
|
}
|
|
@@ -278,7 +278,7 @@ class Scrollbar {
|
|
|
278
278
|
travel: track - thumb_size,
|
|
279
279
|
offset: vertical ? element.scrollTop : element.scrollLeft,
|
|
280
280
|
start: vertical ? insets.top : insets.left,
|
|
281
|
-
end: vertical ? insets.bottom : insets.right
|
|
281
|
+
end: vertical ? insets.bottom : insets.right,
|
|
282
282
|
};
|
|
283
283
|
}
|
|
284
284
|
|
|
@@ -289,17 +289,17 @@ class Scrollbar {
|
|
|
289
289
|
const vertical = axis === AXIS.VERTICAL;
|
|
290
290
|
const box = vertical
|
|
291
291
|
? {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
292
|
+
left: Math.round(rect.right - metrics.end - this.#inset - this.#thickness),
|
|
293
|
+
top: Math.round(rect.top + metrics.start + position),
|
|
294
|
+
width: this.#thickness,
|
|
295
|
+
height: metrics.thumb_size,
|
|
296
|
+
}
|
|
297
297
|
: {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
298
|
+
left: Math.round(rect.left + metrics.start + position),
|
|
299
|
+
top: Math.round(rect.bottom - metrics.end - this.#inset - this.#thickness),
|
|
300
|
+
width: metrics.thumb_size,
|
|
301
|
+
height: this.#thickness,
|
|
302
|
+
};
|
|
303
303
|
// Запись в стиль всегда обнуляет разметку, а пересчёт идёт каждый кадр прокрутки:
|
|
304
304
|
// одинаковую геометрию не переписываем, иначе получаем reflow на каждый узел
|
|
305
305
|
const signature = `${box.left}|${box.top}|${box.width}|${box.height}`;
|
|
@@ -321,8 +321,13 @@ class Scrollbar {
|
|
|
321
321
|
return;
|
|
322
322
|
}
|
|
323
323
|
const rect = element.getBoundingClientRect();
|
|
324
|
-
const on_screen =
|
|
325
|
-
|
|
324
|
+
const on_screen =
|
|
325
|
+
rect.width > 0 &&
|
|
326
|
+
rect.height > 0 &&
|
|
327
|
+
rect.bottom > 0 &&
|
|
328
|
+
rect.top < window.innerHeight &&
|
|
329
|
+
rect.right > 0 &&
|
|
330
|
+
rect.left < window.innerWidth;
|
|
326
331
|
// Узел за пределами окна (его вытянет прокрутка родителя): писать в глифы нечего,
|
|
327
332
|
// кроме снятия видимости при уходе — иначе на каждый узел приходился бы reflow
|
|
328
333
|
if (on_screen === false) {
|
|
@@ -522,19 +527,25 @@ class OverlayScrollbars {
|
|
|
522
527
|
subtree: true,
|
|
523
528
|
characterData: true,
|
|
524
529
|
attributes: true,
|
|
525
|
-
attributeFilter: ["class", "style", "hidden"]
|
|
530
|
+
attributeFilter: ["class", "style", "hidden"],
|
|
526
531
|
});
|
|
527
532
|
}
|
|
528
533
|
OverlayScrollbars.scan(document.body);
|
|
529
534
|
// Прокрутка любого узла двигает и вложенные в него: свой слушатель есть у каждого
|
|
530
535
|
// накрытого узла, но «прокрутился родитель» его не будит. Событие `scroll` не
|
|
531
536
|
// всплывает, поэтому ловим на фазе захвата — так оно доходит и от потомков.
|
|
532
|
-
document.addEventListener("scroll", OverlayScrollbars.#onViewportChange, {capture: true, passive: true});
|
|
533
|
-
window.addEventListener("resize", OverlayScrollbars.#onResize, {passive: true});
|
|
537
|
+
document.addEventListener("scroll", OverlayScrollbars.#onViewportChange, { capture: true, passive: true });
|
|
538
|
+
window.addEventListener("resize", OverlayScrollbars.#onResize, { passive: true });
|
|
534
539
|
// Панели и слои появляются анимацией (сдвиг, масштаб). Пока узел ехал, он был за
|
|
535
540
|
// пределами окна и геометрия не считалась, поэтому по завершении анимации пересчитываем.
|
|
536
|
-
document.addEventListener("transitionend", OverlayScrollbars.#onViewportChange, {
|
|
537
|
-
|
|
541
|
+
document.addEventListener("transitionend", OverlayScrollbars.#onViewportChange, {
|
|
542
|
+
capture: true,
|
|
543
|
+
passive: true,
|
|
544
|
+
});
|
|
545
|
+
document.addEventListener("animationend", OverlayScrollbars.#onViewportChange, {
|
|
546
|
+
capture: true,
|
|
547
|
+
passive: true,
|
|
548
|
+
});
|
|
538
549
|
return OverlayScrollbars;
|
|
539
550
|
}
|
|
540
551
|
|
|
@@ -542,9 +553,9 @@ class OverlayScrollbars {
|
|
|
542
553
|
static stop() {
|
|
543
554
|
if (OverlayScrollbars.#started === false) return OverlayScrollbars;
|
|
544
555
|
OverlayScrollbars.#started = false;
|
|
545
|
-
document.removeEventListener("scroll", OverlayScrollbars.#onViewportChange, {capture: true});
|
|
546
|
-
document.removeEventListener("transitionend", OverlayScrollbars.#onViewportChange, {capture: true});
|
|
547
|
-
document.removeEventListener("animationend", OverlayScrollbars.#onViewportChange, {capture: true});
|
|
556
|
+
document.removeEventListener("scroll", OverlayScrollbars.#onViewportChange, { capture: true });
|
|
557
|
+
document.removeEventListener("transitionend", OverlayScrollbars.#onViewportChange, { capture: true });
|
|
558
|
+
document.removeEventListener("animationend", OverlayScrollbars.#onViewportChange, { capture: true });
|
|
548
559
|
window.removeEventListener("resize", OverlayScrollbars.#onResize);
|
|
549
560
|
if (OverlayScrollbars.#observer !== undefined) OverlayScrollbars.#observer.disconnect();
|
|
550
561
|
if (OverlayScrollbars.#resize !== undefined) OverlayScrollbars.#resize.disconnect();
|
|
@@ -22,7 +22,9 @@ chui_scrollbar_thumb {
|
|
|
22
22
|
opacity: 0;
|
|
23
23
|
/* Плавно только появление и цвет: `top`/`left`/`width`/`height` анимировать нельзя —
|
|
24
24
|
глиф отставал бы от прокрутки и «плыл» за содержимым */
|
|
25
|
-
transition:
|
|
25
|
+
transition:
|
|
26
|
+
opacity var(--transition_time) ease,
|
|
27
|
+
background-color var(--transition_time) ease;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
chui_scrollbar_thumb.chui_scrollbar_visible {
|
|
@@ -43,8 +43,32 @@ const SERVICES_CHANNELS = {
|
|
|
43
43
|
SHORTCUT_EVENT: "chui_shortcut",
|
|
44
44
|
/** Путь приложения по имени из `APP_PATH_NAMES` */
|
|
45
45
|
APP_PATH: "chui_services_app_path",
|
|
46
|
+
/**
|
|
47
|
+
* Тот же путь, но ответ приходит значением, а не промисом: канал синхронный
|
|
48
|
+
* (`ipcRenderer.sendSync`). `Desktop.app.path` ходит сюда — путь берут на старте, чтобы
|
|
49
|
+
* собрать свои пути к файлам, и ждать промис там негде. Асинхронный `APP_PATH` оставлен:
|
|
50
|
+
* карта `window.chui.services` отдаётся странице целиком, её ключи — часть API безопасного
|
|
51
|
+
* режима, и убрать один из них значило бы сломать чужой вызов.
|
|
52
|
+
*/
|
|
53
|
+
APP_PATH_SYNC: "chui_services_app_path_sync",
|
|
46
54
|
/** Сведения о приложении: имя, версия, язык, сборка */
|
|
47
55
|
APP_INFO: "chui_services_app_info",
|
|
56
|
+
/**
|
|
57
|
+
* Закрыть и перезапустить приложение со страницы. Идут через `Main.stop()`/`restart()`:
|
|
58
|
+
* это те же шаги, что у пункта меню «Выход», — снимаются обработчики сервисов, глобальные
|
|
59
|
+
* клавиши и подписки, а не просто закрывается окно.
|
|
60
|
+
*/
|
|
61
|
+
APP_QUIT: "chui_services_app_quit",
|
|
62
|
+
APP_RESTART: "chui_services_app_restart",
|
|
63
|
+
/**
|
|
64
|
+
* Те же закрытие и перезапуск, но ответ приходит значением, а не промисом: канал
|
|
65
|
+
* синхронный (`ipcRenderer.sendSync`). `Desktop.app.quit()`/`restart()` ходят сюда — выход
|
|
66
|
+
* начинается тем же `Main.stop()`/`restart()`, а страница получает ответ сразу, без `await`.
|
|
67
|
+
* Асинхронные `APP_QUIT`/`APP_RESTART` оставлены: их ключи есть в карте `window.chui.services`,
|
|
68
|
+
* а это часть API безопасного режима.
|
|
69
|
+
*/
|
|
70
|
+
APP_QUIT_SYNC: "chui_services_app_quit_sync",
|
|
71
|
+
APP_RESTART_SYNC: "chui_services_app_restart_sync",
|
|
48
72
|
/** Системные диалоги: окно берётся у отправителя */
|
|
49
73
|
DIALOG_OPEN: "chui_services_dialog_open",
|
|
50
74
|
DIALOG_SAVE: "chui_services_dialog_save",
|
|
@@ -52,7 +76,7 @@ const SERVICES_CHANNELS = {
|
|
|
52
76
|
/** Сессия окна-отправителя: кеш и хранилище */
|
|
53
77
|
SESSION_CACHE_SIZE: "chui_services_session_cache_size",
|
|
54
78
|
SESSION_CLEAR_CACHE: "chui_services_session_clear_cache",
|
|
55
|
-
SESSION_CLEAR_STORAGE: "chui_services_session_clear_storage"
|
|
79
|
+
SESSION_CLEAR_STORAGE: "chui_services_session_clear_storage",
|
|
56
80
|
};
|
|
57
81
|
|
|
58
82
|
/**
|
|
@@ -61,8 +85,22 @@ const SERVICES_CHANNELS = {
|
|
|
61
85
|
* Имена совпадают с именами Electron, кроме `logs` (в Electron это `logs`).
|
|
62
86
|
*/
|
|
63
87
|
const APP_PATH_NAMES = [
|
|
64
|
-
"home",
|
|
65
|
-
"
|
|
88
|
+
"home",
|
|
89
|
+
"appData",
|
|
90
|
+
"userData",
|
|
91
|
+
"sessionData",
|
|
92
|
+
"temp",
|
|
93
|
+
"exe",
|
|
94
|
+
"module",
|
|
95
|
+
"desktop",
|
|
96
|
+
"documents",
|
|
97
|
+
"downloads",
|
|
98
|
+
"music",
|
|
99
|
+
"pictures",
|
|
100
|
+
"videos",
|
|
101
|
+
"logs",
|
|
102
|
+
"recent",
|
|
103
|
+
"crashDumps",
|
|
66
104
|
];
|
|
67
105
|
|
|
68
106
|
/**
|
|
@@ -99,12 +137,38 @@ const SERVICES_CALLS = {
|
|
|
99
137
|
localeSet: SERVICES_CHANNELS.LOCALE_SET,
|
|
100
138
|
appPath: SERVICES_CHANNELS.APP_PATH,
|
|
101
139
|
appInfo: SERVICES_CHANNELS.APP_INFO,
|
|
140
|
+
appQuit: SERVICES_CHANNELS.APP_QUIT,
|
|
141
|
+
appRestart: SERVICES_CHANNELS.APP_RESTART,
|
|
102
142
|
dialogOpen: SERVICES_CHANNELS.DIALOG_OPEN,
|
|
103
143
|
dialogSave: SERVICES_CHANNELS.DIALOG_SAVE,
|
|
104
144
|
dialogMessage: SERVICES_CHANNELS.DIALOG_MESSAGE,
|
|
105
145
|
sessionCacheSize: SERVICES_CHANNELS.SESSION_CACHE_SIZE,
|
|
106
146
|
sessionClearCache: SERVICES_CHANNELS.SESSION_CLEAR_CACHE,
|
|
107
|
-
sessionClearStorage: SERVICES_CHANNELS.SESSION_CLEAR_STORAGE
|
|
147
|
+
sessionClearStorage: SERVICES_CHANNELS.SESSION_CLEAR_STORAGE,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Синхронные вызовы (`ipcRenderer.sendSync`) — те, где ответ нужен значением, а не промисом.
|
|
152
|
+
*
|
|
153
|
+
* Отдельный map, а не строка в `SERVICES_CALLS`: тот мост превращает в методы страницы через
|
|
154
|
+
* `ipcRenderer.invoke`, а на синхронный канал invoke не отвечает — промис не завершился бы
|
|
155
|
+
* никогда, и страница молча ждала бы ответа.
|
|
156
|
+
*
|
|
157
|
+
* Ответ синхронного канала — конверт `{value}` или `{error}`: у `sendSync` нет канала для
|
|
158
|
+
* исключения, и без конверта причина отказа (имя пути вне белого списка) потерялась бы,
|
|
159
|
+
* а страница получила бы `undefined`. Разбирает конверт `Desktop.#callSync` — одинаково
|
|
160
|
+
* в обычном режиме и в безопасном.
|
|
161
|
+
*
|
|
162
|
+
* `sendSync` останавливает страницу на время ответа (main при этом свободен), поэтому
|
|
163
|
+
* синхронных вызовов должно быть мало и отвечать они обязаны мгновенно: `app.getPath` —
|
|
164
|
+
* чтение кеша Electron, без обращения к диску.
|
|
165
|
+
*/
|
|
166
|
+
const SERVICES_SYNC_CALLS = {
|
|
167
|
+
appPathSync: SERVICES_CHANNELS.APP_PATH_SYNC,
|
|
168
|
+
// Закрытие и перезапуск отвечают мгновенно (`setImmediate` в main откладывает выход),
|
|
169
|
+
// поэтому синхронный канал здесь так же уместен, как у пути: странице не нужен `await`
|
|
170
|
+
appQuitSync: SERVICES_CHANNELS.APP_QUIT_SYNC,
|
|
171
|
+
appRestartSync: SERVICES_CHANNELS.APP_RESTART_SYNC,
|
|
108
172
|
};
|
|
109
173
|
|
|
110
174
|
/** Каналы моста: окно, тема и прикладные сообщения безопасного окна */
|
|
@@ -116,18 +180,19 @@ const BRIDGE_CHANNELS = {
|
|
|
116
180
|
LOCALE_GET: "chui_bridge_locale_get",
|
|
117
181
|
LOCALE_EVENT: "chui_bridge_locale_event",
|
|
118
182
|
/** Прикладные сообщения страницы в main по своему каналу из белого списка */
|
|
119
|
-
MESSAGE: "chui_bridge_message"
|
|
183
|
+
MESSAGE: "chui_bridge_message",
|
|
120
184
|
};
|
|
121
185
|
|
|
122
186
|
/** Дополнительные аргументы процесса preload'а: страница, белый список каналов и CSP */
|
|
123
187
|
const BRIDGE_ARGS = {
|
|
124
188
|
RENDER: "--chui-render=",
|
|
125
189
|
CHANNELS: "--chui-channels=",
|
|
126
|
-
CSP: "--chui-csp="
|
|
190
|
+
CSP: "--chui-csp=",
|
|
127
191
|
};
|
|
128
192
|
|
|
129
|
-
exports.SERVICES_CHANNELS = SERVICES_CHANNELS
|
|
130
|
-
exports.SERVICES_CALLS = SERVICES_CALLS
|
|
131
|
-
exports.
|
|
132
|
-
exports.
|
|
133
|
-
exports.
|
|
193
|
+
exports.SERVICES_CHANNELS = SERVICES_CHANNELS;
|
|
194
|
+
exports.SERVICES_CALLS = SERVICES_CALLS;
|
|
195
|
+
exports.SERVICES_SYNC_CALLS = SERVICES_SYNC_CALLS;
|
|
196
|
+
exports.BRIDGE_CHANNELS = BRIDGE_CHANNELS;
|
|
197
|
+
exports.APP_PATH_NAMES = APP_PATH_NAMES;
|
|
198
|
+
exports.BRIDGE_ARGS = BRIDGE_ARGS;
|