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.
Files changed (222) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/README.md +43 -632
  3. package/framework/appLayout/default/chui_app_layout.js +314 -273
  4. package/framework/appLayout/default/global_style.css +93 -53
  5. package/framework/components/chui_accordion/accordion.js +29 -26
  6. package/framework/components/chui_accordion/styles.css +6 -5
  7. package/framework/components/chui_action_sheet/action_sheet.js +59 -33
  8. package/framework/components/chui_action_sheet/styles.css +2 -1
  9. package/framework/components/chui_affix/affix.js +11 -6
  10. package/framework/components/chui_alert/alert.js +23 -14
  11. package/framework/components/chui_avatar/avatar.js +23 -22
  12. package/framework/components/chui_avatar_group/avatar_group.js +21 -19
  13. package/framework/components/chui_backtop/backtop.js +35 -19
  14. package/framework/components/chui_badge/badge.js +15 -13
  15. package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
  16. package/framework/components/chui_button/button.js +42 -22
  17. package/framework/components/chui_button/styles.css +2 -2
  18. package/framework/components/chui_calendar/calendar.js +12 -10
  19. package/framework/components/chui_card/card.js +43 -23
  20. package/framework/components/chui_chat/chat.js +72 -33
  21. package/framework/components/chui_clipboard_history/clipboard_history.js +30 -21
  22. package/framework/components/chui_clipboard_history/styles.css +4 -2
  23. package/framework/components/chui_code/code.js +2 -2
  24. package/framework/components/chui_code/styles.css +2 -2
  25. package/framework/components/chui_code_editor/code_editor.js +47 -31
  26. package/framework/components/chui_code_editor/styles.css +3 -2
  27. package/framework/components/chui_command_palette/command_palette.js +60 -37
  28. package/framework/components/chui_console/console.js +5 -5
  29. package/framework/components/chui_console/styles.css +1 -1
  30. package/framework/components/chui_content_block/content_block.js +33 -19
  31. package/framework/components/chui_content_block/styles.css +2 -2
  32. package/framework/components/chui_context_menu/context_menu.js +9 -4
  33. package/framework/components/chui_custom_element/custom_element.js +22 -15
  34. package/framework/components/chui_data_grid/data_grid.js +396 -234
  35. package/framework/components/chui_data_grid/styles.css +10 -8
  36. package/framework/components/chui_descriptions/descriptions.js +34 -17
  37. package/framework/components/chui_details/details.js +32 -26
  38. package/framework/components/chui_details/styles.css +5 -4
  39. package/framework/components/chui_diff_viewer/diff_viewer.js +91 -66
  40. package/framework/components/chui_diff_viewer/styles.css +1 -1
  41. package/framework/components/chui_divider/divider.js +13 -11
  42. package/framework/components/chui_drawer/drawer.js +27 -25
  43. package/framework/components/chui_drop_zone/drop_zone.js +31 -21
  44. package/framework/components/chui_empty_state/empty_state.js +20 -15
  45. package/framework/components/chui_fieldset/fieldset.js +37 -20
  46. package/framework/components/chui_fieldset/styles.css +1 -1
  47. package/framework/components/chui_file_explorer/file_explorer.js +157 -86
  48. package/framework/components/chui_file_explorer/styles.css +2 -1
  49. package/framework/components/chui_form/form.js +31 -19
  50. package/framework/components/chui_form/styles.css +1 -1
  51. package/framework/components/chui_gantt/gantt.js +64 -40
  52. package/framework/components/chui_graphs/graphs.js +301 -200
  53. package/framework/components/chui_graphs/styles.css +1 -1
  54. package/framework/components/chui_hero/hero.js +40 -22
  55. package/framework/components/chui_html_block/html_block.js +6 -6
  56. package/framework/components/chui_html_block/styles.css +2 -2
  57. package/framework/components/chui_hx/hx.js +3 -3
  58. package/framework/components/chui_hx/styles.css +11 -4
  59. package/framework/components/chui_icons/icons.js +2109 -2109
  60. package/framework/components/chui_icons/styles.css +2 -2
  61. package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
  62. package/framework/components/chui_inputs/chui_check_box/styles.css +18 -18
  63. package/framework/components/chui_inputs/chui_chips/chips.js +50 -40
  64. package/framework/components/chui_inputs/chui_chips/styles.css +4 -2
  65. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +36 -24
  66. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +100 -82
  67. package/framework/components/chui_inputs/chui_combo_box/styles.css +14 -12
  68. package/framework/components/chui_inputs/chui_date/date.js +102 -66
  69. package/framework/components/chui_inputs/chui_date/styles.css +12 -11
  70. package/framework/components/chui_inputs/chui_date_range/date_range.js +40 -29
  71. package/framework/components/chui_inputs/chui_datetime/datetime.js +35 -27
  72. package/framework/components/chui_inputs/chui_email/email.js +43 -31
  73. package/framework/components/chui_inputs/chui_email/styles.css +5 -5
  74. package/framework/components/chui_inputs/chui_file/file.js +68 -41
  75. package/framework/components/chui_inputs/chui_file/styles.css +13 -12
  76. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +61 -36
  77. package/framework/components/chui_inputs/chui_masked/masked.js +39 -28
  78. package/framework/components/chui_inputs/chui_mention/mention.js +77 -30
  79. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +173 -153
  80. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +9 -7
  81. package/framework/components/chui_inputs/chui_number/number.js +58 -41
  82. package/framework/components/chui_inputs/chui_number/styles.css +7 -7
  83. package/framework/components/chui_inputs/chui_otp/otp.js +38 -29
  84. package/framework/components/chui_inputs/chui_password/password.js +58 -36
  85. package/framework/components/chui_inputs/chui_password/styles.css +8 -8
  86. package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
  87. package/framework/components/chui_inputs/chui_radio_button/styles.css +20 -20
  88. package/framework/components/chui_inputs/chui_rating/rating.js +26 -22
  89. package/framework/components/chui_inputs/chui_select_box/select_box.js +102 -78
  90. package/framework/components/chui_inputs/chui_select_box/styles.css +11 -11
  91. package/framework/components/chui_inputs/chui_slider/slider.js +29 -26
  92. package/framework/components/chui_inputs/chui_slider/styles.css +2 -1
  93. package/framework/components/chui_inputs/chui_text/styles.css +8 -8
  94. package/framework/components/chui_inputs/chui_text/text.js +65 -44
  95. package/framework/components/chui_inputs/chui_text_area/styles.css +6 -6
  96. package/framework/components/chui_inputs/chui_text_area/text_area.js +51 -28
  97. package/framework/components/chui_inputs/chui_time/styles.css +5 -3
  98. package/framework/components/chui_inputs/chui_time/time.js +38 -27
  99. package/framework/components/chui_inputs/chui_toggle/styles.css +3 -3
  100. package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
  101. package/framework/components/chui_json_editor/json_editor.js +53 -43
  102. package/framework/components/chui_json_viewer/json_viewer.js +52 -33
  103. package/framework/components/chui_json_viewer/styles.css +3 -2
  104. package/framework/components/chui_kanban/kanban.js +52 -34
  105. package/framework/components/chui_kbd/kbd.js +12 -10
  106. package/framework/components/chui_label/label.js +14 -12
  107. package/framework/components/chui_label/styles.css +2 -2
  108. package/framework/components/chui_link/link.js +27 -20
  109. package/framework/components/chui_list/list.js +31 -27
  110. package/framework/components/chui_list/styles.css +2 -1
  111. package/framework/components/chui_markdown_editor/markdown_editor.js +60 -44
  112. package/framework/components/chui_media/audio.js +326 -227
  113. package/framework/components/chui_media/audio_styles.css +40 -21
  114. package/framework/components/chui_media/image.js +70 -38
  115. package/framework/components/chui_media/image_compare.js +52 -21
  116. package/framework/components/chui_media/image_styles.css +3 -3
  117. package/framework/components/chui_media/video.js +155 -62
  118. package/framework/components/chui_media/video_styles.css +33 -16
  119. package/framework/components/chui_menu_bar/menu_bar.js +26 -24
  120. package/framework/components/chui_menu_bar/styles.css +4 -2
  121. package/framework/components/chui_modal/modal.js +44 -43
  122. package/framework/components/chui_modal/styles.css +3 -2
  123. package/framework/components/chui_notification/notification.js +50 -34
  124. package/framework/components/chui_notification/notification_download.js +31 -25
  125. package/framework/components/chui_notification/notification_download_progress.css +3 -2
  126. package/framework/components/chui_notification/notification_download_progress.js +47 -41
  127. package/framework/components/chui_notification/notification_update.js +23 -16
  128. package/framework/components/chui_notification/status_plate.js +2 -2
  129. package/framework/components/chui_notification/styles_download.css +1 -1
  130. package/framework/components/chui_notification/styles_update.css +1 -1
  131. package/framework/components/chui_org_chart/org_chart.js +74 -35
  132. package/framework/components/chui_pagination/pagination.js +62 -27
  133. package/framework/components/chui_paragraph/paragraph.js +2 -2
  134. package/framework/components/chui_paragraph/styles.css +1 -1
  135. package/framework/components/chui_popover/popover.js +49 -28
  136. package/framework/components/chui_popups/popups.js +137 -108
  137. package/framework/components/chui_popups/styles.css +2 -2
  138. package/framework/components/chui_print_button/print_button.js +33 -23
  139. package/framework/components/chui_progress_bar/progress_bar.js +23 -15
  140. package/framework/components/chui_progress_bar/styles.css +2 -2
  141. package/framework/components/chui_progress_ring/progress_ring.js +17 -15
  142. package/framework/components/chui_qrcode/qrcode.js +75 -31
  143. package/framework/components/chui_query_builder/query_builder.js +216 -123
  144. package/framework/components/chui_radio_group/radio_group.js +36 -26
  145. package/framework/components/chui_radio_group/styles.css +1 -1
  146. package/framework/components/chui_result/result.js +26 -16
  147. package/framework/components/chui_scheduler/scheduler.js +57 -35
  148. package/framework/components/chui_scheduler/styles.css +6 -2
  149. package/framework/components/chui_segmented_control/segmented_control.js +27 -21
  150. package/framework/components/chui_settings/settings.js +122 -48
  151. package/framework/components/chui_shortcut_help/shortcut_help.js +55 -32
  152. package/framework/components/chui_sidebar_nav/sidebar_nav.js +33 -23
  153. package/framework/components/chui_skeleton/skeleton.js +29 -24
  154. package/framework/components/chui_slideshow/slideshow.js +60 -41
  155. package/framework/components/chui_slideshow/styles.css +18 -12
  156. package/framework/components/chui_spinner/spinner.js +8 -8
  157. package/framework/components/chui_spinner/styles.css +0 -1
  158. package/framework/components/chui_split_button/split_button.js +23 -18
  159. package/framework/components/chui_split_button/styles.css +1 -1
  160. package/framework/components/chui_splitter/splitter.js +35 -28
  161. package/framework/components/chui_statistic/statistic.js +65 -38
  162. package/framework/components/chui_status_bar/status_bar.js +11 -9
  163. package/framework/components/chui_stepper/stepper.js +27 -22
  164. package/framework/components/chui_sticky_bar/sticky_bar.js +9 -4
  165. package/framework/components/chui_sticky_bar/styles.css +3 -1
  166. package/framework/components/chui_tabs/chui_tabs.js +28 -22
  167. package/framework/components/chui_tabs/styles.css +3 -3
  168. package/framework/components/chui_text_editor/styles.css +20 -19
  169. package/framework/components/chui_text_editor/text_editor.js +85 -61
  170. package/framework/components/chui_text_editor/text_editor_panel.js +346 -284
  171. package/framework/components/chui_theme_toggle/theme_toggle.js +27 -22
  172. package/framework/components/chui_timeline/timeline.js +14 -12
  173. package/framework/components/chui_toast_queue/toast_queue.js +52 -46
  174. package/framework/components/chui_toolbar/toolbar.js +20 -13
  175. package/framework/components/chui_tooltip/tooltip.js +37 -24
  176. package/framework/components/chui_tour/styles.css +8 -3
  177. package/framework/components/chui_tour/tour.js +61 -27
  178. package/framework/components/chui_transfer/styles.css +2 -1
  179. package/framework/components/chui_transfer/transfer.js +75 -42
  180. package/framework/components/chui_tree_table/tree_table.js +43 -29
  181. package/framework/components/chui_tree_view/styles.css +4 -2
  182. package/framework/components/chui_tree_view/tree_view.js +142 -99
  183. package/framework/components/chui_watermark/watermark.js +24 -16
  184. package/framework/components/chui_webview/styles.css +2 -2
  185. package/framework/components/chui_webview/webview.js +62 -50
  186. package/framework/components/telegram_bot/chui_telegram_bot.js +71 -64
  187. package/framework/modules/chui_a11y/chui_a11y.js +77 -46
  188. package/framework/modules/chui_animations/animations.js +42 -42
  189. package/framework/modules/chui_animations/styles.css +1 -1
  190. package/framework/modules/chui_bridge/preload.js +56 -26
  191. package/framework/modules/chui_functions.js +52 -50
  192. package/framework/modules/chui_highlight/chui_highlight.js +25 -22
  193. package/framework/modules/chui_i18n/chui_i18n.js +9 -7
  194. package/framework/modules/chui_i18n/locales/a11y.js +5 -5
  195. package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
  196. package/framework/modules/chui_i18n/locales/calendar.js +3 -3
  197. package/framework/modules/chui_i18n/locales/common.js +3 -3
  198. package/framework/modules/chui_i18n/locales/data.js +36 -26
  199. package/framework/modules/chui_i18n/locales/editors.js +40 -13
  200. package/framework/modules/chui_i18n/locales/feedback.js +3 -3
  201. package/framework/modules/chui_i18n/locales/forms.js +8 -8
  202. package/framework/modules/chui_i18n/locales/graphics.js +8 -8
  203. package/framework/modules/chui_i18n/locales/media.js +4 -4
  204. package/framework/modules/chui_i18n/locales/navigation.js +8 -8
  205. package/framework/modules/chui_i18n/locales/validate.js +3 -3
  206. package/framework/modules/chui_json/chui_json.js +9 -9
  207. package/framework/modules/chui_layout/chui_layout.js +12 -10
  208. package/framework/modules/chui_logger/chui_logger.js +29 -25
  209. package/framework/modules/chui_page/page.js +33 -27
  210. package/framework/modules/chui_page/styles.css +3 -26
  211. package/framework/modules/chui_qr/chui_qr.js +158 -67
  212. package/framework/modules/chui_scrollbar/chui_scrollbar.js +35 -24
  213. package/framework/modules/chui_scrollbar/styles.css +3 -1
  214. package/framework/modules/chui_services/chui_channels.js +76 -11
  215. package/framework/modules/chui_services/chui_services.js +39 -31
  216. package/framework/modules/chui_services/desktop.js +149 -30
  217. package/framework/modules/chui_sortable/chui_sortable.js +17 -12
  218. package/framework/modules/chui_validate/chui_validate.js +7 -4
  219. package/framework/tray_bar/chui_menu_items.js +136 -46
  220. package/index.d.ts +4814 -0
  221. package/index.js +449 -334
  222. 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
- [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, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
62
- [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, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28],
63
- [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, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
64
- [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, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]
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
- [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, 19, 20, 21, 22, 24, 25],
69
- [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, 33, 35, 37, 38, 40, 43, 45, 47, 49],
70
- [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, 45, 48, 51, 53, 56, 59, 62, 65, 68],
71
- [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, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81]
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
- [], [6, 18], [6, 22], [6, 26], [6, 30], [6, 34], [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50],
76
- [6, 30, 54], [6, 32, 58], [6, 34, 62], [6, 26, 46, 66], [6, 26, 48, 70], [6, 26, 50, 74], [6, 30, 54, 78],
77
- [6, 30, 56, 82], [6, 30, 58, 86], [6, 34, 62, 90], [6, 28, 50, 72, 94], [6, 26, 50, 74, 98],
78
- [6, 30, 54, 78, 102], [6, 28, 54, 80, 106], [6, 32, 58, 84, 110], [6, 30, 58, 86, 114],
79
- [6, 34, 62, 90, 118], [6, 26, 50, 74, 98, 122], [6, 30, 54, 78, 102, 126], [6, 26, 52, 78, 104, 130],
80
- [6, 30, 56, 82, 108, 134], [6, 34, 60, 86, 112, 138], [6, 30, 58, 86, 114, 142], [6, 34, 62, 90, 118, 146],
81
- [6, 30, 54, 78, 102, 126, 150], [6, 24, 50, 76, 102, 128, 154], [6, 28, 54, 80, 106, 132, 158],
82
- [6, 32, 58, 84, 110, 136, 162], [6, 26, 54, 82, 110, 138, 166], [6, 30, 58, 86, 114, 142, 170]
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 = 0x11D;
88
- const PAD_BYTES = [0xEC, 0x11];
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 = 0x1F25;
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(0xC0 | (code >> 6), 0x80 | (code & 0x3F));
138
- else if (code < 0x10000) bytes.push(0xE0 | (code >> 12), 0x80 | ((code >> 6) & 0x3F), 0x80 | (code & 0x3F));
139
- else bytes.push(0xF0 | (code >> 18), 0x80 | ((code >> 12) & 0x3F), 0x80 | ((code >> 6) & 0x3F), 0x80 | (code & 0x3F));
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 {ok: false, error: {
180
- code: "tooLong", mode: payload.mode, length: payload.length,
181
- needed: payload.length, capacity: QR.#capacity(last, level, payload.mode)
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, matrix: pattern.modules, size: size, version: version, mask: chosen_mask,
196
- level: level, mode: payload.mode, length: payload.length
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 = ALPHANUMERIC_CHARS.indexOf(text.charAt(i)) * 45 + ALPHANUMERIC_CHARS.indexOf(text.charAt(i + 1));
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 [[3, 3], [size - 4, 3], [3, size - 4]]) {
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 = (row === 0 && column === 0) ||
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: return (x + y) % 2 === 0;
471
- case 1: return y % 2 === 0;
472
- case 2: return x % 3 === 0;
473
- case 3: return (x + y) % 3 === 0;
474
- case 4: return (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0;
475
- case 5: return ((x * y) % 2) + ((x * y) % 3) === 0;
476
- case 6: return (((x * y) % 2) + ((x * y) % 3)) % 2 === 0;
477
- case 7: return (((x + y) % 2) + ((x * y) % 3)) % 2 === 0;
478
- default: throw new RangeError("QR: маска вне диапазона 0…7");
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]) score += PENALTY.N2;
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 = unit > 0 && history[2] === unit && history[3] === unit * 3 && history[4] === unit && history[5] === unit;
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 (history[0] >= unit * 4 && history[6] >= unit ? 1 : 0) +
587
- (history[6] >= unit * 4 && history[0] >= unit ? 1 : 0);
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
- 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
- }
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
- 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
- };
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 = rect.width > 0 && rect.height > 0 && rect.bottom > 0
325
- && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
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, {capture: true, passive: true});
537
- document.addEventListener("animationend", OverlayScrollbars.#onViewportChange, {capture: true, passive: true});
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: opacity var(--transition_time) ease, background-color var(--transition_time) ease;
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", "appData", "userData", "sessionData", "temp", "exe", "module",
65
- "desktop", "documents", "downloads", "music", "pictures", "videos", "logs", "recent", "crashDumps"
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.BRIDGE_CHANNELS = BRIDGE_CHANNELS
132
- exports.APP_PATH_NAMES = APP_PATH_NAMES
133
- exports.BRIDGE_ARGS = BRIDGE_ARGS
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;