chuijs 4.0.3 → 4.0.4

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 (258) hide show
  1. package/CHANGELOG.md +536 -0
  2. package/framework/appLayout/default/chui_app_layout.js +361 -303
  3. package/framework/appLayout/default/global_style.css +243 -89
  4. package/framework/appLayout/default/main_theme_style.css +188 -101
  5. package/framework/components/chui_accordion/accordion.js +17 -17
  6. package/framework/components/chui_accordion/styles.css +7 -7
  7. package/framework/components/chui_action_sheet/action_sheet.js +35 -32
  8. package/framework/components/chui_action_sheet/styles.css +10 -4
  9. package/framework/components/chui_actions_bar/actions_bar.js +338 -0
  10. package/framework/components/chui_actions_bar/styles.css +139 -0
  11. package/framework/components/chui_affix/affix.js +4 -4
  12. package/framework/components/chui_affix/styles.css +5 -0
  13. package/framework/components/chui_alert/alert.js +11 -5
  14. package/framework/components/chui_alert/styles.css +7 -0
  15. package/framework/components/chui_avatar/avatar.js +13 -13
  16. package/framework/components/chui_avatar/styles.css +1 -1
  17. package/framework/components/chui_avatar_group/avatar_group.js +4 -4
  18. package/framework/components/chui_avatar_group/styles.css +1 -1
  19. package/framework/components/chui_backtop/backtop.js +25 -2
  20. package/framework/components/chui_backtop/styles.css +21 -0
  21. package/framework/components/chui_badge/badge.js +15 -15
  22. package/framework/components/chui_badge/styles.css +6 -6
  23. package/framework/components/chui_banner/banner.js +222 -0
  24. package/framework/components/chui_banner/styles.css +170 -0
  25. package/framework/components/chui_breadcrumb/styles.css +1 -1
  26. package/framework/components/chui_button/button.js +24 -28
  27. package/framework/components/chui_button/styles.css +5 -5
  28. package/framework/components/chui_calendar/calendar.js +6 -6
  29. package/framework/components/chui_card/card.js +14 -14
  30. package/framework/components/chui_card_scroll/card_scroll.js +169 -0
  31. package/framework/components/chui_card_scroll/styles.css +86 -0
  32. package/framework/components/chui_chat/chat.js +73 -51
  33. package/framework/components/chui_chat/styles.css +18 -7
  34. package/framework/components/chui_clipboard_history/clipboard_history.js +25 -20
  35. package/framework/components/chui_clipboard_history/styles.css +10 -8
  36. package/framework/components/chui_code/code.js +8 -8
  37. package/framework/components/chui_code/styles.css +2 -2
  38. package/framework/components/chui_code_editor/code_editor.js +26 -26
  39. package/framework/components/chui_code_editor/styles.css +3 -3
  40. package/framework/components/chui_command_palette/command_palette.js +29 -29
  41. package/framework/components/chui_command_palette/styles.css +5 -5
  42. package/framework/components/chui_console/console.js +9 -9
  43. package/framework/components/chui_console/styles.css +5 -2
  44. package/framework/components/chui_content_block/content_block.js +2 -2
  45. package/framework/components/chui_context_menu/context_menu.js +162 -54
  46. package/framework/components/chui_context_menu/styles.css +82 -8
  47. package/framework/components/chui_custom_element/custom_element.js +11 -11
  48. package/framework/components/chui_data_grid/data_grid.js +268 -268
  49. package/framework/components/chui_data_grid/styles.css +14 -14
  50. package/framework/components/chui_descriptions/styles.css +1 -1
  51. package/framework/components/chui_details/details.js +12 -12
  52. package/framework/components/chui_details/styles.css +7 -7
  53. package/framework/components/chui_diff_viewer/diff_viewer.js +88 -88
  54. package/framework/components/chui_diff_viewer/styles.css +9 -9
  55. package/framework/components/chui_divider/divider.js +6 -6
  56. package/framework/components/chui_divider/styles.css +2 -2
  57. package/framework/components/chui_drawer/drawer.js +37 -14
  58. package/framework/components/chui_drawer/styles.css +18 -4
  59. package/framework/components/chui_drop_zone/drop_zone.js +6 -6
  60. package/framework/components/chui_drop_zone/styles.css +10 -6
  61. package/framework/components/chui_fieldset/fieldset.js +6 -6
  62. package/framework/components/chui_fieldset/styles.css +5 -5
  63. package/framework/components/chui_file_explorer/file_explorer.js +115 -115
  64. package/framework/components/chui_file_explorer/styles.css +6 -6
  65. package/framework/components/chui_form/form.js +11 -11
  66. package/framework/components/chui_gantt/gantt.js +41 -41
  67. package/framework/components/chui_gantt/styles.css +5 -5
  68. package/framework/components/chui_graphs/graphs.js +82 -46
  69. package/framework/components/chui_graphs/styles.css +26 -5
  70. package/framework/components/chui_hero/hero.js +63 -20
  71. package/framework/components/chui_hero/styles.css +176 -7
  72. package/framework/components/chui_html_block/html_block.js +5 -5
  73. package/framework/components/chui_html_block/styles.css +1 -1
  74. package/framework/components/chui_hx/styles.css +2 -2
  75. package/framework/components/chui_icons/icons.js +7 -7
  76. package/framework/components/chui_icons/styles.css +2 -1
  77. package/framework/components/chui_inputs/chui_check_box/styles.css +12 -3
  78. package/framework/components/chui_inputs/chui_chips/chips.js +92 -31
  79. package/framework/components/chui_inputs/chui_chips/styles.css +28 -5
  80. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +20 -15
  81. package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
  82. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +58 -58
  83. package/framework/components/chui_inputs/chui_combo_box/styles.css +9 -9
  84. package/framework/components/chui_inputs/chui_date/date.js +93 -95
  85. package/framework/components/chui_inputs/chui_date/styles.css +8 -8
  86. package/framework/components/chui_inputs/chui_date_range/date_range.js +22 -22
  87. package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
  88. package/framework/components/chui_inputs/chui_datetime/datetime.js +12 -12
  89. package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
  90. package/framework/components/chui_inputs/chui_email/email.js +10 -10
  91. package/framework/components/chui_inputs/chui_email/styles.css +6 -6
  92. package/framework/components/chui_inputs/chui_file/file.js +8 -8
  93. package/framework/components/chui_inputs/chui_file/styles.css +12 -9
  94. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +39 -39
  95. package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
  96. package/framework/components/chui_inputs/chui_masked/masked.js +44 -44
  97. package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
  98. package/framework/components/chui_inputs/chui_mention/mention.js +13 -13
  99. package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
  100. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +147 -137
  101. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +14 -8
  102. package/framework/components/chui_inputs/chui_number/number.js +42 -45
  103. package/framework/components/chui_inputs/chui_number/styles.css +6 -6
  104. package/framework/components/chui_inputs/chui_otp/otp.js +32 -32
  105. package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
  106. package/framework/components/chui_inputs/chui_password/password.js +30 -36
  107. package/framework/components/chui_inputs/chui_password/styles.css +7 -7
  108. package/framework/components/chui_inputs/chui_radio_button/styles.css +2 -2
  109. package/framework/components/chui_inputs/chui_rating/rating.js +28 -28
  110. package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
  111. package/framework/components/chui_inputs/chui_select_box/select_box.js +54 -54
  112. package/framework/components/chui_inputs/chui_select_box/styles.css +10 -10
  113. package/framework/components/chui_inputs/chui_slider/slider.js +14 -14
  114. package/framework/components/chui_inputs/chui_slider/styles.css +5 -4
  115. package/framework/components/chui_inputs/chui_text/styles.css +7 -7
  116. package/framework/components/chui_inputs/chui_text/text.js +13 -17
  117. package/framework/components/chui_inputs/chui_text_area/styles.css +8 -8
  118. package/framework/components/chui_inputs/chui_text_area/text_area.js +23 -23
  119. package/framework/components/chui_inputs/chui_time/styles.css +13 -17
  120. package/framework/components/chui_inputs/chui_time/time.js +35 -24
  121. package/framework/components/chui_inputs/chui_toggle/styles.css +10 -3
  122. package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
  123. package/framework/components/chui_json_editor/json_editor.js +87 -87
  124. package/framework/components/chui_json_editor/styles.css +5 -5
  125. package/framework/components/chui_json_viewer/json_viewer.js +80 -80
  126. package/framework/components/chui_json_viewer/styles.css +6 -6
  127. package/framework/components/chui_kanban/kanban.js +27 -27
  128. package/framework/components/chui_kanban/styles.css +8 -4
  129. package/framework/components/chui_kbd/styles.css +1 -1
  130. package/framework/components/chui_label/label.js +17 -17
  131. package/framework/components/chui_label/styles.css +1 -1
  132. package/framework/components/chui_link/link.js +9 -9
  133. package/framework/components/chui_link/styles.css +11 -4
  134. package/framework/components/chui_list/list.js +11 -11
  135. package/framework/components/chui_list/styles.css +2 -2
  136. package/framework/components/chui_markdown_editor/markdown_editor.js +66 -66
  137. package/framework/components/chui_markdown_editor/styles.css +5 -5
  138. package/framework/components/chui_media/audio.js +240 -246
  139. package/framework/components/chui_media/audio_styles.css +41 -23
  140. package/framework/components/chui_media/image.js +49 -46
  141. package/framework/components/chui_media/image_compare.js +35 -35
  142. package/framework/components/chui_media/image_compare_styles.css +5 -5
  143. package/framework/components/chui_media/image_styles.css +1 -1
  144. package/framework/components/chui_media/video.js +148 -148
  145. package/framework/components/chui_media/video_styles.css +27 -11
  146. package/framework/components/chui_menu_bar/menu_bar.js +54 -54
  147. package/framework/components/chui_menu_bar/styles.css +10 -10
  148. package/framework/components/chui_message_bar/message_bar.js +551 -0
  149. package/framework/components/chui_message_bar/styles.css +248 -0
  150. package/framework/components/chui_modal/modal.js +37 -13
  151. package/framework/components/chui_notification/notification.js +76 -54
  152. package/framework/components/chui_notification/notification_download.js +26 -81
  153. package/framework/components/chui_notification/notification_download_card.js +115 -0
  154. package/framework/components/chui_notification/notification_download_progress.css +2 -2
  155. package/framework/components/chui_notification/notification_download_progress.js +70 -108
  156. package/framework/components/chui_notification/notification_update.js +31 -31
  157. package/framework/components/chui_notification/status_plate.css +3 -3
  158. package/framework/components/chui_notification/styles.css +6 -1
  159. package/framework/components/chui_notification/styles_download.css +1 -1
  160. package/framework/components/chui_notification/styles_update.css +2 -2
  161. package/framework/components/chui_org_chart/org_chart.js +29 -29
  162. package/framework/components/chui_org_chart/styles.css +2 -2
  163. package/framework/components/chui_pagination/pagination.js +3 -3
  164. package/framework/components/chui_pagination/styles.css +1 -1
  165. package/framework/components/chui_paragraph/styles.css +2 -2
  166. package/framework/components/chui_popover/popover.js +29 -23
  167. package/framework/components/chui_popover/styles.css +1 -1
  168. package/framework/components/chui_popups/popups.js +124 -124
  169. package/framework/components/chui_popups/styles.css +5 -5
  170. package/framework/components/chui_print_button/print_button.js +15 -10
  171. package/framework/components/chui_progress_bar/progress_bar.js +34 -12
  172. package/framework/components/chui_progress_bar/styles.css +4 -4
  173. package/framework/components/chui_progress_ring/progress_ring.js +15 -15
  174. package/framework/components/chui_progress_ring/styles.css +1 -1
  175. package/framework/components/chui_qrcode/qrcode.js +12 -12
  176. package/framework/components/chui_query_builder/query_builder.js +46 -46
  177. package/framework/components/chui_query_builder/styles.css +4 -4
  178. package/framework/components/chui_radio_group/styles.css +1 -1
  179. package/framework/components/chui_result/result.js +15 -15
  180. package/framework/components/chui_result/styles.css +3 -3
  181. package/framework/components/chui_scheduler/scheduler.js +74 -74
  182. package/framework/components/chui_scheduler/styles.css +5 -5
  183. package/framework/components/chui_screen_spinner/screen_spinner.js +167 -0
  184. package/framework/components/chui_screen_spinner/styles.css +49 -0
  185. package/framework/components/chui_segmented_control/segmented_control.js +63 -6
  186. package/framework/components/chui_segmented_control/styles.css +32 -6
  187. package/framework/components/chui_settings/settings.js +45 -46
  188. package/framework/components/chui_settings/styles.css +4 -4
  189. package/framework/components/chui_shortcut_help/shortcut_help.js +32 -34
  190. package/framework/components/chui_sidebar_nav/sidebar_nav.js +98 -29
  191. package/framework/components/chui_sidebar_nav/styles.css +9 -3
  192. package/framework/components/chui_slideshow/slideshow.js +85 -85
  193. package/framework/components/chui_slideshow/styles.css +6 -6
  194. package/framework/components/chui_spinner/spinner.js +10 -10
  195. package/framework/components/chui_split_button/split_button.js +30 -12
  196. package/framework/components/chui_split_button/styles.css +21 -5
  197. package/framework/components/chui_splitter/splitter.js +11 -11
  198. package/framework/components/chui_splitter/styles.css +2 -2
  199. package/framework/components/chui_statistic/statistic.js +47 -47
  200. package/framework/components/chui_status_bar/styles.css +2 -2
  201. package/framework/components/chui_stepper/stepper.js +202 -31
  202. package/framework/components/chui_stepper/styles.css +79 -14
  203. package/framework/components/chui_sticky_bar/sticky_bar.js +44 -13
  204. package/framework/components/chui_sticky_bar/styles.css +10 -8
  205. package/framework/components/chui_tabs/chui_tabs.js +74 -26
  206. package/framework/components/chui_tabs/styles.css +40 -12
  207. package/framework/components/chui_text_editor/styles.css +7 -7
  208. package/framework/components/chui_text_editor/text_editor.js +56 -56
  209. package/framework/components/chui_text_editor/text_editor_panel.js +173 -174
  210. package/framework/components/chui_theme_toggle/theme_toggle.js +21 -5
  211. package/framework/components/chui_timeline/styles.css +3 -1
  212. package/framework/components/chui_toast_queue/styles.css +11 -11
  213. package/framework/components/chui_toast_queue/toast_queue.js +30 -27
  214. package/framework/components/chui_toolbar/styles.css +2 -2
  215. package/framework/components/chui_tooltip/styles.css +2 -2
  216. package/framework/components/chui_tooltip/tooltip.js +3 -3
  217. package/framework/components/chui_tour/styles.css +8 -8
  218. package/framework/components/chui_tour/tour.js +72 -72
  219. package/framework/components/chui_transfer/styles.css +6 -6
  220. package/framework/components/chui_transfer/transfer.js +93 -106
  221. package/framework/components/chui_tree_table/styles.css +4 -4
  222. package/framework/components/chui_tree_table/tree_table.js +45 -45
  223. package/framework/components/chui_tree_view/styles.css +10 -8
  224. package/framework/components/chui_tree_view/tree_view.js +185 -183
  225. package/framework/components/chui_user_bar/styles.css +145 -0
  226. package/framework/components/chui_user_bar/user_bar.js +402 -0
  227. package/framework/components/chui_user_list_bar/styles.css +173 -0
  228. package/framework/components/chui_user_list_bar/user_list_bar.js +485 -0
  229. package/framework/components/chui_watermark/watermark.js +17 -17
  230. package/framework/components/chui_webview/webview.js +9 -9
  231. package/framework/components/chui_write_bar/styles.css +172 -0
  232. package/framework/components/chui_write_bar/write_bar.js +320 -0
  233. package/framework/main_window.js +1234 -0
  234. package/framework/modules/chui_a11y/chui_a11y.js +78 -79
  235. package/framework/modules/chui_animations/animations.js +77 -15
  236. package/framework/modules/chui_animations/motion.js +120 -0
  237. package/framework/modules/chui_animations/styles.css +36 -3
  238. package/framework/modules/chui_functions.js +31 -27
  239. package/framework/modules/chui_highlight/styles.css +13 -10
  240. package/framework/modules/chui_i18n/chui_i18n.js +3 -3
  241. package/framework/modules/chui_i18n/locales/feedback.js +62 -0
  242. package/framework/modules/chui_i18n/locales/navigation.js +4 -0
  243. package/framework/modules/chui_json/chui_json.js +2 -2
  244. package/framework/modules/chui_logger/chui_logger.js +23 -8
  245. package/framework/modules/chui_page/page.js +10 -10
  246. package/framework/modules/chui_palette/palette.js +61 -0
  247. package/framework/modules/chui_qr/chui_qr.js +23 -23
  248. package/framework/modules/chui_scrollbar/chui_scrollbar.js +45 -45
  249. package/framework/modules/chui_scrollbar/styles.css +3 -3
  250. package/framework/modules/chui_services/chui_services.js +8 -8
  251. package/framework/modules/chui_services/desktop.js +77 -71
  252. package/framework/modules/chui_sortable/chui_sortable.js +17 -17
  253. package/framework/modules/chui_validate/chui_validate.js +3 -3
  254. package/framework/tray_bar/chui_menu_items.js +2 -2
  255. package/index.d.ts +266 -34
  256. package/index.js +20 -1168
  257. package/package.json +6 -4
  258. package/framework/components/telegram_bot/chui_telegram_bot.js +0 -191
@@ -18,25 +18,25 @@ const store = new Store();
18
18
  * (`setPin("top" | "bottom" | "left" | "right")`) — тогда она висит поверх содержимого.
19
19
  */
20
20
  class Audio {
21
- #chui_ap_main = document.createElement("chui_ap_main");
22
- #chui_ap_block = document.createElement("chui_ap_block");
23
- #chui_ap_row = document.createElement("chui_ap_row");
24
- #chui_at = document.createElement("audio");
21
+ #chuiApMain = document.createElement("chui_ap_main");
22
+ #chuiApBlock = document.createElement("chui_ap_block");
23
+ #chuiApRow = document.createElement("chui_ap_row");
24
+ #chuiAt = document.createElement("audio");
25
25
  // Управление
26
- #chui_ap_play_pause = document.createElement("chui_ap_play_pause");
27
- #chui_ap_info = document.createElement("chui_ap_info");
28
- #chui_ap_time1 = undefined;
29
- #chui_ap_time2 = undefined;
30
- #chui_ap_seek_block = document.createElement("chui_ap_seek_block");
31
- #chui_ap_seek = document.createElement("input");
32
- #chui_ap_seek_buf = document.createElement("chui_ap_seek_buf");
33
- #chui_ap_volume_block = document.createElement("chui_ap_volume_block");
34
- #chui_ap_volume_icon = document.createElement("chui_ap_volume_icon");
35
- #chui_ap_volume = document.createElement("input");
26
+ #chuiApPlayPause = document.createElement("chui_ap_play_pause");
27
+ #chuiApInfo = document.createElement("chui_ap_info");
28
+ #chuiApTime1 = undefined;
29
+ #chuiApTime2 = undefined;
30
+ #chuiApSeekBlock = document.createElement("chui_ap_seek_block");
31
+ #chuiApSeek = document.createElement("input");
32
+ #chuiApSeekBuf = document.createElement("chui_ap_seek_buf");
33
+ #chuiApVolumeBlock = document.createElement("chui_ap_volume_block");
34
+ #chuiApVolumeIcon = document.createElement("chui_ap_volume_icon");
35
+ #chuiApVolume = document.createElement("input");
36
36
  // Эквалайзер
37
- #chui_ap_fx_icon = document.createElement("chui_ap_fx_icon");
38
- #chui_ap_fx_dropdown = document.createElement("chui_ap_fx_dropdown");
39
- #chui_audio_fx = new AudioFX(this.#chui_at);
37
+ #chuiApFxIcon = document.createElement("chui_ap_fx_icon");
38
+ #chuiApFxDropdown = document.createElement("chui_ap_fx_dropdown");
39
+ #chuiAudioFx = new AudioFX(this.#chuiAt);
40
40
  // Состояние
41
41
  #status = document.createElement("div");
42
42
  #pin = false;
@@ -65,99 +65,99 @@ class Audio {
65
65
  }
66
66
  ) {
67
67
  require("../../modules/chui_functions").setStyles(__dirname + "/audio_styles.css", "chUiJS_Audio");
68
- this.#chui_at.preload = "metadata";
69
- this.#chui_at.controls = false;
68
+ this.#chuiAt.preload = "metadata";
69
+ this.#chuiAt.controls = false;
70
70
  // Плеер — именованная группа: без имени скринридер читает подряд безымянные кнопки
71
- this.#chui_ap_main.setAttribute("role", "group");
72
- this.#chui_ap_main.setAttribute("aria-label", optionOr(options.label, I18n.t("media.audioPlayer")));
71
+ this.#chuiApMain.setAttribute("role", "group");
72
+ this.#chuiApMain.setAttribute("aria-label", optionOr(options.label, I18n.t("media.audioPlayer")));
73
73
  // НАСТРОЙКИ
74
- if (options.src !== undefined) this.#chui_at.setAttribute("src", options.src);
75
- if (options.autoplay !== undefined) this.#chui_at.autoplay = options.autoplay === true;
76
- if (options.loop !== undefined) this.#chui_at.loop = options.loop === true;
77
- if (options.muted !== undefined) this.#chui_at.muted = options.muted === true;
78
- this.#chui_at.volume = options.volume === undefined ? 1 : Math.min(1, Math.max(0, Number(options.volume)));
79
- if (options.width !== undefined) this.#chui_ap_main.style.width = options.width;
80
- if (options.height !== undefined) this.#chui_ap_main.style.height = options.height;
74
+ if (options.src !== undefined) this.#chuiAt.setAttribute("src", options.src);
75
+ if (options.autoplay !== undefined) this.#chuiAt.autoplay = options.autoplay === true;
76
+ if (options.loop !== undefined) this.#chuiAt.loop = options.loop === true;
77
+ if (options.muted !== undefined) this.#chuiAt.muted = options.muted === true;
78
+ this.#chuiAt.volume = options.volume === undefined ? 1 : Math.min(1, Math.max(0, Number(options.volume)));
79
+ if (options.width !== undefined) this.#chuiApMain.style.width = options.width;
80
+ if (options.height !== undefined) this.#chuiApMain.style.height = options.height;
81
81
  // ПОЛОСА ПРОГРЕССА
82
- this.#chui_ap_time1 = new Label({ text: `0:00` });
83
- this.#chui_ap_time2 = new Label({ text: `0:00` });
84
- this.#chui_ap_seek.type = "range";
85
- this.#chui_ap_seek.id = "chui_ap_seek";
86
- this.#chui_ap_seek.max = "0";
87
- this.#chui_ap_seek.value = "0";
88
- this.#chui_ap_seek.step = "any";
89
- this.#chui_ap_seek.setAttribute("aria-label", I18n.t("media.position"));
82
+ this.#chuiApTime1 = new Label({ text: `0:00` });
83
+ this.#chuiApTime2 = new Label({ text: `0:00` });
84
+ this.#chuiApSeek.type = "range";
85
+ this.#chuiApSeek.id = "chui_ap_seek";
86
+ this.#chuiApSeek.max = "0";
87
+ this.#chuiApSeek.value = "0";
88
+ this.#chuiApSeek.step = "any";
89
+ this.#chuiApSeek.setAttribute("aria-label", I18n.t("media.position"));
90
90
  // До метаданных длительность неизвестна: ползунок включается в #setSliderMax()
91
91
  this.#setSliderMax();
92
- this.#chui_ap_seek_block.appendChild(this.#chui_ap_seek);
93
- this.#chui_ap_seek_block.appendChild(this.#chui_ap_seek_buf);
94
- this.#chui_ap_info.appendChild(this.#chui_ap_time1.set());
95
- this.#chui_ap_info.appendChild(this.#chui_ap_seek_block);
96
- this.#chui_ap_info.appendChild(this.#chui_ap_time2.set());
97
- // КНОПКИ
98
- this.#setButton(this.#chui_ap_play_pause, I18n.t("media.play"), Icons.AUDIO_VIDEO.PLAY_ARROW, "18px");
99
- this.#setButton(this.#chui_ap_volume_icon, I18n.t("media.mute"), Icons.AUDIO_VIDEO.VOLUME_UP, "18px");
100
- this.#setButton(this.#chui_ap_fx_icon, I18n.t("media.equalizer"), Icons.AUDIO_VIDEO.EQUALIZER, "18px");
92
+ this.#chuiApSeekBlock.appendChild(this.#chuiApSeek);
93
+ this.#chuiApSeekBlock.appendChild(this.#chuiApSeekBuf);
94
+ this.#chuiApInfo.appendChild(this.#chuiApTime1.set());
95
+ this.#chuiApInfo.appendChild(this.#chuiApSeekBlock);
96
+ this.#chuiApInfo.appendChild(this.#chuiApTime2.set());
97
+ // КНОПКИ: кегль глифа задаёт стиль кнопки (--player_icon_size), значок его наследует
98
+ this.#setButton(this.#chuiApPlayPause, I18n.t("media.play"), Icons.AUDIO_VIDEO.PLAY_ARROW);
99
+ this.#setButton(this.#chuiApVolumeIcon, I18n.t("media.mute"), Icons.AUDIO_VIDEO.VOLUME_UP);
100
+ this.#setButton(this.#chuiApFxIcon, I18n.t("media.equalizer"), Icons.AUDIO_VIDEO.EQUALIZER);
101
101
  // ГРОМКОСТЬ
102
- this.#chui_ap_volume.type = "range";
103
- this.#chui_ap_volume.id = "chui_ap_volume";
104
- this.#chui_ap_volume.max = "100";
105
- this.#chui_ap_volume.value = String(Math.round(this.#chui_at.volume * 100));
106
- this.#chui_ap_volume.step = "1";
107
- this.#chui_ap_volume.setAttribute("aria-label", I18n.t("media.volume"));
108
- this.#chui_ap_volume_block.appendChild(this.#chui_ap_volume_icon);
109
- this.#chui_ap_volume_block.appendChild(this.#chui_ap_volume);
110
- this.#chui_ap_volume_block.appendChild(this.#chui_ap_fx_icon);
102
+ this.#chuiApVolume.type = "range";
103
+ this.#chuiApVolume.id = "chui_ap_volume";
104
+ this.#chuiApVolume.max = "100";
105
+ this.#chuiApVolume.value = String(Math.round(this.#chuiAt.volume * 100));
106
+ this.#chuiApVolume.step = "1";
107
+ this.#chuiApVolume.setAttribute("aria-label", I18n.t("media.volume"));
108
+ this.#chuiApVolumeBlock.appendChild(this.#chuiApVolumeIcon);
109
+ this.#chuiApVolumeBlock.appendChild(this.#chuiApVolume);
110
+ this.#chuiApVolumeBlock.appendChild(this.#chuiApFxIcon);
111
111
  // СБОРКА: одна строка — воспроизведение, прогресс со временем, звук и эквалайзер
112
- this.#chui_ap_row.appendChild(this.#chui_ap_play_pause);
113
- this.#chui_ap_row.appendChild(this.#chui_ap_info);
114
- this.#chui_ap_row.appendChild(this.#chui_ap_volume_block);
115
- this.#chui_ap_block.appendChild(this.#chui_ap_row);
112
+ this.#chuiApRow.appendChild(this.#chuiApPlayPause);
113
+ this.#chuiApRow.appendChild(this.#chuiApInfo);
114
+ this.#chuiApRow.appendChild(this.#chuiApVolumeBlock);
115
+ this.#chuiApBlock.appendChild(this.#chuiApRow);
116
116
  // Эквалайзер — секция внутри карточки, под полосой управления: наложением он быть
117
117
  // не может, у карточки `overflow: hidden` (её скругление)
118
- this.#chui_ap_block.appendChild(this.#chui_ap_fx_dropdown);
119
- this.#chui_ap_fx_dropdown.appendChild(this.#chui_audio_fx.set());
120
- this.#chui_ap_main.appendChild(this.#chui_at);
121
- this.#chui_ap_main.appendChild(this.#chui_ap_block);
118
+ this.#chuiApBlock.appendChild(this.#chuiApFxDropdown);
119
+ this.#chuiApFxDropdown.appendChild(this.#chuiAudioFx.set());
120
+ this.#chuiApMain.appendChild(this.#chuiAt);
121
+ this.#chuiApMain.appendChild(this.#chuiApBlock);
122
122
  // О смене состояния и ошибках сообщает скрытый live-регион
123
123
  this.#status.classList.add("chui_visually_hidden");
124
124
  this.#status.setAttribute("role", "status");
125
125
  this.#status.setAttribute("aria-live", "polite");
126
- this.#chui_ap_main.appendChild(this.#status);
126
+ this.#chuiApMain.appendChild(this.#status);
127
127
  // СОБЫТИЯ
128
128
  // Состояние кнопки идёт от самого элемента: play() может отклониться политикой
129
129
  // автозапуска, и «пауза» на кнопке была бы неправдой
130
- this.#chui_at.addEventListener("play", this.#onPlay);
131
- this.#chui_at.addEventListener("pause", this.#onPause);
132
- this.#chui_at.addEventListener("timeupdate", this.#onTimeUpdate);
133
- this.#chui_at.addEventListener("loadedmetadata", this.#onDurationChange);
134
- this.#chui_at.addEventListener("durationchange", this.#onDurationChange);
135
- this.#chui_at.addEventListener("progress", () => this.#displayBufferedAmount());
136
- this.#chui_at.addEventListener("volumechange", () => this.#renderVolume());
137
- this.#chui_at.addEventListener("error", () => this.#onMediaError());
138
- this.#chui_ap_play_pause.addEventListener("click", () => this.#playPause());
139
- this.#chui_ap_volume_icon.addEventListener("click", () => this.setMuted(!this.getMuted()));
140
- this.#chui_ap_seek.addEventListener("input", () => {
141
- this.#chui_at.currentTime = Number(Number(this.#chui_ap_seek.value).toFixed(6));
130
+ this.#chuiAt.addEventListener("play", this.#onPlay);
131
+ this.#chuiAt.addEventListener("pause", this.#onPause);
132
+ this.#chuiAt.addEventListener("timeupdate", this.#onTimeUpdate);
133
+ this.#chuiAt.addEventListener("loadedmetadata", this.#onDurationChange);
134
+ this.#chuiAt.addEventListener("durationchange", this.#onDurationChange);
135
+ this.#chuiAt.addEventListener("progress", () => this.#displayBufferedAmount());
136
+ this.#chuiAt.addEventListener("volumechange", () => this.#renderVolume());
137
+ this.#chuiAt.addEventListener("error", () => this.#onMediaError());
138
+ this.#chuiApPlayPause.addEventListener("click", () => this.#playPause());
139
+ this.#chuiApVolumeIcon.addEventListener("click", () => this.setMuted(!this.getMuted()));
140
+ this.#chuiApSeek.addEventListener("input", () => {
141
+ this.#chuiAt.currentTime = Number(Number(this.#chuiApSeek.value).toFixed(6));
142
142
  this.#renderProgress();
143
143
  });
144
- this.#chui_ap_volume.addEventListener("input", () => {
145
- this.#chui_at.volume = Number(this.#chui_ap_volume.value) / 100;
146
- this.#chui_at.muted = false;
144
+ this.#chuiApVolume.addEventListener("input", () => {
145
+ this.#chuiAt.volume = Number(this.#chuiApVolume.value) / 100;
146
+ this.#chuiAt.muted = false;
147
147
  });
148
148
  // ЭКВАЛАЙЗЕР: панель открывает кнопка, закрывают повторное нажатие, клик мимо и Escape
149
- this.#chui_ap_fx_icon.setAttribute("aria-haspopup", "true");
150
- this.#chui_ap_fx_icon.setAttribute("aria-expanded", "false");
151
- this.#chui_ap_fx_icon.addEventListener("click", (event) => {
149
+ this.#chuiApFxIcon.setAttribute("aria-haspopup", "true");
150
+ this.#chuiApFxIcon.setAttribute("aria-expanded", "false");
151
+ this.#chuiApFxIcon.addEventListener("click", (event) => {
152
152
  // Клик по кнопке не должен тут же закрывать панель общим обработчиком окна
153
153
  event.stopPropagation();
154
154
  this.#toggleFx();
155
155
  });
156
- this.#chui_ap_fx_dropdown.addEventListener("keydown", (event) => {
156
+ this.#chuiApFxDropdown.addEventListener("keydown", (event) => {
157
157
  if (event.key !== "Escape") return;
158
158
  event.preventDefault();
159
159
  this.#toggleFx(false);
160
- this.#chui_ap_fx_icon.focus();
160
+ this.#chuiApFxIcon.focus();
161
161
  });
162
162
  this.#setMediaActions();
163
163
  this.#renderPlayState(false);
@@ -165,17 +165,17 @@ class Audio {
165
165
  this.setPin(options.pin === undefined ? false : options.pin);
166
166
  }
167
167
  #toggleFx(open = undefined) {
168
- const следующий = open === undefined ? !this.#chui_ap_fx_dropdown.classList.contains("fx_open") : open;
169
- if (следующий === this.#chui_ap_fx_dropdown.classList.contains("fx_open")) return;
170
- this.#chui_ap_fx_dropdown.classList.toggle("fx_open", следующий);
171
- this.#chui_ap_fx_icon.classList.toggle("fx_icon_open", следующий);
172
- this.#chui_ap_fx_icon.setAttribute("aria-expanded", String(следующий));
168
+ const следующий = open === undefined ? !this.#chuiApFxDropdown.classList.contains("fx_open") : open;
169
+ if (следующий === this.#chuiApFxDropdown.classList.contains("fx_open")) return;
170
+ this.#chuiApFxDropdown.classList.toggle("fx_open", следующий);
171
+ this.#chuiApFxIcon.classList.toggle("fx_icon_open", следующий);
172
+ this.#chuiApFxIcon.setAttribute("aria-expanded", String(следующий));
173
173
  if (следующий) document.addEventListener("mousedown", this.#onFxOutside);
174
174
  else document.removeEventListener("mousedown", this.#onFxOutside);
175
175
  }
176
176
  #onFxOutside = (event) => {
177
- if (this.#chui_ap_fx_dropdown.contains(event.target)) return;
178
- if (this.#chui_ap_fx_icon.contains(event.target)) return;
177
+ if (this.#chuiApFxDropdown.contains(event.target)) return;
178
+ if (this.#chuiApFxIcon.contains(event.target)) return;
179
179
  this.#toggleFx(false);
180
180
  };
181
181
  #playPause = async () => {
@@ -188,31 +188,26 @@ class Audio {
188
188
  } else this.pause();
189
189
  };
190
190
  #renderPlayState(playing) {
191
- this.#setIcon(
192
- this.#chui_ap_play_pause,
193
- playing ? Icons.AUDIO_VIDEO.PAUSE : Icons.AUDIO_VIDEO.PLAY_ARROW,
194
- "18px"
195
- );
196
- this.#setLabel(this.#chui_ap_play_pause, playing ? I18n.t("media.pause") : I18n.t("media.play"));
191
+ this.#setIcon(this.#chuiApPlayPause, playing ? Icons.AUDIO_VIDEO.PAUSE : Icons.AUDIO_VIDEO.PLAY_ARROW);
192
+ this.#setLabel(this.#chuiApPlayPause, playing ? I18n.t("media.pause") : I18n.t("media.play"));
197
193
  }
198
194
  #renderVolume = () => {
199
- const доля = Math.min(100, Math.max(0, Math.round(this.#chui_at.volume * 100)));
200
- this.#chui_ap_volume.value = String(доля);
201
- this.#chui_ap_volume.disabled = this.getMuted();
202
- this.#chui_ap_main.style.setProperty("--volume-before-width", `${доля}%`);
195
+ const доля = Math.min(100, Math.max(0, Math.round(this.#chuiAt.volume * 100)));
196
+ this.#chuiApVolume.value = String(доля);
197
+ this.#chuiApVolume.disabled = this.getMuted();
198
+ this.#chuiApMain.style.setProperty("--volume_before_width", `${доля}%`);
203
199
  this.#setIcon(
204
- this.#chui_ap_volume_icon,
205
- this.getMuted() || доля === 0 ? Icons.AUDIO_VIDEO.VOLUME_OFF : Icons.AUDIO_VIDEO.VOLUME_UP,
206
- "18px"
200
+ this.#chuiApVolumeIcon,
201
+ this.getMuted() || доля === 0 ? Icons.AUDIO_VIDEO.VOLUME_OFF : Icons.AUDIO_VIDEO.VOLUME_UP
207
202
  );
208
- this.#setLabel(this.#chui_ap_volume_icon, I18n.t(this.getMuted() ? "media.unmute" : "media.mute"));
203
+ this.#setLabel(this.#chuiApVolumeIcon, I18n.t(this.getMuted() ? "media.unmute" : "media.mute"));
209
204
  };
210
205
  #displayBufferedAmount = () => {
211
- const max = Number(this.#chui_ap_seek.max);
206
+ const max = Number(this.#chuiApSeek.max);
212
207
  if (!(max > 0)) return;
213
208
  try {
214
- const конец = Math.floor((this.#chui_at.buffered.end(0) / max) * 100);
215
- this.#chui_ap_seek_buf.style.width = `${Math.min(100, Math.max(0, конец))}%`;
209
+ const конец = Math.floor((this.#chuiAt.buffered.end(0) / max) * 100);
210
+ this.#chuiApSeekBuf.style.width = `${Math.min(100, Math.max(0, конец))}%`;
216
211
  } catch (_error) {
217
212
  // Буфер ещё пуст (метаданные не пришли) — рисовать нечего
218
213
  }
@@ -222,28 +217,28 @@ class Audio {
222
217
  #setSliderMax = () => {
223
218
  const duration = this.getDuration();
224
219
  const известна = Number.isFinite(duration) && duration > 0;
225
- this.#chui_ap_seek.max = известна ? String(Math.floor(duration)) : "0";
220
+ this.#chuiApSeek.max = известна ? String(Math.floor(duration)) : "0";
226
221
  // Без известной длительности ползунок бессмысленен: перетаскивание отправляло бы плеер в начало
227
- this.#chui_ap_seek.disabled = !известна;
222
+ this.#chuiApSeek.disabled = !известна;
228
223
  };
229
224
  #renderProgress = () => {
230
- const max = Number(this.#chui_ap_seek.max);
225
+ const max = Number(this.#chuiApSeek.max);
231
226
  const position = this.getCurrentTime();
232
227
  const duration = this.getDuration();
233
228
  if (!(max > 0)) {
234
229
  // «0:07 / 0:00» читалось бы как поломка: у источника без длительности только прошедшее
235
- this.#chui_ap_time1.setText(this.#calculateTime(position));
236
- this.#chui_ap_time2.setText("");
237
- this.#chui_ap_main.style.setProperty("--seek-before-width", "0%");
230
+ this.#chuiApTime1.setText(this.#calculateTime(position));
231
+ this.#chuiApTime2.setText("");
232
+ this.#chuiApMain.style.setProperty("--seek_before_width", "0%");
238
233
  return;
239
234
  }
240
- this.#chui_ap_time1.setText(this.#calculateTime(position));
241
- this.#chui_ap_time2.setText(this.#calculateTime(duration));
242
- this.#chui_ap_seek.value = String(position);
235
+ this.#chuiApTime1.setText(this.#calculateTime(position));
236
+ this.#chuiApTime2.setText(this.#calculateTime(duration));
237
+ this.#chuiApSeek.value = String(position);
243
238
  // Доля ограничена сотней: `max` — округлённая длительность, а позиция идёт дальше,
244
239
  // и без ограничения полоса целиком заливалась акцентом
245
240
  const доля = Math.min(100, Math.max(0, Math.floor((position / max) * 100)));
246
- this.#chui_ap_main.style.setProperty("--seek-before-width", `${доля}%`);
241
+ this.#chuiApMain.style.setProperty("--seek_before_width", `${доля}%`);
247
242
  };
248
243
  #calculateTime = (secs) => {
249
244
  const seconds = Number.isFinite(Number(secs)) ? Number(secs) : 0;
@@ -252,7 +247,7 @@ class Audio {
252
247
  return `${minutes}:${rest < 10 ? `0${rest}` : `${rest}`}`;
253
248
  };
254
249
  #onMediaError = () => {
255
- const код = this.#chui_at.error === null ? undefined : this.#chui_at.error.code;
250
+ const код = this.#chuiAt.error === null ? undefined : this.#chuiAt.error.code;
256
251
  const причина = Audio.#ERRORS[код] === undefined ? "" : `: ${I18n.t(Audio.#ERRORS[код])}`;
257
252
  Log.error(`Audio: ошибка воспроизведения${причина}`);
258
253
  this.#setStatus(`${I18n.t("media.audioNotPlaying", { reason: I18n.t("media.error.interrupted") })}${причина}`);
@@ -260,13 +255,13 @@ class Audio {
260
255
  #setStatus(text) {
261
256
  this.#status.innerText = text;
262
257
  }
263
- #setButton(node, label, icon, size) {
264
- node.innerHTML = new Icon(icon, size).getHTML();
258
+ #setButton(node, label, icon) {
259
+ node.innerHTML = new Icon(icon).getHTML();
265
260
  node.setAttribute("aria-label", label);
266
261
  makeKeyboardButton(node);
267
262
  }
268
- #setIcon(node, icon, size) {
269
- const глиф = new Icon(icon, size).getHTML();
263
+ #setIcon(node, icon) {
264
+ const глиф = new Icon(icon).getHTML();
270
265
  if (node.innerHTML !== глиф) node.innerHTML = глиф;
271
266
  }
272
267
  #setLabel(node, label) {
@@ -305,8 +300,8 @@ class Audio {
305
300
  return this;
306
301
  }
307
302
  this.#pin = значение;
308
- if (значение === false) this.#chui_ap_main.removeAttribute("data_pin");
309
- else this.#chui_ap_main.setAttribute("data_pin", значение);
303
+ if (значение === false) this.#chuiApMain.removeAttribute("data_pin");
304
+ else this.#chuiApMain.setAttribute("data_pin", значение);
310
305
  return this;
311
306
  }
312
307
  getPin() {
@@ -315,10 +310,10 @@ class Audio {
315
310
  // === ЭКВАЛАЙЗЕР ===
316
311
  /** Включить или выключить эквалайзер: то же, что делает выключатель в панели */
317
312
  setEqualizerEnabled(boolean = Boolean()) {
318
- return (this.#chui_audio_fx.setEnabled(boolean), this);
313
+ return (this.#chuiAudioFx.setEnabled(boolean), this);
319
314
  }
320
315
  isEqualizerEnabled() {
321
- return this.#chui_audio_fx.isEnabled();
316
+ return this.#chuiAudioFx.isEnabled();
322
317
  }
323
318
  /** Раскрыть или свернуть панель эквалайзера */
324
319
  setEqualizerOpen(open = Boolean()) {
@@ -327,142 +322,142 @@ class Audio {
327
322
  }
328
323
  /** Показать панель эквалайзера, если она скрыта, и наоборот */
329
324
  isEqualizerOpen() {
330
- return this.#chui_ap_fx_dropdown.classList.contains("fx_open");
325
+ return this.#chuiApFxDropdown.classList.contains("fx_open");
331
326
  }
332
327
  /** Прочитать сохранённое состояние эквалайзера из настроек */
333
328
  restoreFX() {
334
- this.#chui_audio_fx.restore();
329
+ this.#chuiAudioFx.restore();
335
330
  return this;
336
331
  }
337
332
  // === СТАНДАРТНЫЕ ВОЗМОЖНОСТИ `<audio>` ===
338
333
  /** Сам элемент: для всего, чего нет в списке ниже */
339
334
  getAudio() {
340
- return this.#chui_at;
335
+ return this.#chuiAt;
341
336
  }
342
337
  /** Воспроизведение: промис, как у `<audio>` */
343
338
  play() {
344
- return this.#chui_at.play();
339
+ return this.#chuiAt.play();
345
340
  }
346
341
  pause() {
347
- this.#chui_at.pause();
342
+ this.#chuiAt.pause();
348
343
  return this;
349
344
  }
350
345
  load() {
351
- this.#chui_at.load();
346
+ this.#chuiAt.load();
352
347
  return this;
353
348
  }
354
349
  canPlayType(type = String()) {
355
- return this.#chui_at.canPlayType(type);
350
+ return this.#chuiAt.canPlayType(type);
356
351
  }
357
352
  getSrc() {
358
- return this.#chui_at.getAttribute("src") ?? "";
353
+ return this.#chuiAt.getAttribute("src") ?? "";
359
354
  }
360
355
  setSrc(url = String()) {
361
- this.#chui_at.setAttribute("src", url);
362
- this.#chui_at.load();
356
+ this.#chuiAt.setAttribute("src", url);
357
+ this.#chuiAt.load();
363
358
  return this;
364
359
  }
365
360
  getSrcObject() {
366
- return this.#chui_at.srcObject;
361
+ return this.#chuiAt.srcObject;
367
362
  }
368
363
  /** Живой поток — штатное `srcObject`, а не путь */
369
364
  setSrcObject(object) {
370
- this.#chui_at.srcObject = object;
365
+ this.#chuiAt.srcObject = object;
371
366
  return this;
372
367
  }
373
368
  getCurrentTime() {
374
- return this.#chui_at.currentTime;
369
+ return this.#chuiAt.currentTime;
375
370
  }
376
371
  setCurrentTime(seconds = Number()) {
377
- this.#chui_at.currentTime = Number(seconds);
372
+ this.#chuiAt.currentTime = Number(seconds);
378
373
  // Подписи и заливка не ждут `timeupdate`: перемотка из кода видна сразу
379
374
  this.#renderProgress();
380
375
  return this;
381
376
  }
382
377
  getDuration() {
383
- return this.#chui_at.duration;
378
+ return this.#chuiAt.duration;
384
379
  }
385
380
  getBuffered() {
386
- return this.#chui_at.buffered;
381
+ return this.#chuiAt.buffered;
387
382
  }
388
383
  getPaused() {
389
- return this.#chui_at.paused;
384
+ return this.#chuiAt.paused;
390
385
  }
391
386
  getEnded() {
392
- return this.#chui_at.ended;
387
+ return this.#chuiAt.ended;
393
388
  }
394
389
  getReadyState() {
395
- return this.#chui_at.readyState;
390
+ return this.#chuiAt.readyState;
396
391
  }
397
392
  getVolume() {
398
- return this.#chui_at.volume;
393
+ return this.#chuiAt.volume;
399
394
  }
400
395
  setVolume(value = Number()) {
401
- this.#chui_at.volume = Math.min(1, Math.max(0, Number(value)));
396
+ this.#chuiAt.volume = Math.min(1, Math.max(0, Number(value)));
402
397
  return this;
403
398
  }
404
399
  getMuted() {
405
- return this.#chui_at.muted;
400
+ return this.#chuiAt.muted;
406
401
  }
407
402
  setMuted(boolean = Boolean()) {
408
- this.#chui_at.muted = boolean === true;
403
+ this.#chuiAt.muted = boolean === true;
409
404
  return this;
410
405
  }
411
406
  getPlaybackRate() {
412
- return this.#chui_at.playbackRate;
407
+ return this.#chuiAt.playbackRate;
413
408
  }
414
409
  setPlaybackRate(rate = Number()) {
415
- this.#chui_at.playbackRate = Number(rate);
410
+ this.#chuiAt.playbackRate = Number(rate);
416
411
  return this;
417
412
  }
418
413
  getDefaultPlaybackRate() {
419
- return this.#chui_at.defaultPlaybackRate;
414
+ return this.#chuiAt.defaultPlaybackRate;
420
415
  }
421
416
  setDefaultPlaybackRate(rate = Number()) {
422
- this.#chui_at.defaultPlaybackRate = Number(rate);
417
+ this.#chuiAt.defaultPlaybackRate = Number(rate);
423
418
  return this;
424
419
  }
425
420
  getLoop() {
426
- return this.#chui_at.loop;
421
+ return this.#chuiAt.loop;
427
422
  }
428
423
  setLoop(boolean = Boolean()) {
429
- this.#chui_at.loop = boolean === true;
424
+ this.#chuiAt.loop = boolean === true;
430
425
  return this;
431
426
  }
432
427
  getAutoplay() {
433
- return this.#chui_at.autoplay;
428
+ return this.#chuiAt.autoplay;
434
429
  }
435
430
  setAutoplay(boolean = Boolean()) {
436
- this.#chui_at.autoplay = boolean === true;
431
+ this.#chuiAt.autoplay = boolean === true;
437
432
  return this;
438
433
  }
439
434
  addEventListener(type = String(), listener = () => {}) {
440
- this.#chui_at.addEventListener(type, listener);
435
+ this.#chuiAt.addEventListener(type, listener);
441
436
  return this;
442
437
  }
443
438
  removeEventListener(type = String(), listener = () => {}) {
444
- this.#chui_at.removeEventListener(type, listener);
439
+ this.#chuiAt.removeEventListener(type, listener);
445
440
  return this;
446
441
  }
447
442
  set() {
448
- return this.#chui_ap_main;
443
+ return this.#chuiApMain;
449
444
  }
450
445
  detach() {
451
446
  this.pause();
452
- this.#chui_ap_main.remove();
447
+ this.#chuiApMain.remove();
453
448
  return this;
454
449
  }
455
450
  /** Остановить плеер и снять всё, что живёт вне его узлов. Повторный вызов безопасен */
456
451
  destroy() {
457
452
  if (this.#destroyed) return this;
458
453
  this.#destroyed = true;
459
- this.#chui_at.pause();
460
- this.#chui_at.removeAttribute("src");
461
- this.#chui_at.load(); // отпускает декодер и прочитанный файл
454
+ this.#chuiAt.pause();
455
+ this.#chuiAt.removeAttribute("src");
456
+ this.#chuiAt.load(); // отпускает декодер и прочитанный файл
462
457
  this.#unsetMediaActions();
463
458
  document.removeEventListener("mousedown", this.#onFxOutside);
464
- this.#chui_audio_fx.destroy();
465
- if (this.#chui_ap_main.parentElement !== null) this.#chui_ap_main.remove();
459
+ this.#chuiAudioFx.destroy();
460
+ if (this.#chuiApMain.parentElement !== null) this.#chuiApMain.remove();
466
461
  return this;
467
462
  }
468
463
  static #ERRORS = {
@@ -473,11 +468,11 @@ class Audio {
473
468
  };
474
469
  }
475
470
  class AudioFX {
476
- #chui_ap_equalizer_main = document.createElement("chui_ap_equalizer_main");
477
- #chui_ap_equalizer_controls = document.createElement("chui_ap_equalizer_controls");
478
- #chui_ap_equalizer_block = document.createElement("chui_ap_equalizer_block");
479
- #chui_ap_equalizer_preamp_block = document.createElement("chui_ap_equalizer_preamp_block");
480
- #chui_ap_equalizer_band_block = document.createElement("chui_ap_equalizer_band_block");
471
+ #chuiApEqualizerMain = document.createElement("chui_ap_equalizer_main");
472
+ #chuiApEqualizerControls = document.createElement("chui_ap_equalizer_controls");
473
+ #chuiApEqualizerBlock = document.createElement("chui_ap_equalizer_block");
474
+ #chuiApEqualizerPreampBlock = document.createElement("chui_ap_equalizer_preamp_block");
475
+ #chuiApEqualizerBandBlock = document.createElement("chui_ap_equalizer_band_block");
481
476
  /* Поле пресетов и переключатель — общекитовые `Select` и `Toggle`, вложенные в панель:
482
477
  клавиатура, роли и состояния у них уже есть, а размеры для полосы панели задаёт
483
478
  `audio_styles.css`. Прежде тут были свои элементы, и список пресетов ломался:
@@ -490,14 +485,14 @@ class AudioFX {
490
485
  #nodes = new Map();
491
486
  #media = undefined;
492
487
  #filters = undefined;
493
- #fx_status = "chuijs.framework.settings.fx_status";
494
- #fx_preset = "chuijs.framework.settings.fx_preset";
488
+ #fxStatus = "chuijs.framework.settings.fx_status";
489
+ #fxPreset = "chuijs.framework.settings.fx_preset";
495
490
  #audioContext = new AudioContext();
496
491
  #destroyed = false;
497
492
  constructor(audio) {
498
493
  this.#media = this.#audioContext.createMediaElementSource(audio);
499
494
  this.#filters = this.#eqBands.map((band, i) => {
500
- let filter = this.#audioContext.createBiquadFilter();
495
+ const filter = this.#audioContext.createBiquadFilter();
501
496
  if (i === 0) {
502
497
  filter.type = "lowshelf";
503
498
  } else if (i === this.#eqBands.length - 1) {
@@ -517,8 +512,8 @@ class AudioFX {
517
512
  this.#media.connect(this.#filters[0]);
518
513
  this.#filters[this.#filters.length - 1].connect(this.#audioContext.destination);
519
514
  //
520
- this.#chui_ap_equalizer_preamp_block.appendChild(this.#setSliderPreamp(this.#filters));
521
- this.#filters.forEach((filter) => this.#chui_ap_equalizer_band_block.appendChild(this.#setSliderBand(filter)));
515
+ this.#chuiApEqualizerPreampBlock.appendChild(this.#setSliderPreamp(this.#filters));
516
+ this.#filters.forEach((filter) => this.#chuiApEqualizerBandBlock.appendChild(this.#setSliderBand(filter)));
522
517
  // Пресеты: подпись варианта — перевод, значение — имя пресета, поэтому выбор
523
518
  // читается из события списка, а не сверкой подписи
524
519
  this.#presets.addOptions(
@@ -533,18 +528,18 @@ class AudioFX {
533
528
  this.#presets.addValueChangeListener((event) => this.#usePreset(event.detail.value));
534
529
  // Переключатель — общекитовый `Toggle`; подпись он отдаёт в `aria-label`
535
530
  this.#switch.addChangeListener(() => {
536
- if (this.#switch.getValue()) this.#fx_ON(this.#audioContext);
537
- else this.#fx_OFF(this.#audioContext);
531
+ if (this.#switch.getValue()) this.#fxON(this.#audioContext);
532
+ else this.#fxOFF(this.#audioContext);
538
533
  });
539
534
  //
540
- this.#chui_ap_equalizer_controls.appendChild(this.#presets.set());
541
- this.#chui_ap_equalizer_controls.appendChild(this.#switch.set());
535
+ this.#chuiApEqualizerControls.appendChild(this.#presets.set());
536
+ this.#chuiApEqualizerControls.appendChild(this.#switch.set());
542
537
  //
543
- this.#chui_ap_equalizer_block.appendChild(this.#chui_ap_equalizer_preamp_block);
544
- this.#chui_ap_equalizer_block.appendChild(this.#chui_ap_equalizer_band_block);
538
+ this.#chuiApEqualizerBlock.appendChild(this.#chuiApEqualizerPreampBlock);
539
+ this.#chuiApEqualizerBlock.appendChild(this.#chuiApEqualizerBandBlock);
545
540
  //
546
- this.#chui_ap_equalizer_main.appendChild(this.#chui_ap_equalizer_controls);
547
- this.#chui_ap_equalizer_main.appendChild(this.#chui_ap_equalizer_block);
541
+ this.#chuiApEqualizerMain.appendChild(this.#chuiApEqualizerControls);
542
+ this.#chuiApEqualizerMain.appendChild(this.#chuiApEqualizerBlock);
548
543
  // По умолчанию эквалайзер выключен — и вид полосы должен говорить то же: пока
549
544
  // `restoreFX()` не позвал хозяин, выключатель выключен, а дорожки уже серые
550
545
  this.#setStatusBlock(false);
@@ -558,7 +553,7 @@ class AudioFX {
558
553
  const known = AudioFX.PRESETS.some((preset) => preset.name === name);
559
554
  this.#presets.setValue(known ? name : AudioFX.PRESETS[0].name, true);
560
555
  }
561
- #fx_ON(audioContext) {
556
+ #fxON(audioContext) {
562
557
  try {
563
558
  this.#media.disconnect(audioContext.destination);
564
559
  this.#media.connect(this.#filters[0]);
@@ -567,25 +562,25 @@ class AudioFX {
567
562
  this.#media.connect(this.#filters[0]);
568
563
  this.#filters[this.#filters.length - 1].connect(audioContext.destination);
569
564
  }
570
- store.delete(this.#fx_status);
571
- store.set(this.#fx_status, true);
565
+ store.delete(this.#fxStatus);
566
+ store.set(this.#fxStatus, true);
572
567
  this.#setStatusBlock(true);
573
568
  }
574
- #fx_OFF(audioContext) {
569
+ #fxOFF(audioContext) {
575
570
  this.#filters[this.#filters.length - 1].disconnect(audioContext.destination);
576
571
  this.#media.disconnect(this.#filters[0]);
577
572
  this.#media.connect(audioContext.destination);
578
- store.delete(this.#fx_status);
579
- store.set(this.#fx_status, false);
573
+ store.delete(this.#fxStatus);
574
+ store.set(this.#fxStatus, false);
580
575
  this.#setStatusBlock(false);
581
576
  }
582
577
  #setPreset(filter, name) {
583
- store.delete(this.#fx_preset);
584
- store.set(this.#fx_preset, name);
585
- let filter_test = this.#getPreset(name);
586
- this.#renderPreampSlider(undefined, filter_test, filter);
587
- let input = filter_test.inputs.filter((input) => input.id === String(filter.frequency.value))[0];
588
- this.#renderSlider(input, filter, filter_test.preamp);
578
+ store.delete(this.#fxPreset);
579
+ store.set(this.#fxPreset, name);
580
+ const preset = this.#getPreset(name);
581
+ this.#renderPreampSlider(undefined, preset, filter);
582
+ const input = preset.inputs.filter((input) => input.id === String(filter.frequency.value))[0];
583
+ this.#renderSlider(input, filter, preset.preamp);
589
584
  }
590
585
  #setStatusBlock(status) {
591
586
  //
@@ -594,30 +589,30 @@ class AudioFX {
594
589
  // состоянии не шлёт `change` — включить было бы нечем)
595
590
  this.#presets.setDisabled(!status);
596
591
  //
597
- for (let band of this.#eqBands) {
598
- let sliderBand = this.#node(String(band));
592
+ for (const band of this.#eqBands) {
593
+ const sliderBand = this.#node(String(band));
599
594
  sliderBand.disabled = !status;
600
595
  if (status) {
601
596
  sliderBand.style.cursor = "pointer";
602
- this.#chui_ap_equalizer_preamp_block.classList.remove("chui_ap_equalizer_disabled");
603
- this.#chui_ap_equalizer_band_block.classList.remove("chui_ap_equalizer_disabled");
597
+ this.#chuiApEqualizerPreampBlock.classList.remove("chui_ap_equalizer_disabled");
598
+ this.#chuiApEqualizerBandBlock.classList.remove("chui_ap_equalizer_disabled");
604
599
  } else {
605
600
  sliderBand.style.cursor = "not-allowed";
606
- this.#chui_ap_equalizer_preamp_block.classList.add("chui_ap_equalizer_disabled");
607
- this.#chui_ap_equalizer_band_block.classList.add("chui_ap_equalizer_disabled");
601
+ this.#chuiApEqualizerPreampBlock.classList.add("chui_ap_equalizer_disabled");
602
+ this.#chuiApEqualizerBandBlock.classList.add("chui_ap_equalizer_disabled");
608
603
  }
609
604
  }
610
605
  //
611
- let sliderPreamp = this.#node("preamp");
606
+ const sliderPreamp = this.#node("preamp");
612
607
  sliderPreamp.disabled = !status;
613
608
  if (status) {
614
609
  sliderPreamp.style.cursor = "pointer";
615
- this.#chui_ap_equalizer_preamp_block.classList.remove("chui_ap_equalizer_disabled");
616
- this.#chui_ap_equalizer_band_block.classList.remove("chui_ap_equalizer_disabled");
610
+ this.#chuiApEqualizerPreampBlock.classList.remove("chui_ap_equalizer_disabled");
611
+ this.#chuiApEqualizerBandBlock.classList.remove("chui_ap_equalizer_disabled");
617
612
  } else {
618
613
  sliderPreamp.style.cursor = "not-allowed";
619
- this.#chui_ap_equalizer_preamp_block.classList.add("chui_ap_equalizer_disabled");
620
- this.#chui_ap_equalizer_band_block.classList.add("chui_ap_equalizer_disabled");
614
+ this.#chuiApEqualizerPreampBlock.classList.add("chui_ap_equalizer_disabled");
615
+ this.#chuiApEqualizerBandBlock.classList.add("chui_ap_equalizer_disabled");
621
616
  }
622
617
  }
623
618
  #getPreset(name) {
@@ -628,10 +623,10 @@ class AudioFX {
628
623
  return this.#nodes.get(id);
629
624
  }
630
625
  #setSliderPreamp(filters) {
631
- let sliderMain = document.createElement("chui_eq_slider_main");
632
- let val = document.createElement("slider_label");
633
- let slider = document.createElement("input");
634
- let label = document.createElement("slider_label");
626
+ const sliderMain = document.createElement("chui_eq_slider_main");
627
+ const val = document.createElement("slider_label");
628
+ const slider = document.createElement("input");
629
+ const label = document.createElement("slider_label");
635
630
  sliderMain.id = "preamp_main";
636
631
  slider.id = "preamp";
637
632
  slider.type = "range";
@@ -644,9 +639,8 @@ class AudioFX {
644
639
  slider.setAttribute("aria-valuetext", I18n.t("media.decibels", { value: 0 }));
645
640
  // Доля заливки рельса: заливка рисуется градиентом по тому же числу, что у полос
646
641
  // прогресса и громкости
647
- slider.style.setProperty("--fx-before-width", `50%`);
648
- slider.oninput = (e) =>
649
- this.#renderPreampSlider(e.target, this.#getPreset(store.get(this.#fx_preset)), filters);
642
+ slider.style.setProperty("--fx_before_width", `50%`);
643
+ slider.oninput = (e) => this.#renderPreampSlider(e.target, this.#getPreset(store.get(this.#fxPreset)), filters);
650
644
  val.id = "val_preamp";
651
645
  this.#nodes.set("preamp", slider);
652
646
  this.#nodes.set("val_preamp", val);
@@ -658,27 +652,27 @@ class AudioFX {
658
652
  return sliderMain;
659
653
  }
660
654
  #setSliderBand(filter) {
661
- let freq_value = String(filter.frequency.value);
662
- let sliderMain = document.createElement("chui_eq_slider_main");
663
- let val = document.createElement("slider_label");
664
- let slider = document.createElement("input");
665
- let label = document.createElement("slider_label");
666
- slider.id = freq_value;
655
+ const freqValue = String(filter.frequency.value);
656
+ const sliderMain = document.createElement("chui_eq_slider_main");
657
+ const val = document.createElement("slider_label");
658
+ const slider = document.createElement("input");
659
+ const label = document.createElement("slider_label");
660
+ slider.id = freqValue;
667
661
  slider.type = "range";
668
662
  slider.className = "eq_slider_test";
669
663
  slider.step = "0.1";
670
664
  slider.min = "-10";
671
665
  slider.max = "10";
672
666
  slider.value = String(filter.gain.value);
673
- slider.setAttribute("aria-label", I18n.t("media.hertzGain", { freq: freq_value }));
667
+ slider.setAttribute("aria-label", I18n.t("media.hertzGain", { freq: freqValue }));
674
668
  slider.setAttribute("aria-valuetext", I18n.t("media.decibels", { value: slider.value }));
675
- slider.style.setProperty("--fx-before-width", `50%`);
669
+ slider.style.setProperty("--fx_before_width", `50%`);
676
670
  slider.oninput = (e) => this.#renderSlider(e.target, filter, Number(this.#node("preamp").value));
677
- val.id = "val_" + freq_value;
678
- this.#nodes.set(freq_value, slider);
679
- this.#nodes.set("val_" + freq_value, val);
671
+ val.id = "val_" + freqValue;
672
+ this.#nodes.set(freqValue, slider);
673
+ this.#nodes.set("val_" + freqValue, val);
680
674
  val.innerText = String(slider.value);
681
- label.innerText = freq_value.replace("000", "K");
675
+ label.innerText = freqValue.replace("000", "K");
682
676
  sliderMain.appendChild(val);
683
677
  sliderMain.appendChild(slider);
684
678
  sliderMain.appendChild(label);
@@ -687,35 +681,35 @@ class AudioFX {
687
681
  restore() {
688
682
  setTimeout(() => {
689
683
  if (this.#destroyed) return;
690
- let status = store.get(this.#fx_status);
691
- let preset = store.get(this.#fx_preset);
684
+ const status = store.get(this.#fxStatus);
685
+ const preset = store.get(this.#fxPreset);
692
686
  if (status) {
693
- this.#fx_ON(this.#audioContext);
687
+ this.#fxON(this.#audioContext);
694
688
  this.#switch.setValue(true);
695
- this.#setPresetName(store.get(this.#fx_preset));
689
+ this.#setPresetName(store.get(this.#fxPreset));
696
690
  this.#setStatusBlock(status);
697
691
  } else {
698
- this.#fx_OFF(this.#audioContext);
692
+ this.#fxOFF(this.#audioContext);
699
693
  this.#switch.setValue(false);
700
694
  if (status === undefined || preset === undefined) {
701
695
  this.#setPresetName("Default");
702
696
  } else {
703
- this.#setPresetName(store.get(this.#fx_preset));
697
+ this.#setPresetName(store.get(this.#fxPreset));
704
698
  }
705
699
  this.#setStatusBlock(status);
706
700
  }
707
701
  }, 250);
708
702
  }
709
703
  set() {
710
- return this.#chui_ap_equalizer_main;
704
+ return this.#chuiApEqualizerMain;
711
705
  }
712
706
  /** Включить или выключить эквалайзер: тот же путь, что у выключателя в панели */
713
707
  setEnabled(boolean = Boolean()) {
714
708
  const включён = this.#switch.getValue();
715
709
  if (boolean === включён) return this;
716
710
  this.#switch.setValue(boolean);
717
- if (boolean) this.#fx_ON(this.#audioContext);
718
- else this.#fx_OFF(this.#audioContext);
711
+ if (boolean) this.#fxON(this.#audioContext);
712
+ else this.#fxOFF(this.#audioContext);
719
713
  return this;
720
714
  }
721
715
  /** Состояние выключателя в панели */
@@ -735,14 +729,14 @@ class AudioFX {
735
729
  return this;
736
730
  }
737
731
  #renderPreampSlider(input, preset, filters = []) {
738
- let p_slider = this.#node("preamp");
739
- let p_val = this.#node("val_preamp");
732
+ const preampSlider = this.#node("preamp");
733
+ const preampValue = this.#node("val_preamp");
740
734
  if (input === undefined) {
741
- p_slider.value = preset.preamp;
735
+ preampSlider.value = preset.preamp;
742
736
  } else {
743
- p_slider.value = input.value;
737
+ preampSlider.value = input.value;
744
738
  preset.inputs.forEach((inp) => {
745
- let slid = this.#node(inp.id);
739
+ const slid = this.#node(inp.id);
746
740
  filters.forEach((filter) => {
747
741
  if (String(inp.id) === String(filter.frequency.value)) {
748
742
  filter.gain.value = Number(slid.value) + Number(input.value);
@@ -750,18 +744,18 @@ class AudioFX {
750
744
  });
751
745
  });
752
746
  }
753
- p_val.innerText = String(p_slider.value);
754
- p_slider.setAttribute("aria-valuetext", I18n.t("media.decibels", { value: p_slider.value }));
755
- p_slider.style.setProperty("--fx-before-width", `${(50 + p_slider.value * 5).toFixed(1)}%`);
747
+ preampValue.innerText = String(preampSlider.value);
748
+ preampSlider.setAttribute("aria-valuetext", I18n.t("media.decibels", { value: preampSlider.value }));
749
+ preampSlider.style.setProperty("--fx_before_width", `${(50 + preampSlider.value * 5).toFixed(1)}%`);
756
750
  }
757
751
  #renderSlider(input, filter, preamp) {
758
- let slider = this.#node(input.id);
759
- let val = this.#node("val_" + input.id);
752
+ const slider = this.#node(input.id);
753
+ const val = this.#node("val_" + input.id);
760
754
  slider.value = input.value;
761
755
  filter.gain.value = Number(Number(slider.value) + preamp);
762
756
  val.innerText = String(slider.value);
763
757
  slider.setAttribute("aria-valuetext", I18n.t("media.decibels", { value: slider.value }));
764
- slider.style.setProperty("--fx-before-width", `${(50 + slider.value * 5).toFixed(1)}%`);
758
+ slider.style.setProperty("--fx_before_width", `${(50 + slider.value * 5).toFixed(1)}%`);
765
759
  }
766
760
  // ya.music.Audio.fx
767
761
  static PRESETS = [