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
@@ -3,7 +3,7 @@ const { makeKeyboardButton } = require("../../modules/chui_a11y/chui_a11y");
3
3
  const { I18n } = require("../../modules/chui_i18n/chui_i18n");
4
4
 
5
5
  /** Идентификаторы панелей дерева для aria-controls */
6
- let tree_panel_counter = 0;
6
+ let treePanelCounter = 0;
7
7
 
8
8
  /** Классы состояния узлов дерева */
9
9
  const SELECTED_CLASS = "tree_view_button_selected";
@@ -69,17 +69,17 @@ class TreeView {
69
69
  static #registry = new WeakMap();
70
70
  static #HIDDEN_CLASS = "tree_view_search_hidden";
71
71
 
72
- #chui_tree_view = document.createElement(`chui_tree_view`);
73
- #main_test = undefined;
74
- #selection_mode = TreeView.SELECTION.NONE;
72
+ #chuiTreeView = document.createElement(`chui_tree_view`);
73
+ #mainTest = undefined;
74
+ #selectionMode = TreeView.SELECTION.NONE;
75
75
  #selected = new Set();
76
76
  #anchor = undefined;
77
77
  #draggable = false;
78
- #move_on_drop = false;
79
- #on_select = undefined;
80
- #on_drop = undefined;
81
- #drag_source = undefined;
82
- #drop_target = undefined;
78
+ #moveOnDrop = false;
79
+ #onSelect = undefined;
80
+ #onDrop = undefined;
81
+ #dragSource = undefined;
82
+ #dropTarget = undefined;
83
83
  // Поиск: запрос, совпадения и скрытый статус для скринридера
84
84
  #query = "";
85
85
  #matches = new Set();
@@ -87,28 +87,28 @@ class TreeView {
87
87
  // Виртуализация: структурная модель (все узлы) + плоский список видимых строк
88
88
  #virtual = undefined;
89
89
  // Переменная высота строк: из данных (`rowHeight`-функция) или из DOM (`variableHeight`)
90
- #variable_height = false;
91
- #measure_dom = false;
90
+ #variableHeight = false;
91
+ #measureDom = false;
92
92
  #heights = new Map();
93
- #row_heights = [];
93
+ #rowHeights = [];
94
94
  #offsets = [0];
95
- #subtree_heights = new Map();
95
+ #subtreeHeights = new Map();
96
96
  #nodes = [];
97
- #node_index = new Map();
97
+ #nodeIndex = new Map();
98
98
  #roots = [];
99
99
  #rows = [];
100
- #child_rows = new Map();
101
- #root_rows = [];
102
- #row_sizes = new Map();
103
- #row_positions = new Map();
104
- #rows_dirty = true;
100
+ #childRows = new Map();
101
+ #rootRows = [];
102
+ #rowSizes = new Map();
103
+ #rowPositions = new Map();
104
+ #rowsDirty = true;
105
105
  // Счётчик изменений структуры: окно пересобирается, когда он разошёлся с отрисованным
106
106
  #stamp = 0;
107
- #win_stamp = -1;
108
- #win_rows = -1;
107
+ #winStamp = -1;
108
+ #winRows = -1;
109
109
  #win = undefined;
110
- #measured_row_height = undefined;
111
- #scroll_bound = false;
110
+ #measuredRowHeight = undefined;
111
+ #scrollBound = false;
112
112
  #raf = null;
113
113
  #destroyed = false;
114
114
 
@@ -130,9 +130,9 @@ class TreeView {
130
130
  }
131
131
  ) {
132
132
  require("../../modules/chui_functions").setStyles(__dirname + "/styles.css", "chUiJS_TreeView");
133
- let main_test = document.createElement(`chui_tree_view_main_test`);
134
- main_test.setAttribute("role", "tree");
135
- this.#main_test = main_test;
133
+ const treeNode = document.createElement(`chui_tree_view_main_test`);
134
+ treeNode.setAttribute("role", "tree");
135
+ this.#mainTest = treeNode;
136
136
  // Виртуализация включается явно: `virtual: true` или `{rowHeight, buffer}`
137
137
  this.#virtual =
138
138
  options.virtual === undefined || options.virtual === false
@@ -144,73 +144,73 @@ class TreeView {
144
144
  // `variableHeight: true` — высоты измеряются по отрисованным строкам
145
145
  if (this.#virtual !== undefined) {
146
146
  if (options.variableHeight === true) this.#virtual.variableHeight = true;
147
- this.#variable_height = typeof this.#virtual.rowHeight === "function";
148
- this.#measure_dom = this.#virtual.variableHeight === true;
149
- if (this.#measure_dom && this.#virtual.estimatedRowHeight === undefined)
147
+ this.#variableHeight = typeof this.#virtual.rowHeight === "function";
148
+ this.#measureDom = this.#virtual.variableHeight === true;
149
+ if (this.#measureDom && this.#virtual.estimatedRowHeight === undefined)
150
150
  this.#virtual.estimatedRowHeight = 32;
151
151
  }
152
- this.#selection_mode = options.selection === undefined ? TreeView.SELECTION.NONE : options.selection;
152
+ this.#selectionMode = options.selection === undefined ? TreeView.SELECTION.NONE : options.selection;
153
153
  this.#draggable = options.draggable === true;
154
- this.#move_on_drop = options.moveOnDrop === true;
155
- this.#on_select = options.onSelect;
156
- this.#on_drop = options.onDrop;
157
- if (options.label !== undefined) main_test.setAttribute("aria-label", options.label);
154
+ this.#moveOnDrop = options.moveOnDrop === true;
155
+ this.#onSelect = options.onSelect;
156
+ this.#onDrop = options.onDrop;
157
+ if (options.label !== undefined) treeNode.setAttribute("aria-label", options.label);
158
158
  // Отложенная отрисовка строк: узлы в DOM, но далёкие от окна не раскладываются
159
- if (options.deferRender === true) main_test.classList.add("tree_view_defer");
160
- if (this.#selection_mode !== TreeView.SELECTION.NONE) {
161
- main_test.setAttribute(
159
+ if (options.deferRender === true) treeNode.classList.add("tree_view_defer");
160
+ if (this.#selectionMode !== TreeView.SELECTION.NONE) {
161
+ treeNode.setAttribute(
162
162
  "aria-multiselectable",
163
- this.#selection_mode === TreeView.SELECTION.MULTIPLE ? "true" : "false"
163
+ this.#selectionMode === TreeView.SELECTION.MULTIPLE ? "true" : "false"
164
164
  );
165
- main_test.addEventListener("click", this.#onClick);
165
+ treeNode.addEventListener("click", this.#onClick);
166
166
  // Space приходит и от makeKeyboardButton (кликом), поэтому перехватываем его
167
167
  // с модификатором раньше — в фазе перехвата
168
- main_test.addEventListener("keydown", this.#onSelectionKeyDown, true);
168
+ treeNode.addEventListener("keydown", this.#onSelectionKeyDown, true);
169
169
  }
170
170
  // Стрелки по дереву: ↑/↓ по видимым пунктам, → раскрыть, ← свернуть, Home/End — края
171
- main_test.addEventListener("keydown", this.#onNavigationKeyDown);
171
+ treeNode.addEventListener("keydown", this.#onNavigationKeyDown);
172
172
  if (this.#draggable) {
173
- main_test.addEventListener("dragstart", this.#onDragStart);
174
- main_test.addEventListener("dragover", this.#onDragOver);
175
- main_test.addEventListener("dragleave", this.#onDragLeave);
176
- main_test.addEventListener("drop", this.#onDropEvent);
177
- main_test.addEventListener("dragend", this.#onDragEnd);
173
+ treeNode.addEventListener("dragstart", this.#onDragStart);
174
+ treeNode.addEventListener("dragover", this.#onDragOver);
175
+ treeNode.addEventListener("dragleave", this.#onDragLeave);
176
+ treeNode.addEventListener("drop", this.#onDropEvent);
177
+ treeNode.addEventListener("dragend", this.#onDragEnd);
178
178
  }
179
179
  if (options.width !== undefined) {
180
- this.#chui_tree_view.style.width = options.width;
180
+ this.#chuiTreeView.style.width = options.width;
181
181
  } else {
182
- this.#chui_tree_view.style.width = "max-content";
182
+ this.#chuiTreeView.style.width = "max-content";
183
183
  }
184
184
  // Панели действий приходят опцией: частичный объект опций без них — дерево без панелей
185
- const toolbar_buttons = Array.isArray(options.components) ? options.components : [];
186
- toolbar_buttons.forEach((buttons) => {
187
- main_test.appendChild(buttons.button);
185
+ const toolbarButtons = Array.isArray(options.components) ? options.components : [];
186
+ toolbarButtons.forEach((buttons) => {
187
+ treeNode.appendChild(buttons.button);
188
188
  if (buttons.panel !== undefined) {
189
- main_test.appendChild(buttons.panel);
189
+ treeNode.appendChild(buttons.panel);
190
190
  }
191
191
  });
192
192
  // Структурная модель строится один раз по полному DOM: дальше окно собирается из неё,
193
193
  // поэтому отрисовка перестаёт зависеть от того, что сейчас лежит в документе
194
194
  this.#buildStructure();
195
195
  if (this.#virtual !== undefined) {
196
- this.#chui_tree_view.style.height = options.height === undefined ? "400px" : options.height;
196
+ this.#chuiTreeView.style.height = options.height === undefined ? "400px" : options.height;
197
197
  // Высота строки одна для вёрстки и для арифметики распорок (в переменном режиме её нет)
198
198
  if (!this.#isVariable())
199
- this.#chui_tree_view.style.setProperty("--tree_view_row_height", `${this.#rowHeight()}px`);
200
- this.#chui_tree_view.dataset.virtual = "true";
201
- main_test.classList.add("tree_view_virtual");
199
+ this.#chuiTreeView.style.setProperty("--tree_view_row_height", `${this.#rowHeight()}px`);
200
+ this.#chuiTreeView.dataset.virtual = "true";
201
+ treeNode.classList.add("tree_view_virtual");
202
202
  this.#bindScroll();
203
203
  // Клик по раскрытию меняет не только классы, но и состав видимых строк
204
- main_test.addEventListener("click", this.#onStructureClick);
204
+ treeNode.addEventListener("click", this.#onStructureClick);
205
205
  }
206
206
  this.#applySelection(false);
207
207
  this.#syncDraggable();
208
- this.#chui_tree_view.appendChild(main_test);
208
+ this.#chuiTreeView.appendChild(treeNode);
209
209
  if (this.#virtual !== undefined) this.#renderVirtual();
210
210
  }
211
211
 
212
212
  set() {
213
- return this.#chui_tree_view;
213
+ return this.#chuiTreeView;
214
214
  }
215
215
  /**
216
216
  * Снять подписки (прокрутка, клавиатура, клики, drag) и отпустить модель строк: плоский список
@@ -222,28 +222,28 @@ class TreeView {
222
222
  this.#destroyed = true;
223
223
  if (this.#raf !== null) cancelAnimationFrame(this.#raf);
224
224
  this.#raf = null;
225
- this.#chui_tree_view.removeEventListener("scroll", this.#onScroll);
226
- this.#scroll_bound = false;
227
- this.#main_test.removeEventListener("click", this.#onClick);
228
- this.#main_test.removeEventListener("keydown", this.#onSelectionKeyDown, true);
229
- this.#main_test.removeEventListener("keydown", this.#onNavigationKeyDown);
230
- this.#main_test.removeEventListener("click", this.#onStructureClick);
231
- this.#main_test.removeEventListener("dragstart", this.#onDragStart);
232
- this.#main_test.removeEventListener("dragover", this.#onDragOver);
233
- this.#main_test.removeEventListener("dragleave", this.#onDragLeave);
234
- this.#main_test.removeEventListener("drop", this.#onDropEvent);
235
- this.#main_test.removeEventListener("dragend", this.#onDragEnd);
225
+ this.#chuiTreeView.removeEventListener("scroll", this.#onScroll);
226
+ this.#scrollBound = false;
227
+ this.#mainTest.removeEventListener("click", this.#onClick);
228
+ this.#mainTest.removeEventListener("keydown", this.#onSelectionKeyDown, true);
229
+ this.#mainTest.removeEventListener("keydown", this.#onNavigationKeyDown);
230
+ this.#mainTest.removeEventListener("click", this.#onStructureClick);
231
+ this.#mainTest.removeEventListener("dragstart", this.#onDragStart);
232
+ this.#mainTest.removeEventListener("dragover", this.#onDragOver);
233
+ this.#mainTest.removeEventListener("dragleave", this.#onDragLeave);
234
+ this.#mainTest.removeEventListener("drop", this.#onDropEvent);
235
+ this.#mainTest.removeEventListener("dragend", this.#onDragEnd);
236
236
  this.#nodes = [];
237
237
  this.#rows = [];
238
238
  this.#roots = [];
239
- this.#root_rows = [];
240
- this.#row_heights = [];
239
+ this.#rootRows = [];
240
+ this.#rowHeights = [];
241
241
  this.#offsets = [0];
242
- this.#node_index.clear();
243
- this.#child_rows.clear();
244
- this.#row_sizes.clear();
245
- this.#row_positions.clear();
246
- this.#subtree_heights.clear();
242
+ this.#nodeIndex.clear();
243
+ this.#childRows.clear();
244
+ this.#rowSizes.clear();
245
+ this.#rowPositions.clear();
246
+ this.#subtreeHeights.clear();
247
247
  this.#heights.clear();
248
248
  this.#selected.clear();
249
249
  return this;
@@ -251,7 +251,7 @@ class TreeView {
251
251
 
252
252
  // === ВЫБОР ===
253
253
  getSelectionMode() {
254
- return this.#selection_mode;
254
+ return this.#selectionMode;
255
255
  }
256
256
 
257
257
  /** Описания выбранных узлов — те же объекты, что вернули фабрики */
@@ -295,7 +295,7 @@ class TreeView {
295
295
  // строки могут быть вне документа, но остаются видимыми по смыслу
296
296
  #items() {
297
297
  if (this.#virtual === undefined) {
298
- return [...this.#main_test.querySelectorAll("tree_view_button")].filter((button) =>
298
+ return [...this.#mainTest.querySelectorAll("tree_view_button")].filter((button) =>
299
299
  this.#isVisibleRow(button)
300
300
  );
301
301
  }
@@ -320,7 +320,7 @@ class TreeView {
320
320
 
321
321
  /** Все кнопки, к которым применим выбор: в виртуальном режиме — по модели, а не по документу */
322
322
  #selectionTargets() {
323
- if (this.#virtual === undefined) return [...this.#main_test.querySelectorAll("tree_view_button")];
323
+ if (this.#virtual === undefined) return [...this.#mainTest.querySelectorAll("tree_view_button")];
324
324
  return this.#project().map((row) => this.#nodes[row.index].button);
325
325
  }
326
326
 
@@ -332,7 +332,7 @@ class TreeView {
332
332
  const node = entry instanceof Element ? entry : entry.button;
333
333
  if (node === undefined || !(node instanceof Element)) continue;
334
334
  // В виртуальном режиме строка может быть вне документа — она всё равно есть в модели
335
- if (this.#main_test.contains(node) || this.#node_index.has(node)) nodes.push(node);
335
+ if (this.#mainTest.contains(node) || this.#nodeIndex.has(node)) nodes.push(node);
336
336
  }
337
337
  return nodes;
338
338
  }
@@ -349,12 +349,12 @@ class TreeView {
349
349
  for (const node of this.#selectionTargets()) {
350
350
  const selected = this.#selected.has(node);
351
351
  node.classList.toggle(SELECTED_CLASS, selected);
352
- if (this.#selection_mode !== TreeView.SELECTION.NONE)
352
+ if (this.#selectionMode !== TreeView.SELECTION.NONE)
353
353
  node.setAttribute("aria-selected", selected ? "true" : "false");
354
354
  }
355
- if (!announce || this.#on_select === undefined) return;
355
+ if (!announce || this.#onSelect === undefined) return;
356
356
  const items = this.getSelected();
357
- this.#on_select(items, items.length === 0 ? undefined : items[items.length - 1]);
357
+ this.#onSelect(items, items.length === 0 ? undefined : items[items.length - 1]);
358
358
  }
359
359
 
360
360
  #toggleNode(node) {
@@ -367,7 +367,7 @@ class TreeView {
367
367
 
368
368
  #selectRange(node) {
369
369
  const items = this.#items();
370
- const anchor = this.#anchor === undefined || !this.#main_test.contains(this.#anchor) ? node : this.#anchor;
370
+ const anchor = this.#anchor === undefined || !this.#mainTest.contains(this.#anchor) ? node : this.#anchor;
371
371
  const from = items.indexOf(anchor);
372
372
  const to = items.indexOf(node);
373
373
  if (from === -1 || to === -1) return;
@@ -401,9 +401,9 @@ class TreeView {
401
401
  #inOwnSubtree(source, target) {
402
402
  if (source === target || source.contains(target)) return true;
403
403
  // Модель знает родство и для строк вне окна: DOM-проверка видит только отрисованное
404
- const sourceIndex = this.#node_index.get(source);
404
+ const sourceIndex = this.#nodeIndex.get(source);
405
405
  if (sourceIndex !== undefined) {
406
- let current = this.#node_index.get(target);
406
+ let current = this.#nodeIndex.get(target);
407
407
  while (current !== undefined && current !== -1) {
408
408
  if (current === sourceIndex) return true;
409
409
  current = this.#nodes[current].parent;
@@ -425,13 +425,13 @@ class TreeView {
425
425
  }
426
426
 
427
427
  #applyDropTarget(target, position) {
428
- if (this.#drop_target !== undefined) {
429
- this.#drop_target.node.classList.remove(DROP_CLASSES[this.#drop_target.position]);
430
- this.#drop_target = undefined;
428
+ if (this.#dropTarget !== undefined) {
429
+ this.#dropTarget.node.classList.remove(DROP_CLASSES[this.#dropTarget.position]);
430
+ this.#dropTarget = undefined;
431
431
  }
432
432
  if (target !== undefined && position !== undefined) {
433
433
  target.classList.add(DROP_CLASSES[position]);
434
- this.#drop_target = { node: target, position: position };
434
+ this.#dropTarget = { node: target, position: position };
435
435
  }
436
436
  }
437
437
 
@@ -462,8 +462,8 @@ class TreeView {
462
462
  }
463
463
 
464
464
  #finishDrag() {
465
- if (this.#drag_source !== undefined) this.#drag_source.classList.remove(DRAGGING_CLASS);
466
- this.#drag_source = undefined;
465
+ if (this.#dragSource !== undefined) this.#dragSource.classList.remove(DRAGGING_CLASS);
466
+ this.#dragSource = undefined;
467
467
  }
468
468
 
469
469
  #descriptor(node) {
@@ -484,9 +484,9 @@ class TreeView {
484
484
  // Строится один раз по полному DOM, ленивые поддеревья и переносы достраивают её точечно.
485
485
  #buildStructure() {
486
486
  this.#nodes = [];
487
- this.#node_index = new Map();
487
+ this.#nodeIndex = new Map();
488
488
  this.#roots = [];
489
- for (const child of [...this.#main_test.children]) {
489
+ for (const child of [...this.#mainTest.children]) {
490
490
  if (child.tagName.toLowerCase() !== "tree_view_button") continue;
491
491
  this.#register(child, -1);
492
492
  }
@@ -495,7 +495,7 @@ class TreeView {
495
495
 
496
496
  /** Структура изменилась: плоский список и окно надо пересобрать */
497
497
  #touch() {
498
- this.#rows_dirty = true;
498
+ this.#rowsDirty = true;
499
499
  this.#stamp += 1;
500
500
  }
501
501
 
@@ -516,7 +516,7 @@ class TreeView {
516
516
  hidden: false,
517
517
  };
518
518
  this.#nodes.push(record);
519
- this.#node_index.set(button, index);
519
+ this.#nodeIndex.set(button, index);
520
520
  if (parent === -1) this.#roots.push(index);
521
521
  else this.#nodes[parent].children.push(index);
522
522
  if (html !== null) {
@@ -535,7 +535,7 @@ class TreeView {
535
535
  * можно собирать из него, не оглядываясь на документ.
536
536
  */
537
537
  #project() {
538
- if (!this.#rows_dirty) return this.#rows;
538
+ if (!this.#rowsDirty) return this.#rows;
539
539
  const rows = [];
540
540
  const positions = new Map();
541
541
  const childrenOf = new Map();
@@ -571,17 +571,17 @@ class TreeView {
571
571
  const roots = [];
572
572
  for (const root of this.#roots) if (walk(root, 0) > 0) roots.push(root);
573
573
  this.#rows = rows;
574
- this.#child_rows = childrenOf;
575
- this.#root_rows = roots;
576
- this.#row_sizes = sizes;
577
- this.#subtree_heights = subtree;
578
- this.#row_heights = heights;
579
- this.#row_positions = positions;
574
+ this.#childRows = childrenOf;
575
+ this.#rootRows = roots;
576
+ this.#rowSizes = sizes;
577
+ this.#subtreeHeights = subtree;
578
+ this.#rowHeights = heights;
579
+ this.#rowPositions = positions;
580
580
  // Верхняя граница каждой позиции: для переменной высоты окно и прокрутка считаются по ней
581
581
  const offsets = [0];
582
582
  for (const value of heights) offsets.push(offsets[offsets.length - 1] + value);
583
583
  this.#offsets = offsets;
584
- this.#rows_dirty = false;
584
+ this.#rowsDirty = false;
585
585
  return rows;
586
586
  }
587
587
 
@@ -593,19 +593,19 @@ class TreeView {
593
593
 
594
594
  /** Переменная высота строк: высоты из данных (функция) или измеренные по DOM */
595
595
  #isVariable() {
596
- return this.#variable_height || this.#measure_dom;
596
+ return this.#variableHeight || this.#measureDom;
597
597
  }
598
598
 
599
599
  /** Высота строки с индексом модели: из данных, из кеша замеров или оценка */
600
600
  #heightOf(index) {
601
- if (this.#variable_height) {
601
+ if (this.#variableHeight) {
602
602
  if (!this.#heights.has(index)) {
603
603
  const value = Number(this.#virtual.rowHeight(this.#nodes[index], index));
604
604
  this.#heights.set(index, Number.isFinite(value) && value > 0 ? value : 26);
605
605
  }
606
606
  return this.#heights.get(index);
607
607
  }
608
- if (this.#measure_dom) {
608
+ if (this.#measureDom) {
609
609
  if (this.#heights.has(index)) return this.#heights.get(index);
610
610
  return this.#virtual.estimatedRowHeight;
611
611
  }
@@ -619,13 +619,13 @@ class TreeView {
619
619
  * тела `DataGrid`).
620
620
  */
621
621
  #measureWindow() {
622
- for (const button of this.#main_test.querySelectorAll("tree_view_button")) {
623
- const index = this.#node_index.get(button);
622
+ for (const button of this.#mainTest.querySelectorAll("tree_view_button")) {
623
+ const index = this.#nodeIndex.get(button);
624
624
  if (index === undefined) continue;
625
625
  const measured = Math.round(button.getBoundingClientRect().height);
626
626
  if (measured > 0 && this.#heights.get(index) !== measured) {
627
627
  this.#heights.set(index, measured);
628
- this.#rows_dirty = true;
628
+ this.#rowsDirty = true;
629
629
  }
630
630
  }
631
631
  }
@@ -634,12 +634,12 @@ class TreeView {
634
634
  #rowHeight() {
635
635
  if (this.#virtual === undefined) return 26;
636
636
  if (this.#virtual.rowHeight !== undefined) return this.#virtual.rowHeight;
637
- return this.#measured_row_height === undefined ? 26 : this.#measured_row_height;
637
+ return this.#measuredRowHeight === undefined ? 26 : this.#measuredRowHeight;
638
638
  }
639
639
 
640
640
  #measureRow() {
641
641
  if (this.#virtual === undefined || this.#isVariable() || this.#virtual.rowHeight !== undefined) return 0;
642
- const sample = this.#main_test.querySelector("tree_view_button");
642
+ const sample = this.#mainTest.querySelector("tree_view_button");
643
643
  return sample === null ? 0 : Math.round(sample.getBoundingClientRect().height);
644
644
  }
645
645
 
@@ -648,9 +648,9 @@ class TreeView {
648
648
  }
649
649
 
650
650
  #bindScroll() {
651
- if (this.#scroll_bound) return;
652
- this.#scroll_bound = true;
653
- this.#chui_tree_view.addEventListener("scroll", this.#onScroll, { passive: true });
651
+ if (this.#scrollBound) return;
652
+ this.#scrollBound = true;
653
+ this.#chuiTreeView.addEventListener("scroll", this.#onScroll, { passive: true });
654
654
  }
655
655
 
656
656
  #onScroll = () => {
@@ -679,15 +679,15 @@ class TreeView {
679
679
  if (remeasure) {
680
680
  // Переменный режим по DOM: сначала измеряем уже отрисованные строки — их настоящие
681
681
  // высоты уточняют смещения, и только потом считается окно
682
- if (this.#measure_dom) this.#measureWindow();
682
+ if (this.#measureDom) this.#measureWindow();
683
683
  // Настоящая высота строки может отличаться от умолчания: распорки и окно считаются
684
684
  // по ней, поэтому замер идёт до расчёта окна
685
685
  const measured = this.#measureRow();
686
- if (measured > 0 && measured !== this.#measured_row_height) {
687
- this.#measured_row_height = measured;
688
- this.#chui_tree_view.style.setProperty("--tree_view_row_height", `${measured}px`);
686
+ if (measured > 0 && measured !== this.#measuredRowHeight) {
687
+ this.#measuredRowHeight = measured;
688
+ this.#chuiTreeView.style.setProperty("--tree_view_row_height", `${measured}px`);
689
689
  // Смещения в проекции считались по прежней высоте — пересобрать
690
- this.#rows_dirty = true;
690
+ this.#rowsDirty = true;
691
691
  force = true;
692
692
  }
693
693
  }
@@ -695,7 +695,7 @@ class TreeView {
695
695
  const variable = this.#isVariable();
696
696
  const height = this.#rowHeight();
697
697
  const buffer = this.#buffer();
698
- const viewport = Math.max(1, this.#chui_tree_view.clientHeight);
698
+ const viewport = Math.max(1, this.#chuiTreeView.clientHeight);
699
699
  // Позиция строки по верхней границе прокрутки (двоичный поиск по смещениям)
700
700
  const positionFor = (top) => {
701
701
  let low = 0;
@@ -713,8 +713,8 @@ class TreeView {
713
713
  // нет паддинга, рамки и зазоров между отрисованными строками, поэтому «модельный» низ чуть
714
714
  // выше настоящего — только по нему последняя строка (End, стрелка вниз) осталась бы обрезанной
715
715
  const modelBottom = Math.max(0, total - viewport);
716
- const realBottom = Math.max(0, this.#chui_tree_view.scrollHeight - viewport);
717
- let scrollTop = Math.min(Math.max(0, this.#chui_tree_view.scrollTop), Math.max(modelBottom, realBottom));
716
+ const realBottom = Math.max(0, this.#chuiTreeView.scrollHeight - viewport);
717
+ let scrollTop = Math.min(Math.max(0, this.#chuiTreeView.scrollTop), Math.max(modelBottom, realBottom));
718
718
  // Низ окна для переменной высоты — позиция строки под нижней кромкой плюс одна строка,
719
719
  // иначе последняя видимая строка выпадала бы из окна
720
720
  const windowTo = (top) =>
@@ -730,7 +730,7 @@ class TreeView {
730
730
  from = Math.max(0, positionFor(scrollTop) - buffer);
731
731
  to = windowTo(scrollTop);
732
732
  }
733
- if (scrollTop !== this.#chui_tree_view.scrollTop) this.#chui_tree_view.scrollTop = scrollTop;
733
+ if (scrollTop !== this.#chuiTreeView.scrollTop) this.#chuiTreeView.scrollTop = scrollTop;
734
734
  // Ни окно, ни структура не изменились (прокрутка в пределах строки) — пересобирать
735
735
  // нечего: пересборка на каждом кадре только дёргала бы DOM и фокус
736
736
  if (
@@ -738,13 +738,13 @@ class TreeView {
738
738
  this.#win !== undefined &&
739
739
  from === this.#win.from &&
740
740
  to === this.#win.to &&
741
- this.#win_rows === rows.length &&
742
- this.#win_stamp === this.#stamp
741
+ this.#winRows === rows.length &&
742
+ this.#winStamp === this.#stamp
743
743
  )
744
744
  return;
745
745
  // Кто держит фокус: снимок до мутации — после неё `document.activeElement` уже `body`
746
746
  const active = document.activeElement;
747
- const activeIndex = active instanceof Element ? this.#node_index.get(active) : undefined;
747
+ const activeIndex = active instanceof Element ? this.#nodeIndex.get(active) : undefined;
748
748
  const keepIndex = activeIndex === undefined ? undefined : this.#pinRow(rows, activeIndex);
749
749
  const visible = new Set();
750
750
  for (let position = from; position < to; position++) {
@@ -763,7 +763,7 @@ class TreeView {
763
763
  current = this.#nodes[current].parent;
764
764
  }
765
765
  }
766
- const sizeOf = (index) => this.#row_sizes.get(index) || 1;
766
+ const sizeOf = (index) => this.#rowSizes.get(index) || 1;
767
767
  const spacer = (px) => {
768
768
  const node = document.createElement("tree_view_spacer");
769
769
  node.setAttribute("aria-hidden", "true");
@@ -771,10 +771,10 @@ class TreeView {
771
771
  return node;
772
772
  };
773
773
  // Сколько занимает пропущенная ветка: в переменном режиме — суммарная высота её поддерева
774
- const subtreePx = (index) => (variable ? this.#subtree_heights.get(index) || 0 : sizeOf(index) * height);
774
+ const subtreePx = (index) => (variable ? this.#subtreeHeights.get(index) || 0 : sizeOf(index) * height);
775
775
  const fill = (container, parentIndex) => {
776
776
  // Дети берутся из проекции: скрытое поиском и свёрнутое в неё уже не попадает
777
- const children = parentIndex === -1 ? this.#root_rows : this.#child_rows.get(parentIndex) || [];
777
+ const children = parentIndex === -1 ? this.#rootRows : this.#childRows.get(parentIndex) || [];
778
778
  const parts = [];
779
779
  let gap = 0;
780
780
  for (const index of children) {
@@ -789,7 +789,7 @@ class TreeView {
789
789
  }
790
790
  const record = this.#nodes[index];
791
791
  // Высота из данных задаётся строке инлайном — иначе DOM разошёлся бы с моделью
792
- if (this.#variable_height) {
792
+ if (this.#variableHeight) {
793
793
  const rowHeightPx = this.#heightOf(index);
794
794
  record.button.style.minHeight = `${rowHeightPx}px`;
795
795
  record.button.style.height = `${rowHeightPx}px`;
@@ -809,14 +809,14 @@ class TreeView {
809
809
  else record.html.replaceChildren();
810
810
  }
811
811
  };
812
- fill(this.#main_test, -1);
813
- if (this.#status !== undefined) this.#main_test.appendChild(this.#status);
812
+ fill(this.#mainTest, -1);
813
+ if (this.#status !== undefined) this.#mainTest.appendChild(this.#status);
814
814
  this.#restoreFocus(keepIndex);
815
815
  this.#applySelection(false);
816
816
  this.#syncDraggable();
817
817
  this.#win = { from: from, to: to };
818
- this.#win_stamp = this.#stamp;
819
- this.#win_rows = rows.length;
818
+ this.#winStamp = this.#stamp;
819
+ this.#winRows = rows.length;
820
820
  }
821
821
 
822
822
  /**
@@ -825,7 +825,7 @@ class TreeView {
825
825
  * видимая: фокус остаётся в дереве, а не уходит в `body`.
826
826
  */
827
827
  #pinRow(rows, index) {
828
- const position = this.#row_positions.get(index);
828
+ const position = this.#rowPositions.get(index);
829
829
  if (position !== undefined) return rows[position].index;
830
830
  let nearest = undefined;
831
831
  for (const row of rows) {
@@ -881,17 +881,17 @@ class TreeView {
881
881
  return;
882
882
  }
883
883
  // Позиция строки в плоском списке: карта проекции, чтобы не перебирать все строки
884
- const modelIndex = this.#node_index.get(button);
885
- const place = modelIndex === undefined ? undefined : this.#row_positions.get(modelIndex);
884
+ const modelIndex = this.#nodeIndex.get(button);
885
+ const place = modelIndex === undefined ? undefined : this.#rowPositions.get(modelIndex);
886
886
  if (place === undefined) return;
887
887
  // В переменном режиме верх и высота строки берутся из смещений проекции
888
888
  const variable = this.#isVariable();
889
- const height = variable ? this.#row_heights[place] || this.#rowHeight() : this.#rowHeight();
890
- const viewport = Math.max(1, this.#chui_tree_view.clientHeight);
889
+ const height = variable ? this.#rowHeights[place] || this.#rowHeight() : this.#rowHeight();
890
+ const viewport = Math.max(1, this.#chuiTreeView.clientHeight);
891
891
  const top = variable ? this.#offsets[place] : place * height;
892
- const scrollTop = this.#chui_tree_view.scrollTop;
892
+ const scrollTop = this.#chuiTreeView.scrollTop;
893
893
  if (top < scrollTop || top + height > scrollTop + viewport) {
894
- this.#chui_tree_view.scrollTop = Math.max(0, top - Math.floor(viewport / 2));
894
+ this.#chuiTreeView.scrollTop = Math.max(0, top - Math.floor(viewport / 2));
895
895
  this.#renderVirtual();
896
896
  }
897
897
  button.focus();
@@ -901,7 +901,7 @@ class TreeView {
901
901
  #onStructureClick = (event) => {
902
902
  const button = event.target instanceof Element ? event.target.closest("tree_view_button[aria-expanded]") : null;
903
903
  if (button === null) return;
904
- const index = this.#node_index.get(button);
904
+ const index = this.#nodeIndex.get(button);
905
905
  if (index !== undefined) this.#syncSubtree(index);
906
906
  const panel = button.nextElementSibling;
907
907
  if (panel !== null && panel.tagName.toLowerCase() === "tree_view_panel") {
@@ -917,7 +917,7 @@ class TreeView {
917
917
  if (record === undefined || record.html === null) return;
918
918
  for (const child of [...record.html.children]) {
919
919
  if (child.tagName.toLowerCase() !== "tree_view_button") continue;
920
- if (this.#node_index.has(child)) continue;
920
+ if (this.#nodeIndex.has(child)) continue;
921
921
  this.#register(child, index);
922
922
  }
923
923
  }
@@ -937,8 +937,8 @@ class TreeView {
937
937
  }
938
938
 
939
939
  #syncMove(source, target, position) {
940
- const index = this.#node_index.get(source);
941
- const targetIndex = this.#node_index.get(target);
940
+ const index = this.#nodeIndex.get(source);
941
+ const targetIndex = this.#nodeIndex.get(target);
942
942
  if (index === undefined || targetIndex === undefined) return;
943
943
  if (position === TreeView.DROP.INSIDE) this.#relink(index, targetIndex);
944
944
  else {
@@ -978,7 +978,7 @@ class TreeView {
978
978
  this.#announce(I18n.t("treeView.found", { count: this.#matches.size }));
979
979
  return this;
980
980
  }
981
- const buttons = [...this.#main_test.querySelectorAll("tree_view_button")];
981
+ const buttons = [...this.#mainTest.querySelectorAll("tree_view_button")];
982
982
  const visible = new Set();
983
983
  for (const button of buttons) {
984
984
  if (!this.#title(button).toLocaleLowerCase().includes(text)) continue;
@@ -1000,7 +1000,7 @@ class TreeView {
1000
1000
  }
1001
1001
  }
1002
1002
  for (const button of buttons) if (!visible.has(button)) button.classList.add(TreeView.#HIDDEN_CLASS);
1003
- for (const panel of this.#main_test.querySelectorAll("tree_view_panel")) {
1003
+ for (const panel of this.#mainTest.querySelectorAll("tree_view_panel")) {
1004
1004
  if (!visible.has(panel)) panel.classList.add(TreeView.#HIDDEN_CLASS);
1005
1005
  // Раскрытая панель должна быть видна целиком: max-height после раскрытия пересчитываем
1006
1006
  else if (panel.style.maxHeight !== "") panel.style.maxHeight = "max-content";
@@ -1061,7 +1061,7 @@ class TreeView {
1061
1061
  if (target === undefined || target === null) return undefined;
1062
1062
  const node = target instanceof Element ? target : target.button;
1063
1063
  if (!(node instanceof Element)) return undefined;
1064
- const index = this.#node_index.get(node);
1064
+ const index = this.#nodeIndex.get(node);
1065
1065
  return index === undefined ? undefined : this.#nodes[index];
1066
1066
  }
1067
1067
 
@@ -1092,7 +1092,7 @@ class TreeView {
1092
1092
 
1093
1093
  /** Снять фильтр поиска: возвращает все узлы и снимает подсветку */
1094
1094
  clearSearch() {
1095
- for (const node of this.#main_test.querySelectorAll("." + TreeView.#HIDDEN_CLASS))
1095
+ for (const node of this.#mainTest.querySelectorAll("." + TreeView.#HIDDEN_CLASS))
1096
1096
  node.classList.remove(TreeView.#HIDDEN_CLASS);
1097
1097
  for (const node of this.#matches) node.classList.remove("tree_view_button_match");
1098
1098
  for (const record of this.#nodes) record.hidden = false;
@@ -1113,7 +1113,7 @@ class TreeView {
1113
1113
  });
1114
1114
  this.#status.setAttribute("role", "status");
1115
1115
  this.#status.setAttribute("aria-live", "polite");
1116
- this.#main_test.appendChild(this.#status);
1116
+ this.#mainTest.appendChild(this.#status);
1117
1117
  }
1118
1118
  this.#status.innerText = text;
1119
1119
  }
@@ -1121,8 +1121,8 @@ class TreeView {
1121
1121
  // === ОБРАБОТЧИКИ ===
1122
1122
  #onClick = (event) => {
1123
1123
  const node = event.target instanceof Element ? event.target.closest("tree_view_button") : null;
1124
- if (node === null || !this.#main_test.contains(node)) return;
1125
- const multiple = this.#selection_mode === TreeView.SELECTION.MULTIPLE;
1124
+ if (node === null || !this.#mainTest.contains(node)) return;
1125
+ const multiple = this.#selectionMode === TreeView.SELECTION.MULTIPLE;
1126
1126
  if (multiple && (event.ctrlKey || event.metaKey)) this.#toggleNode(node);
1127
1127
  else if (multiple && event.shiftKey) this.#selectRange(node);
1128
1128
  else {
@@ -1140,10 +1140,10 @@ class TreeView {
1140
1140
  if (!event.ctrlKey && !event.metaKey && !event.shiftKey) return;
1141
1141
  const target = event.target instanceof Element ? event.target : document.activeElement;
1142
1142
  const node = target instanceof Element ? target.closest("tree_view_button") : null;
1143
- if (node === null || !this.#main_test.contains(node)) return;
1143
+ if (node === null || !this.#mainTest.contains(node)) return;
1144
1144
  event.preventDefault();
1145
1145
  event.stopPropagation();
1146
- if (event.shiftKey && this.#selection_mode === TreeView.SELECTION.MULTIPLE) this.#selectRange(node);
1146
+ if (event.shiftKey && this.#selectionMode === TreeView.SELECTION.MULTIPLE) this.#selectRange(node);
1147
1147
  else this.#toggleNode(node);
1148
1148
  };
1149
1149
 
@@ -1183,7 +1183,7 @@ class TreeView {
1183
1183
  // Клавиатурная альтернатива перетаскиванию: Alt+↑/↓ переставляет узел среди соседей.
1184
1184
  // Соседей берём из модели: в виртуальном режиме в DOM только окно
1185
1185
  #moveByKeyboard(node, step) {
1186
- const index = this.#node_index.get(node);
1186
+ const index = this.#nodeIndex.get(node);
1187
1187
  if (index === undefined) return;
1188
1188
  const parent = this.#nodes[index].parent;
1189
1189
  const siblings = parent === -1 ? this.#roots : this.#nodes[parent].children;
@@ -1192,14 +1192,14 @@ class TreeView {
1192
1192
  const target = this.#nodes[targetIndex].button;
1193
1193
  const position = step < 0 ? TreeView.DROP.BEFORE : TreeView.DROP.AFTER;
1194
1194
  if (!this.#moveNodes(node, target, position)) return;
1195
- if (this.#on_drop !== undefined) this.#on_drop(this.#descriptor(node), this.#descriptor(target), position);
1195
+ if (this.#onDrop !== undefined) this.#onDrop(this.#descriptor(node), this.#descriptor(target), position);
1196
1196
  node.focus();
1197
1197
  }
1198
1198
 
1199
1199
  #onDragStart = (event) => {
1200
1200
  const node = event.target instanceof Element ? event.target.closest("tree_view_button") : null;
1201
1201
  if (node === null) return;
1202
- this.#drag_source = node;
1202
+ this.#dragSource = node;
1203
1203
  node.classList.add(DRAGGING_CLASS);
1204
1204
  if (event.dataTransfer === null) return;
1205
1205
  event.dataTransfer.effectAllowed = "move";
@@ -1207,10 +1207,10 @@ class TreeView {
1207
1207
  };
1208
1208
 
1209
1209
  #onDragOver = (event) => {
1210
- if (this.#drag_source === undefined) return;
1210
+ if (this.#dragSource === undefined) return;
1211
1211
  const target = event.target instanceof Element ? event.target.closest("tree_view_button") : null;
1212
1212
  // В себя и в собственное поддерево бросать нельзя: узел потерял бы ветку
1213
- if (target === null || this.#inOwnSubtree(this.#drag_source, target)) {
1213
+ if (target === null || this.#inOwnSubtree(this.#dragSource, target)) {
1214
1214
  this.#applyDropTarget(undefined, undefined);
1215
1215
  if (event.dataTransfer !== null) event.dataTransfer.dropEffect = "none";
1216
1216
  return;
@@ -1221,20 +1221,20 @@ class TreeView {
1221
1221
  };
1222
1222
 
1223
1223
  #onDragLeave = (event) => {
1224
- if (event.relatedTarget instanceof Element && this.#main_test.contains(event.relatedTarget)) return;
1224
+ if (event.relatedTarget instanceof Element && this.#mainTest.contains(event.relatedTarget)) return;
1225
1225
  this.#applyDropTarget(undefined, undefined);
1226
1226
  };
1227
1227
 
1228
1228
  #onDropEvent = (event) => {
1229
- if (this.#drag_source === undefined || this.#drop_target === undefined) return;
1229
+ if (this.#dragSource === undefined || this.#dropTarget === undefined) return;
1230
1230
  event.preventDefault();
1231
- const source = this.#drag_source;
1232
- const target = this.#drop_target.node;
1233
- const position = this.#drop_target.position;
1231
+ const source = this.#dragSource;
1232
+ const target = this.#dropTarget.node;
1233
+ const position = this.#dropTarget.position;
1234
1234
  this.#applyDropTarget(undefined, undefined);
1235
1235
  this.#finishDrag();
1236
- if (this.#move_on_drop) this.#moveNodes(source, target, position);
1237
- if (this.#on_drop !== undefined) this.#on_drop(this.#descriptor(source), this.#descriptor(target), position);
1236
+ if (this.#moveOnDrop) this.#moveNodes(source, target, position);
1237
+ if (this.#onDrop !== undefined) this.#onDrop(this.#descriptor(source), this.#descriptor(target), position);
1238
1238
  };
1239
1239
 
1240
1240
  #onDragEnd = () => {
@@ -1243,27 +1243,29 @@ class TreeView {
1243
1243
  };
1244
1244
 
1245
1245
  static Button(options = { title: String(), listener: () => {} }) {
1246
- let button = document.createElement("tree_view_button");
1246
+ const button = document.createElement("tree_view_button");
1247
1247
  if (options.listener !== undefined) button.addEventListener("click", options.listener);
1248
1248
  makeKeyboardButton(button, "treeitem");
1249
- let button_text = document.createElement("tree_view_button_text");
1250
- button_text.innerHTML = options.title;
1251
- button.appendChild(button_text);
1249
+ const buttonText = document.createElement("tree_view_button_text");
1250
+ // Заголовок — текст, а не разметка: в `title` приходят имена файлов и папок, а тот же
1251
+ // узел читается как `textContent` (`#title`), и поиск сравнивал бы текст с тегами
1252
+ buttonText.textContent = options.title;
1253
+ button.appendChild(buttonText);
1252
1254
  const item = { title: options.title, button: button };
1253
1255
  TreeView.#registry.set(button, item);
1254
1256
  return item;
1255
1257
  }
1256
1258
 
1257
1259
  static ExpandButton(options = { title: String(), subButtons: [], components: [], lazySubButtons: undefined }) {
1258
- let button = document.createElement("tree_view_button");
1259
- let panel = document.createElement("tree_view_panel");
1260
+ const button = document.createElement("tree_view_button");
1261
+ const panel = document.createElement("tree_view_panel");
1260
1262
  // Раскрытая панель переходит с фиксированной высоты на max-content: иначе высота
1261
1263
  // остаётся «замороженной» после первого раскрытия
1262
1264
  const transitionEndEvent = (event) => {
1263
1265
  const target = event.currentTarget;
1264
1266
  if (target.style.maxHeight && target.style.maxHeight !== "0px") target.style.maxHeight = "max-content";
1265
1267
  };
1266
- panel.id = "chui_tree_panel_" + (tree_panel_counter += 1);
1268
+ panel.id = "chui_tree_panel_" + (treePanelCounter += 1);
1267
1269
  button.setAttribute("aria-controls", panel.id);
1268
1270
  button.setAttribute("aria-expanded", "false");
1269
1271
  makeKeyboardButton(button, "treeitem");
@@ -1283,19 +1285,19 @@ class TreeView {
1283
1285
  panel.style.maxHeight = "0px";
1284
1286
  }
1285
1287
  });
1286
- let button_text = document.createElement("tree_view_button_text");
1287
- button_text.innerHTML = options.title;
1288
- button.appendChild(button_text);
1289
- let barrow = document.createElement("tree_view_button_arrow");
1288
+ const buttonText = document.createElement("tree_view_button_text");
1289
+ buttonText.textContent = options.title;
1290
+ button.appendChild(buttonText);
1291
+ const barrow = document.createElement("tree_view_button_arrow");
1290
1292
  barrow.innerHTML = new Icon(Icons.HARDWARE.KEYBOARD_ARROW_DOWN).getHTML();
1291
1293
  button.appendChild(barrow);
1292
- let html = document.createElement("tree_view_html");
1294
+ const html = document.createElement("tree_view_html");
1293
1295
  // Ленивое поддерево: содержимое строится один раз — при первом раскрытии,
1294
1296
  // поэтому большое дерево не занимает DOM заранее (lazySubButtons: () => [...])
1295
- let subs_built = false;
1297
+ let subButtonsBuilt = false;
1296
1298
  const buildSubs = () => {
1297
- if (subs_built) return;
1298
- subs_built = true;
1299
+ if (subButtonsBuilt) return;
1300
+ subButtonsBuilt = true;
1299
1301
  if (options.subButtons !== undefined) {
1300
1302
  options.subButtons.forEach((sub) => {
1301
1303
  html.appendChild(sub.button);