chuijs 4.0.2 → 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 (292) hide show
  1. package/CHANGELOG.md +597 -0
  2. package/README.md +43 -644
  3. package/framework/appLayout/default/chui_app_layout.js +602 -496
  4. package/framework/appLayout/default/global_style.css +288 -97
  5. package/framework/appLayout/default/main_theme_style.css +188 -101
  6. package/framework/components/chui_accordion/accordion.js +38 -35
  7. package/framework/components/chui_accordion/styles.css +13 -12
  8. package/framework/components/chui_action_sheet/action_sheet.js +93 -64
  9. package/framework/components/chui_action_sheet/styles.css +12 -5
  10. package/framework/components/chui_actions_bar/actions_bar.js +338 -0
  11. package/framework/components/chui_actions_bar/styles.css +139 -0
  12. package/framework/components/chui_affix/affix.js +16 -11
  13. package/framework/components/chui_affix/styles.css +5 -0
  14. package/framework/components/chui_alert/alert.js +34 -19
  15. package/framework/components/chui_alert/styles.css +7 -0
  16. package/framework/components/chui_avatar/avatar.js +36 -35
  17. package/framework/components/chui_avatar/styles.css +1 -1
  18. package/framework/components/chui_avatar_group/avatar_group.js +25 -23
  19. package/framework/components/chui_avatar_group/styles.css +1 -1
  20. package/framework/components/chui_backtop/backtop.js +60 -21
  21. package/framework/components/chui_backtop/styles.css +21 -0
  22. package/framework/components/chui_badge/badge.js +30 -28
  23. package/framework/components/chui_badge/styles.css +6 -6
  24. package/framework/components/chui_banner/banner.js +222 -0
  25. package/framework/components/chui_banner/styles.css +170 -0
  26. package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
  27. package/framework/components/chui_breadcrumb/styles.css +1 -1
  28. package/framework/components/chui_button/button.js +52 -36
  29. package/framework/components/chui_button/styles.css +7 -7
  30. package/framework/components/chui_calendar/calendar.js +18 -16
  31. package/framework/components/chui_card/card.js +52 -32
  32. package/framework/components/chui_card_scroll/card_scroll.js +169 -0
  33. package/framework/components/chui_card_scroll/styles.css +86 -0
  34. package/framework/components/chui_chat/chat.js +140 -79
  35. package/framework/components/chui_chat/styles.css +18 -7
  36. package/framework/components/chui_clipboard_history/clipboard_history.js +53 -39
  37. package/framework/components/chui_clipboard_history/styles.css +13 -9
  38. package/framework/components/chui_code/code.js +10 -10
  39. package/framework/components/chui_code/styles.css +4 -4
  40. package/framework/components/chui_code_editor/code_editor.js +73 -57
  41. package/framework/components/chui_code_editor/styles.css +6 -5
  42. package/framework/components/chui_command_palette/command_palette.js +87 -64
  43. package/framework/components/chui_command_palette/styles.css +5 -5
  44. package/framework/components/chui_console/console.js +13 -13
  45. package/framework/components/chui_console/styles.css +6 -3
  46. package/framework/components/chui_content_block/content_block.js +35 -21
  47. package/framework/components/chui_content_block/styles.css +2 -2
  48. package/framework/components/chui_context_menu/context_menu.js +171 -58
  49. package/framework/components/chui_context_menu/styles.css +82 -8
  50. package/framework/components/chui_custom_element/custom_element.js +25 -18
  51. package/framework/components/chui_data_grid/data_grid.js +633 -471
  52. package/framework/components/chui_data_grid/styles.css +24 -22
  53. package/framework/components/chui_descriptions/descriptions.js +34 -17
  54. package/framework/components/chui_descriptions/styles.css +1 -1
  55. package/framework/components/chui_details/details.js +42 -36
  56. package/framework/components/chui_details/styles.css +12 -11
  57. package/framework/components/chui_diff_viewer/diff_viewer.js +172 -147
  58. package/framework/components/chui_diff_viewer/styles.css +10 -10
  59. package/framework/components/chui_divider/divider.js +19 -17
  60. package/framework/components/chui_divider/styles.css +2 -2
  61. package/framework/components/chui_drawer/drawer.js +63 -38
  62. package/framework/components/chui_drawer/styles.css +18 -4
  63. package/framework/components/chui_drop_zone/drop_zone.js +37 -27
  64. package/framework/components/chui_drop_zone/styles.css +10 -6
  65. package/framework/components/chui_empty_state/empty_state.js +20 -15
  66. package/framework/components/chui_fieldset/fieldset.js +40 -23
  67. package/framework/components/chui_fieldset/styles.css +6 -6
  68. package/framework/components/chui_file_explorer/file_explorer.js +260 -189
  69. package/framework/components/chui_file_explorer/styles.css +8 -7
  70. package/framework/components/chui_form/form.js +40 -28
  71. package/framework/components/chui_form/styles.css +1 -1
  72. package/framework/components/chui_gantt/gantt.js +102 -78
  73. package/framework/components/chui_gantt/styles.css +5 -5
  74. package/framework/components/chui_graphs/graphs.js +376 -239
  75. package/framework/components/chui_graphs/styles.css +27 -6
  76. package/framework/components/chui_hero/hero.js +98 -37
  77. package/framework/components/chui_hero/styles.css +176 -7
  78. package/framework/components/chui_html_block/html_block.js +8 -8
  79. package/framework/components/chui_html_block/styles.css +3 -3
  80. package/framework/components/chui_hx/hx.js +3 -3
  81. package/framework/components/chui_hx/styles.css +13 -6
  82. package/framework/components/chui_icons/icons.js +2115 -2115
  83. package/framework/components/chui_icons/styles.css +4 -3
  84. package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
  85. package/framework/components/chui_inputs/chui_check_box/styles.css +30 -21
  86. package/framework/components/chui_inputs/chui_chips/chips.js +141 -70
  87. package/framework/components/chui_inputs/chui_chips/styles.css +32 -7
  88. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +55 -38
  89. package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
  90. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +127 -109
  91. package/framework/components/chui_inputs/chui_combo_box/styles.css +23 -21
  92. package/framework/components/chui_inputs/chui_date/date.js +161 -127
  93. package/framework/components/chui_inputs/chui_date/styles.css +20 -19
  94. package/framework/components/chui_inputs/chui_date_range/date_range.js +61 -50
  95. package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
  96. package/framework/components/chui_inputs/chui_datetime/datetime.js +47 -39
  97. package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
  98. package/framework/components/chui_inputs/chui_email/email.js +48 -36
  99. package/framework/components/chui_inputs/chui_email/styles.css +11 -11
  100. package/framework/components/chui_inputs/chui_file/file.js +71 -44
  101. package/framework/components/chui_inputs/chui_file/styles.css +23 -19
  102. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +101 -76
  103. package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
  104. package/framework/components/chui_inputs/chui_masked/masked.js +83 -72
  105. package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
  106. package/framework/components/chui_inputs/chui_mention/mention.js +87 -40
  107. package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
  108. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +242 -212
  109. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +23 -15
  110. package/framework/components/chui_inputs/chui_number/number.js +84 -70
  111. package/framework/components/chui_inputs/chui_number/styles.css +13 -13
  112. package/framework/components/chui_inputs/chui_otp/otp.js +71 -62
  113. package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
  114. package/framework/components/chui_inputs/chui_password/password.js +72 -56
  115. package/framework/components/chui_inputs/chui_password/styles.css +15 -15
  116. package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
  117. package/framework/components/chui_inputs/chui_radio_button/styles.css +22 -22
  118. package/framework/components/chui_inputs/chui_rating/rating.js +54 -50
  119. package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
  120. package/framework/components/chui_inputs/chui_select_box/select_box.js +132 -108
  121. package/framework/components/chui_inputs/chui_select_box/styles.css +21 -21
  122. package/framework/components/chui_inputs/chui_slider/slider.js +41 -38
  123. package/framework/components/chui_inputs/chui_slider/styles.css +7 -5
  124. package/framework/components/chui_inputs/chui_text/styles.css +14 -14
  125. package/framework/components/chui_inputs/chui_text/text.js +69 -52
  126. package/framework/components/chui_inputs/chui_text_area/styles.css +14 -14
  127. package/framework/components/chui_inputs/chui_text_area/text_area.js +59 -36
  128. package/framework/components/chui_inputs/chui_time/styles.css +18 -20
  129. package/framework/components/chui_inputs/chui_time/time.js +71 -49
  130. package/framework/components/chui_inputs/chui_toggle/styles.css +13 -6
  131. package/framework/components/chui_inputs/chui_toggle/toggle.js +27 -27
  132. package/framework/components/chui_json_editor/json_editor.js +137 -127
  133. package/framework/components/chui_json_editor/styles.css +5 -5
  134. package/framework/components/chui_json_viewer/json_viewer.js +133 -114
  135. package/framework/components/chui_json_viewer/styles.css +9 -8
  136. package/framework/components/chui_kanban/kanban.js +78 -60
  137. package/framework/components/chui_kanban/styles.css +8 -4
  138. package/framework/components/chui_kbd/kbd.js +12 -10
  139. package/framework/components/chui_kbd/styles.css +1 -1
  140. package/framework/components/chui_label/label.js +31 -29
  141. package/framework/components/chui_label/styles.css +3 -3
  142. package/framework/components/chui_link/link.js +36 -29
  143. package/framework/components/chui_link/styles.css +11 -4
  144. package/framework/components/chui_list/list.js +42 -38
  145. package/framework/components/chui_list/styles.css +4 -3
  146. package/framework/components/chui_markdown_editor/markdown_editor.js +125 -109
  147. package/framework/components/chui_markdown_editor/styles.css +5 -5
  148. package/framework/components/chui_media/audio.js +457 -364
  149. package/framework/components/chui_media/audio_styles.css +74 -37
  150. package/framework/components/chui_media/image.js +99 -64
  151. package/framework/components/chui_media/image_compare.js +86 -55
  152. package/framework/components/chui_media/image_compare_styles.css +5 -5
  153. package/framework/components/chui_media/image_styles.css +4 -4
  154. package/framework/components/chui_media/video.js +264 -171
  155. package/framework/components/chui_media/video_styles.css +57 -24
  156. package/framework/components/chui_menu_bar/menu_bar.js +67 -65
  157. package/framework/components/chui_menu_bar/styles.css +14 -12
  158. package/framework/components/chui_message_bar/message_bar.js +551 -0
  159. package/framework/components/chui_message_bar/styles.css +248 -0
  160. package/framework/components/chui_modal/modal.js +81 -56
  161. package/framework/components/chui_modal/styles.css +3 -2
  162. package/framework/components/chui_notification/notification.js +107 -69
  163. package/framework/components/chui_notification/notification_download.js +28 -77
  164. package/framework/components/chui_notification/notification_download_card.js +115 -0
  165. package/framework/components/chui_notification/notification_download_progress.css +5 -4
  166. package/framework/components/chui_notification/notification_download_progress.js +73 -105
  167. package/framework/components/chui_notification/notification_update.js +44 -37
  168. package/framework/components/chui_notification/status_plate.css +3 -3
  169. package/framework/components/chui_notification/status_plate.js +2 -2
  170. package/framework/components/chui_notification/styles.css +6 -1
  171. package/framework/components/chui_notification/styles_download.css +2 -2
  172. package/framework/components/chui_notification/styles_update.css +3 -3
  173. package/framework/components/chui_org_chart/org_chart.js +101 -62
  174. package/framework/components/chui_org_chart/styles.css +2 -2
  175. package/framework/components/chui_pagination/pagination.js +65 -30
  176. package/framework/components/chui_pagination/styles.css +1 -1
  177. package/framework/components/chui_paragraph/paragraph.js +2 -2
  178. package/framework/components/chui_paragraph/styles.css +3 -3
  179. package/framework/components/chui_popover/popover.js +77 -50
  180. package/framework/components/chui_popover/styles.css +1 -1
  181. package/framework/components/chui_popups/popups.js +210 -181
  182. package/framework/components/chui_popups/styles.css +7 -7
  183. package/framework/components/chui_print_button/print_button.js +48 -33
  184. package/framework/components/chui_progress_bar/progress_bar.js +49 -19
  185. package/framework/components/chui_progress_bar/styles.css +6 -6
  186. package/framework/components/chui_progress_ring/progress_ring.js +32 -30
  187. package/framework/components/chui_progress_ring/styles.css +1 -1
  188. package/framework/components/chui_qrcode/qrcode.js +85 -41
  189. package/framework/components/chui_query_builder/query_builder.js +263 -170
  190. package/framework/components/chui_query_builder/styles.css +4 -4
  191. package/framework/components/chui_radio_group/radio_group.js +36 -26
  192. package/framework/components/chui_radio_group/styles.css +2 -2
  193. package/framework/components/chui_result/result.js +41 -31
  194. package/framework/components/chui_result/styles.css +3 -3
  195. package/framework/components/chui_scheduler/scheduler.js +126 -104
  196. package/framework/components/chui_scheduler/styles.css +11 -7
  197. package/framework/components/chui_screen_spinner/screen_spinner.js +167 -0
  198. package/framework/components/chui_screen_spinner/styles.css +49 -0
  199. package/framework/components/chui_segmented_control/segmented_control.js +90 -27
  200. package/framework/components/chui_segmented_control/styles.css +32 -6
  201. package/framework/components/chui_settings/settings.js +160 -87
  202. package/framework/components/chui_settings/styles.css +4 -4
  203. package/framework/components/chui_shortcut_help/shortcut_help.js +82 -61
  204. package/framework/components/chui_sidebar_nav/sidebar_nav.js +132 -53
  205. package/framework/components/chui_sidebar_nav/styles.css +9 -3
  206. package/framework/components/chui_skeleton/skeleton.js +29 -24
  207. package/framework/components/chui_slideshow/slideshow.js +122 -103
  208. package/framework/components/chui_slideshow/styles.css +22 -16
  209. package/framework/components/chui_spinner/spinner.js +17 -17
  210. package/framework/components/chui_spinner/styles.css +0 -1
  211. package/framework/components/chui_split_button/split_button.js +53 -30
  212. package/framework/components/chui_split_button/styles.css +22 -6
  213. package/framework/components/chui_splitter/splitter.js +46 -39
  214. package/framework/components/chui_splitter/styles.css +2 -2
  215. package/framework/components/chui_statistic/statistic.js +111 -84
  216. package/framework/components/chui_status_bar/status_bar.js +11 -9
  217. package/framework/components/chui_status_bar/styles.css +2 -2
  218. package/framework/components/chui_stepper/stepper.js +230 -54
  219. package/framework/components/chui_stepper/styles.css +79 -14
  220. package/framework/components/chui_sticky_bar/sticky_bar.js +53 -17
  221. package/framework/components/chui_sticky_bar/styles.css +11 -7
  222. package/framework/components/chui_tabs/chui_tabs.js +100 -46
  223. package/framework/components/chui_tabs/styles.css +43 -15
  224. package/framework/components/chui_text_editor/styles.css +24 -23
  225. package/framework/components/chui_text_editor/text_editor.js +103 -79
  226. package/framework/components/chui_text_editor/text_editor_panel.js +428 -367
  227. package/framework/components/chui_theme_toggle/theme_toggle.js +46 -25
  228. package/framework/components/chui_timeline/styles.css +3 -1
  229. package/framework/components/chui_timeline/timeline.js +14 -12
  230. package/framework/components/chui_toast_queue/styles.css +11 -11
  231. package/framework/components/chui_toast_queue/toast_queue.js +82 -73
  232. package/framework/components/chui_toolbar/styles.css +2 -2
  233. package/framework/components/chui_toolbar/toolbar.js +20 -13
  234. package/framework/components/chui_tooltip/styles.css +2 -2
  235. package/framework/components/chui_tooltip/tooltip.js +40 -27
  236. package/framework/components/chui_tour/styles.css +12 -7
  237. package/framework/components/chui_tour/tour.js +132 -98
  238. package/framework/components/chui_transfer/styles.css +8 -7
  239. package/framework/components/chui_transfer/transfer.js +143 -123
  240. package/framework/components/chui_tree_table/styles.css +4 -4
  241. package/framework/components/chui_tree_table/tree_table.js +88 -74
  242. package/framework/components/chui_tree_view/styles.css +14 -10
  243. package/framework/components/chui_tree_view/tree_view.js +298 -253
  244. package/framework/components/chui_user_bar/styles.css +145 -0
  245. package/framework/components/chui_user_bar/user_bar.js +402 -0
  246. package/framework/components/chui_user_list_bar/styles.css +173 -0
  247. package/framework/components/chui_user_list_bar/user_list_bar.js +485 -0
  248. package/framework/components/chui_watermark/watermark.js +41 -33
  249. package/framework/components/chui_webview/styles.css +2 -2
  250. package/framework/components/chui_webview/webview.js +64 -52
  251. package/framework/components/chui_write_bar/styles.css +172 -0
  252. package/framework/components/chui_write_bar/write_bar.js +320 -0
  253. package/framework/main_window.js +1234 -0
  254. package/framework/modules/chui_a11y/chui_a11y.js +153 -123
  255. package/framework/modules/chui_animations/animations.js +105 -43
  256. package/framework/modules/chui_animations/motion.js +120 -0
  257. package/framework/modules/chui_animations/styles.css +37 -4
  258. package/framework/modules/chui_bridge/preload.js +36 -25
  259. package/framework/modules/chui_functions.js +69 -63
  260. package/framework/modules/chui_highlight/chui_highlight.js +25 -22
  261. package/framework/modules/chui_highlight/styles.css +13 -10
  262. package/framework/modules/chui_i18n/chui_i18n.js +12 -10
  263. package/framework/modules/chui_i18n/locales/a11y.js +5 -5
  264. package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
  265. package/framework/modules/chui_i18n/locales/calendar.js +3 -3
  266. package/framework/modules/chui_i18n/locales/common.js +3 -3
  267. package/framework/modules/chui_i18n/locales/data.js +36 -26
  268. package/framework/modules/chui_i18n/locales/editors.js +40 -13
  269. package/framework/modules/chui_i18n/locales/feedback.js +65 -3
  270. package/framework/modules/chui_i18n/locales/forms.js +8 -8
  271. package/framework/modules/chui_i18n/locales/graphics.js +8 -8
  272. package/framework/modules/chui_i18n/locales/media.js +4 -4
  273. package/framework/modules/chui_i18n/locales/navigation.js +12 -8
  274. package/framework/modules/chui_i18n/locales/validate.js +3 -3
  275. package/framework/modules/chui_json/chui_json.js +11 -11
  276. package/framework/modules/chui_layout/chui_layout.js +12 -10
  277. package/framework/modules/chui_logger/chui_logger.js +47 -28
  278. package/framework/modules/chui_page/page.js +39 -33
  279. package/framework/modules/chui_palette/palette.js +61 -0
  280. package/framework/modules/chui_qr/chui_qr.js +179 -88
  281. package/framework/modules/chui_scrollbar/chui_scrollbar.js +79 -68
  282. package/framework/modules/chui_scrollbar/styles.css +4 -2
  283. package/framework/modules/chui_services/chui_channels.js +27 -13
  284. package/framework/modules/chui_services/chui_services.js +47 -39
  285. package/framework/modules/chui_services/desktop.js +108 -101
  286. package/framework/modules/chui_sortable/chui_sortable.js +33 -28
  287. package/framework/modules/chui_validate/chui_validate.js +10 -7
  288. package/framework/tray_bar/chui_menu_items.js +136 -46
  289. package/index.d.ts +5046 -0
  290. package/index.js +199 -1254
  291. package/package.json +81 -68
  292. package/framework/components/telegram_bot/chui_telegram_bot.js +0 -184
@@ -1,17 +1,17 @@
1
- const {setStyles} = require("../../modules/chui_functions");
2
- const {Validate} = require("../../modules/chui_validate/chui_validate");
3
- const {SegmentedControl} = require("../chui_segmented_control/segmented_control");
4
- const {Select} = require("../chui_inputs/chui_select_box/select_box");
5
- const {TextInput} = require("../chui_inputs/chui_text/text");
6
- const {NumberInput} = require("../chui_inputs/chui_number/number");
7
- const {DateInput} = require("../chui_inputs/chui_date/date");
8
- const {I18n} = require("../../modules/chui_i18n/chui_i18n");
9
- const {Icon, Icons} = require("../chui_icons/icons");
1
+ const { setStyles } = require("../../modules/chui_functions");
2
+ const { Validate } = require("../../modules/chui_validate/chui_validate");
3
+ const { SegmentedControl } = require("../chui_segmented_control/segmented_control");
4
+ const { Select } = require("../chui_inputs/chui_select_box/select_box");
5
+ const { TextInput } = require("../chui_inputs/chui_text/text");
6
+ const { NumberInput } = require("../chui_inputs/chui_number/number");
7
+ const { DateInput } = require("../chui_inputs/chui_date/date");
8
+ const { I18n } = require("../../modules/chui_i18n/chui_i18n");
9
+ const { Icon, Icons } = require("../chui_icons/icons");
10
10
 
11
11
  /** Соединение условий внутри группы */
12
- const COMBINATOR = {AND: "and", OR: "or"};
12
+ const COMBINATOR = { AND: "and", OR: "or" };
13
13
  /** Типы полей: от типа зависят и операторы, и вид поля значения */
14
- const TYPE = {STRING: "string", NUMBER: "number", BOOLEAN: "boolean", DATE: "date", SELECT: "select"};
14
+ const TYPE = { STRING: "string", NUMBER: "number", BOOLEAN: "boolean", DATE: "date", SELECT: "select" };
15
15
  const TYPES = [TYPE.STRING, TYPE.NUMBER, TYPE.BOOLEAN, TYPE.DATE, TYPE.SELECT];
16
16
  /** Операторы сравнения */
17
17
  const OPERATOR = {
@@ -26,7 +26,7 @@ const OPERATOR = {
26
26
  LESS: "less",
27
27
  LESS_OR_EQUAL: "less_or_equal",
28
28
  IS_EMPTY: "is_empty",
29
- IS_NOT_EMPTY: "is_not_empty"
29
+ IS_NOT_EMPTY: "is_not_empty",
30
30
  };
31
31
  /** Операторы словами — для подписей контролов и `toText()`: внутренние ключи словаря */
32
32
  const OPERATOR_KEYS = {
@@ -41,23 +41,46 @@ const OPERATOR_KEYS = {
41
41
  less: "queryBuilder.operator.less",
42
42
  less_or_equal: "queryBuilder.operator.lessOrEqual",
43
43
  is_empty: "queryBuilder.operator.isEmpty",
44
- is_not_empty: "queryBuilder.operator.isNotEmpty"
44
+ is_not_empty: "queryBuilder.operator.isNotEmpty",
45
45
  };
46
46
  // Публичная таблица отдаёт уже переведённый текст: геттеры читают словарь в момент обращения
47
47
  const OPERATOR_TITLES = {};
48
48
  for (const key of Object.keys(OPERATOR_KEYS)) {
49
- Object.defineProperty(OPERATOR_TITLES, key, {enumerable: true, get: () => I18n.t(OPERATOR_KEYS[key])});
49
+ Object.defineProperty(OPERATOR_TITLES, key, { enumerable: true, get: () => I18n.t(OPERATOR_KEYS[key]) });
50
50
  }
51
51
  /** Операторы по типу поля: «содержит» у числа и «больше» у логического смысла не имеют */
52
52
  const OPERATORS_BY_TYPE = {
53
- string: [OPERATOR.EQUALS, OPERATOR.NOT_EQUALS, OPERATOR.CONTAINS, OPERATOR.NOT_CONTAINS,
54
- OPERATOR.STARTS_WITH, OPERATOR.ENDS_WITH, OPERATOR.IS_EMPTY, OPERATOR.IS_NOT_EMPTY],
55
- number: [OPERATOR.EQUALS, OPERATOR.NOT_EQUALS, OPERATOR.GREATER, OPERATOR.GREATER_OR_EQUAL,
56
- OPERATOR.LESS, OPERATOR.LESS_OR_EQUAL, OPERATOR.IS_EMPTY, OPERATOR.IS_NOT_EMPTY],
57
- date: [OPERATOR.EQUALS, OPERATOR.GREATER, OPERATOR.GREATER_OR_EQUAL, OPERATOR.LESS,
58
- OPERATOR.LESS_OR_EQUAL, OPERATOR.IS_EMPTY, OPERATOR.IS_NOT_EMPTY],
53
+ string: [
54
+ OPERATOR.EQUALS,
55
+ OPERATOR.NOT_EQUALS,
56
+ OPERATOR.CONTAINS,
57
+ OPERATOR.NOT_CONTAINS,
58
+ OPERATOR.STARTS_WITH,
59
+ OPERATOR.ENDS_WITH,
60
+ OPERATOR.IS_EMPTY,
61
+ OPERATOR.IS_NOT_EMPTY,
62
+ ],
63
+ number: [
64
+ OPERATOR.EQUALS,
65
+ OPERATOR.NOT_EQUALS,
66
+ OPERATOR.GREATER,
67
+ OPERATOR.GREATER_OR_EQUAL,
68
+ OPERATOR.LESS,
69
+ OPERATOR.LESS_OR_EQUAL,
70
+ OPERATOR.IS_EMPTY,
71
+ OPERATOR.IS_NOT_EMPTY,
72
+ ],
73
+ date: [
74
+ OPERATOR.EQUALS,
75
+ OPERATOR.GREATER,
76
+ OPERATOR.GREATER_OR_EQUAL,
77
+ OPERATOR.LESS,
78
+ OPERATOR.LESS_OR_EQUAL,
79
+ OPERATOR.IS_EMPTY,
80
+ OPERATOR.IS_NOT_EMPTY,
81
+ ],
59
82
  boolean: [OPERATOR.EQUALS, OPERATOR.NOT_EQUALS],
60
- select: [OPERATOR.EQUALS, OPERATOR.NOT_EQUALS, OPERATOR.IS_EMPTY, OPERATOR.IS_NOT_EMPTY]
83
+ select: [OPERATOR.EQUALS, OPERATOR.NOT_EQUALS, OPERATOR.IS_EMPTY, OPERATOR.IS_NOT_EMPTY],
61
84
  };
62
85
  /** Операторы, которым значение не нужно: у них поле значения не рисуется */
63
86
  const VALUELESS = new Set([OPERATOR.IS_EMPTY, OPERATOR.IS_NOT_EMPTY]);
@@ -128,47 +151,49 @@ class QueryBuilder {
128
151
  #fields = [];
129
152
  #value = undefined;
130
153
  #listeners = [];
131
- #on_change = undefined;
132
- #max_depth = QueryBuilder.MAX_DEPTH;
154
+ #onChange = undefined;
155
+ #maxDepth = QueryBuilder.MAX_DEPTH;
133
156
  #disabled = false;
134
- #error_shown = false;
135
- #node_counter = 0;
136
- #rule_counter = 0;
157
+ #errorShown = false;
158
+ #nodeCounter = 0;
159
+ #ruleCounter = 0;
137
160
  // Переключатели «И/ИЛИ» живут по группе: при перерисовке пересобираются вместе с узлами
138
161
  #combinators = new Map();
139
162
  // Готовые поля условий: их нужно гасить, снимать у них слушатели окна и уметь закрыть
140
163
  // раскрытый список при возврате фокуса после пересборки
141
164
  #controls = [];
142
- #title_text = undefined;
143
- #label_text = undefined;
144
- #empty_text = undefined;
145
-
146
- constructor(options = {
147
- id: String(),
148
- name: String(),
149
- title: String(),
150
- label: String(),
151
- fields: Array(),
152
- value: undefined,
153
- maxDepth: Number(),
154
- emptyText: String(),
155
- required: Boolean(),
156
- messages: Object(),
157
- disabled: Boolean(),
158
- changeListener: undefined,
159
- onChange: undefined
160
- }) {
165
+ #titleText = undefined;
166
+ #labelText = undefined;
167
+ #emptyText = undefined;
168
+
169
+ constructor(
170
+ options = {
171
+ id: String(),
172
+ name: String(),
173
+ title: String(),
174
+ label: String(),
175
+ fields: Array(),
176
+ value: undefined,
177
+ maxDepth: Number(),
178
+ emptyText: String(),
179
+ required: Boolean(),
180
+ messages: Object(),
181
+ disabled: Boolean(),
182
+ changeListener: undefined,
183
+ onChange: undefined,
184
+ }
185
+ ) {
161
186
  setStyles(__dirname + "/styles.css", "chUiJS_QueryBuilder");
162
187
  QueryBuilder.#counter += 1;
163
188
  this.#id = options.id === undefined ? `chui_query_builder_${QueryBuilder.#counter}` : options.id;
164
189
  this.#name = options.name;
165
190
  this.#root.id = this.#id;
166
191
  this.#root.setAttribute("role", "group");
167
- this.#label_text = options.label;
168
- this.#on_change = options.onChange;
169
- if (options.emptyText !== undefined) this.#empty_text = String(options.emptyText);
170
- else this.#empty_text = I18n.t("queryBuilder.empty");
171
- if (options.maxDepth !== undefined) this.#max_depth = Math.max(1, Number(options.maxDepth));
192
+ this.#labelText = options.label;
193
+ this.#onChange = options.onChange;
194
+ if (options.emptyText !== undefined) this.#emptyText = String(options.emptyText);
195
+ else this.#emptyText = I18n.t("queryBuilder.empty");
196
+ if (options.maxDepth !== undefined) this.#maxDepth = Math.max(1, Number(options.maxDepth));
172
197
  this.#title.className = "query_builder_title";
173
198
  this.#title.id = `${this.#id}_title`;
174
199
  this.#tree.className = "query_builder_tree";
@@ -182,19 +207,32 @@ class QueryBuilder {
182
207
  this.#root.appendChild(this.#status);
183
208
  if (options.title !== undefined) this.setTitle(options.title);
184
209
  else this.#title.hidden = true;
185
- this.setLabel(this.#label_text === undefined ? I18n.t("queryBuilder.title") : this.#label_text);
210
+ this.setLabel(this.#labelText === undefined ? I18n.t("queryBuilder.title") : this.#labelText);
186
211
  this.setFields(options.fields === undefined ? [] : options.fields);
187
212
  if (options.value === undefined) this.clear(true);
188
213
  else this.setValue(options.value);
189
214
  // Правила формы и поля читают пустой запрос как пустое значение: за него отвечает required
190
- Validate.installField(this, options, this.#root, this.#error, () => (this.isEmpty() ? "" : this.getText()), this.#tree);
191
- const base_validate = this.validate;
215
+ Validate.installField(
216
+ this,
217
+ options,
218
+ this.#root,
219
+ this.#error,
220
+ () => (this.isEmpty() ? "" : this.getText()),
221
+ this.#tree
222
+ );
223
+ const baseValidate = this.validate;
192
224
  this.validate = () => {
193
- const result = base_validate();
225
+ const result = baseValidate();
194
226
  if (result.valid === false) return result;
195
- const empty = this.#rules().find((rule) => this.#needsValue(rule.operator) && this.#isEmptyValue(rule.value));
227
+ const empty = this.#rules().find(
228
+ (rule) => this.#needsValue(rule.operator) && this.#isEmptyValue(rule.value)
229
+ );
196
230
  if (empty === undefined) return result;
197
- return {valid: false, rule: "query", message: I18n.t("queryBuilder.valueMissing", {index: this.#indexOfRule(empty.id)})};
231
+ return {
232
+ valid: false,
233
+ rule: "query",
234
+ message: I18n.t("queryBuilder.valueMissing", { index: this.#indexOfRule(empty.id) }),
235
+ };
198
236
  };
199
237
  this.setDisabled(options.disabled === true);
200
238
  if (options.changeListener !== undefined) this.addChangeListener(options.changeListener);
@@ -206,11 +244,11 @@ class QueryBuilder {
206
244
  }
207
245
 
208
246
  getTitle() {
209
- return this.#title_text;
247
+ return this.#titleText;
210
248
  }
211
249
 
212
250
  getLabel() {
213
- return this.#label_text;
251
+ return this.#labelText;
214
252
  }
215
253
 
216
254
  /** Имя запроса для формы: с ним `Form.getValues()`/`setValues()` знают, куда класть дерево */
@@ -220,7 +258,9 @@ class QueryBuilder {
220
258
 
221
259
  /** Описания полей: копии того, что задано в `setFields()` */
222
260
  getFields() {
223
- return this.#fields.map((field) => Object.assign({}, field, {options: field.options.map((option) => Object.assign({}, option))}));
261
+ return this.#fields.map((field) =>
262
+ Object.assign({}, field, { options: field.options.map((option) => Object.assign({}, option)) })
263
+ );
224
264
  }
225
265
 
226
266
  /** Дерево запроса: `{id, combinator, children}`, у условий есть `id` */
@@ -235,7 +275,7 @@ class QueryBuilder {
235
275
 
236
276
  /** Плоский список условий `[{field, operator, value}]` — в порядке обхода дерева */
237
277
  getConditions() {
238
- return this.#rules().map((rule) => ({field: rule.field, operator: rule.operator, value: rule.value}));
278
+ return this.#rules().map((rule) => ({ field: rule.field, operator: rule.operator, value: rule.value }));
239
279
  }
240
280
 
241
281
  /** Идентификаторы условий в порядке обхода — для `removeRule()` и `focus()` */
@@ -264,7 +304,7 @@ class QueryBuilder {
264
304
  }
265
305
 
266
306
  getMaxDepth() {
267
- return this.#max_depth;
307
+ return this.#maxDepth;
268
308
  }
269
309
 
270
310
  isDisabled() {
@@ -272,7 +312,7 @@ class QueryBuilder {
272
312
  }
273
313
 
274
314
  getEmptyText() {
275
- return this.#empty_text;
315
+ return this.#emptyText;
276
316
  }
277
317
 
278
318
  /** Запрос словами: «Статус равно «Оплачен» И Сумма больше 1000» */
@@ -291,7 +331,7 @@ class QueryBuilder {
291
331
 
292
332
  /** Подпись над запросом; `undefined` её убирает (имя тогда даёт `label`) */
293
333
  setTitle(text = undefined) {
294
- this.#title_text = text;
334
+ this.#titleText = text;
295
335
  if (text === undefined || text === "") {
296
336
  this.#title.hidden = true;
297
337
  this.#title.innerText = "";
@@ -306,7 +346,7 @@ class QueryBuilder {
306
346
 
307
347
  /** Имя запроса, когда подписи в разметке нет */
308
348
  setLabel(text = undefined) {
309
- this.#label_text = text;
349
+ this.#labelText = text;
310
350
  this.#syncLabel();
311
351
  return this;
312
352
  }
@@ -328,10 +368,12 @@ class QueryBuilder {
328
368
  key: String(field.key),
329
369
  label: field.label === undefined ? String(field.key) : String(field.label),
330
370
  type: TYPES.includes(type) ? type : TYPE.STRING,
331
- options: Array.isArray(field.options) ? field.options.map((option) => ({
332
- value: String(option.value),
333
- title: option.title === undefined ? String(option.value) : String(option.title)
334
- })) : []
371
+ options: Array.isArray(field.options)
372
+ ? field.options.map((option) => ({
373
+ value: String(option.value),
374
+ title: option.title === undefined ? String(option.value) : String(option.title),
375
+ }))
376
+ : [],
335
377
  };
336
378
  });
337
379
  for (const rule of this.#rules()) {
@@ -347,7 +389,7 @@ class QueryBuilder {
347
389
 
348
390
  /** Дерево запроса; `silent` (как у полей формы) — молча, без уведомления слушателей */
349
391
  setValue(value = Object(), silent = false) {
350
- this.#node_counter = 0;
392
+ this.#nodeCounter = 0;
351
393
  this.#value = this.#toGroup(value, 1);
352
394
  this.#render();
353
395
  if (silent === false) this.#notify();
@@ -355,13 +397,13 @@ class QueryBuilder {
355
397
  }
356
398
 
357
399
  setMaxDepth(depth = Number()) {
358
- this.#max_depth = Math.max(1, Number(depth));
400
+ this.#maxDepth = Math.max(1, Number(depth));
359
401
  this.#render();
360
402
  return this;
361
403
  }
362
404
 
363
405
  setEmptyText(text = String()) {
364
- this.#empty_text = text === undefined ? "" : String(text);
406
+ this.#emptyText = text === undefined ? "" : String(text);
365
407
  this.#render();
366
408
  return this;
367
409
  }
@@ -374,7 +416,9 @@ class QueryBuilder {
374
416
  if (group.combinator === next) return this;
375
417
  group.combinator = next;
376
418
  this.#render();
377
- this.#announce(I18n.t("queryBuilder.connectionChanged", {combinator: I18n.t(QueryBuilder.#combinatorTitle(next))}));
419
+ this.#announce(
420
+ I18n.t("queryBuilder.connectionChanged", { combinator: I18n.t(QueryBuilder.#combinatorTitle(next)) })
421
+ );
378
422
  this.#notify();
379
423
  return this;
380
424
  }
@@ -391,7 +435,7 @@ class QueryBuilder {
391
435
  const rule = this.#emptyRule(field);
392
436
  group.children.push(rule);
393
437
  this.#render();
394
- this.#announce(I18n.t("queryBuilder.ruleAdded", {index: this.#indexOfRule(rule.id)}));
438
+ this.#announce(I18n.t("queryBuilder.ruleAdded", { index: this.#indexOfRule(rule.id) }));
395
439
  this.#refreshErrors();
396
440
  this.#notify();
397
441
  return rule.id;
@@ -405,18 +449,20 @@ class QueryBuilder {
405
449
  addGroup(groupId = undefined) {
406
450
  const group = groupId === undefined ? this.#value : this.#group(groupId);
407
451
  if (group === undefined) return undefined;
408
- if (this.#depthOf(group) >= this.#max_depth) return undefined;
452
+ if (this.#depthOf(group) >= this.#maxDepth) return undefined;
409
453
  const field = this.#fields[0];
410
454
  if (field === undefined) return undefined;
411
455
  const nested = {
412
456
  kind: "group",
413
457
  id: this.#nextId("group"),
414
458
  combinator: COMBINATOR.AND,
415
- children: [this.#emptyRule(field)]
459
+ children: [this.#emptyRule(field)],
416
460
  };
417
461
  group.children.push(nested);
418
462
  this.#render();
419
- this.#announce(I18n.t("queryBuilder.groupAdded", {index: this.#groups().findIndex((item) => item.id === nested.id) + 1}));
463
+ this.#announce(
464
+ I18n.t("queryBuilder.groupAdded", { index: this.#groups().findIndex((item) => item.id === nested.id) + 1 })
465
+ );
420
466
  this.#refreshErrors();
421
467
  this.#notify();
422
468
  return nested.id;
@@ -428,7 +474,7 @@ class QueryBuilder {
428
474
  if (index === 0) return this;
429
475
  this.#removeNode(id);
430
476
  this.#render();
431
- this.#announce(I18n.t("queryBuilder.ruleRemoved", {index: index}));
477
+ this.#announce(I18n.t("queryBuilder.ruleRemoved", { index: index }));
432
478
  this.#refreshErrors();
433
479
  this.#notify();
434
480
  return this;
@@ -441,7 +487,7 @@ class QueryBuilder {
441
487
  if (index === -1) return this;
442
488
  this.#removeNode(id);
443
489
  this.#render();
444
- this.#announce(I18n.t("queryBuilder.groupRemoved", {index: index + 1}));
490
+ this.#announce(I18n.t("queryBuilder.groupRemoved", { index: index + 1 }));
445
491
  this.#refreshErrors();
446
492
  this.#notify();
447
493
  return this;
@@ -449,7 +495,7 @@ class QueryBuilder {
449
495
 
450
496
  /** Убрать все условия и группы: остаётся пустой корень */
451
497
  clear(silent = false) {
452
- this.#value = {kind: "group", id: this.#nextId("group"), combinator: COMBINATOR.AND, children: []};
498
+ this.#value = { kind: "group", id: this.#nextId("group"), combinator: COMBINATOR.AND, children: [] };
453
499
  this.#render();
454
500
  if (silent === false) this.#notify();
455
501
  return this;
@@ -472,9 +518,10 @@ class QueryBuilder {
472
518
  focus(id = undefined) {
473
519
  const rules = this.#rules();
474
520
  const rule = id === undefined ? rules[0] : rules.find((item) => item.id === id);
475
- const selector = rule === undefined
476
- ? "query_builder_rule .query_builder_field input"
477
- : `query_builder_rule[data-id="${CSS.escape(rule.id)}"] .query_builder_field input`;
521
+ const selector =
522
+ rule === undefined
523
+ ? "query_builder_rule .query_builder_field input"
524
+ : `query_builder_rule[data-id="${CSS.escape(rule.id)}"] .query_builder_field input`;
478
525
  const node = this.#tree.querySelector(selector);
479
526
  if (node !== null) node.focus();
480
527
  return this;
@@ -484,12 +531,12 @@ class QueryBuilder {
484
531
  check() {
485
532
  const result = this.validate();
486
533
  if (result.valid) {
487
- this.#error_shown = false;
534
+ this.#errorShown = false;
488
535
  this.clearError();
489
536
  this.#announce(this.isEmpty() ? I18n.t("queryBuilder.empty") : I18n.t("queryBuilder.valid"));
490
537
  return this;
491
538
  }
492
- this.#error_shown = true;
539
+ this.#errorShown = true;
493
540
  this.setError(result.message);
494
541
  this.#syncErrors();
495
542
  this.#announce(result.message);
@@ -515,8 +562,8 @@ class QueryBuilder {
515
562
 
516
563
  // === ВНУТРЕННЕЕ ===
517
564
  #nextId(prefix = String()) {
518
- this.#node_counter += 1;
519
- return `${this.#id}_${prefix}_${this.#node_counter}`;
565
+ this.#nodeCounter += 1;
566
+ return `${this.#id}_${prefix}_${this.#nodeCounter}`;
520
567
  }
521
568
 
522
569
  #emptyRule(field = Object()) {
@@ -525,7 +572,7 @@ class QueryBuilder {
525
572
  id: this.#nextId("rule"),
526
573
  field: field.key,
527
574
  operator: OPERATORS_BY_TYPE[field.type][0],
528
- value: undefined
575
+ value: undefined,
529
576
  };
530
577
  }
531
578
 
@@ -534,7 +581,7 @@ class QueryBuilder {
534
581
  const found = this.#fields.find((field) => field.key === key);
535
582
  if (found !== undefined) return found;
536
583
  return this.#fields[0] === undefined
537
- ? {key: String(key), label: String(key), type: TYPE.STRING, options: []}
584
+ ? { key: String(key), label: String(key), type: TYPE.STRING, options: [] }
538
585
  : this.#fields[0];
539
586
  }
540
587
 
@@ -545,13 +592,13 @@ class QueryBuilder {
545
592
  kind: "group",
546
593
  id: typeof source.id === "string" ? source.id : this.#nextId("group"),
547
594
  combinator: source.combinator === COMBINATOR.OR ? COMBINATOR.OR : COMBINATOR.AND,
548
- children: []
595
+ children: [],
549
596
  };
550
597
  const children = Array.isArray(source.children) ? source.children : [];
551
598
  for (const child of children) {
552
599
  if (child === undefined || child === null || typeof child !== "object") continue;
553
600
  if (child.children !== undefined || child.combinator !== undefined) {
554
- if (depth >= this.#max_depth) continue;
601
+ if (depth >= this.#maxDepth) continue;
555
602
  group.children.push(this.#toGroup(child, depth + 1));
556
603
  continue;
557
604
  }
@@ -563,7 +610,7 @@ class QueryBuilder {
563
610
  id: typeof child.id === "string" ? child.id : this.#nextId("rule"),
564
611
  field: field.key,
565
612
  operator: operators.includes(child.operator) ? child.operator : operators[0],
566
- value: child.value
613
+ value: child.value,
567
614
  });
568
615
  }
569
616
  return group;
@@ -573,9 +620,11 @@ class QueryBuilder {
573
620
  return {
574
621
  id: group.id,
575
622
  combinator: group.combinator,
576
- children: group.children.map((child) => (child.kind === "group"
577
- ? QueryBuilder.#describeGroup(child)
578
- : {id: child.id, field: child.field, operator: child.operator, value: child.value}))
623
+ children: group.children.map((child) =>
624
+ child.kind === "group"
625
+ ? QueryBuilder.#describeGroup(child)
626
+ : { id: child.id, field: child.field, operator: child.operator, value: child.value }
627
+ ),
579
628
  };
580
629
  }
581
630
 
@@ -630,7 +679,7 @@ class QueryBuilder {
630
679
  }
631
680
  return undefined;
632
681
  };
633
- return this.#value === undefined ? 1 : walk(this.#value, 1) ?? 1;
682
+ return this.#value === undefined ? 1 : (walk(this.#value, 1) ?? 1);
634
683
  }
635
684
 
636
685
  /** Номер условия в порядке обхода; 0 — условия с таким `id` нет */
@@ -653,27 +702,28 @@ class QueryBuilder {
653
702
  let mark = undefined;
654
703
  if (active !== null && active !== undefined && this.#tree.contains(active)) {
655
704
  const owner = active.closest("query_builder_rule, query_builder_group");
656
- if (owner !== null) mark = {
657
- owner: owner.dataset.id,
658
- control: QueryBuilder.#controlMark(active),
659
- // Раскрытый список должен остаться раскрытым, закрытый — закрытым
660
- open: active.getAttribute("aria-expanded") === "true"
661
- };
705
+ if (owner !== null)
706
+ mark = {
707
+ owner: owner.dataset.id,
708
+ control: QueryBuilder.#controlMark(active),
709
+ // Раскрытый список должен остаться раскрытым, закрытый — закрытым
710
+ open: active.getAttribute("aria-expanded") === "true",
711
+ };
662
712
  }
663
713
  this.#destroyControls();
664
714
  this.#tree.innerHTML = "";
665
715
  this.#combinators.clear();
666
- this.#rule_counter = 0;
716
+ this.#ruleCounter = 0;
667
717
  if (this.#value === undefined || this.#fields.length === 0) {
668
718
  this.#tree.hidden = true;
669
719
  this.#empty.hidden = false;
670
- this.#empty.innerText = this.#fields.length === 0 ? I18n.t("queryBuilder.noFields") : this.#empty_text;
720
+ this.#empty.innerText = this.#fields.length === 0 ? I18n.t("queryBuilder.noFields") : this.#emptyText;
671
721
  return this;
672
722
  }
673
723
  this.#tree.appendChild(this.#groupNode(this.#value, 0));
674
724
  this.#tree.hidden = false;
675
725
  this.#empty.hidden = true;
676
- this.#empty.innerText = this.#empty_text;
726
+ this.#empty.innerText = this.#emptyText;
677
727
  this.#syncErrors();
678
728
  if (mark !== undefined) {
679
729
  const node = this.#tree.querySelector(`[data-id="${CSS.escape(mark.owner)}"] ${mark.control}`);
@@ -705,13 +755,14 @@ class QueryBuilder {
705
755
  * (три `Select` в строке), поэтому контрол ищется вместе с обёрткой условия.
706
756
  */
707
757
  static #controlMark(node = Object()) {
708
- if (node.tagName === "SEGMENTED_OPTION") return `segmented_option[data-value="${CSS.escape(node.dataset.value)}"]`;
758
+ if (node.tagName === "SEGMENTED_OPTION")
759
+ return `segmented_option[data-value="${CSS.escape(node.dataset.value)}"]`;
709
760
  const list = [...node.classList];
710
761
  const own = list.length > 0 ? `.${CSS.escape(list[0])}` : node.tagName.toLowerCase();
711
762
  const holder = node.closest(".query_builder_field, .query_builder_operator, .query_builder_value");
712
763
  if (holder === null) return own;
713
- const holder_class = [...holder.classList].find((name) => name.startsWith("query_builder_"));
714
- return holder_class === undefined ? own : `.${CSS.escape(holder_class)} ${own}`;
764
+ const holderClass = [...holder.classList].find((name) => name.startsWith("query_builder_"));
765
+ return holderClass === undefined ? own : `.${CSS.escape(holderClass)} ${own}`;
715
766
  }
716
767
 
717
768
  #groupNode(group = Object(), depth = Number()) {
@@ -720,10 +771,16 @@ class QueryBuilder {
720
771
  node.dataset.id = group.id;
721
772
  node.style.setProperty("--query_builder_depth", String(depth));
722
773
  node.setAttribute("role", "group");
723
- node.setAttribute("aria-label", I18n.t("queryBuilder.groupAria", {
724
- name: depth === 0 ? I18n.t("queryBuilder.conditions") : I18n.t("queryBuilder.nestedGroup", {depth: depth}),
725
- combinator: I18n.t(QueryBuilder.#combinatorTitle(group.combinator))
726
- }));
774
+ node.setAttribute(
775
+ "aria-label",
776
+ I18n.t("queryBuilder.groupAria", {
777
+ name:
778
+ depth === 0
779
+ ? I18n.t("queryBuilder.conditions")
780
+ : I18n.t("queryBuilder.nestedGroup", { depth: depth }),
781
+ combinator: I18n.t(QueryBuilder.#combinatorTitle(group.combinator)),
782
+ })
783
+ );
727
784
  node.appendChild(this.#groupHead(group, depth));
728
785
  node.appendChild(this.#groupChildren(group, depth));
729
786
  node.appendChild(this.#groupFoot(group, depth));
@@ -735,14 +792,17 @@ class QueryBuilder {
735
792
  head.className = "query_builder_group_head";
736
793
  const combinator = new SegmentedControl({
737
794
  id: `${group.id}_combinator`,
738
- label: depth === 0 ? I18n.t("queryBuilder.connection") : I18n.t("queryBuilder.connectionOfGroup", {depth: depth}),
795
+ label:
796
+ depth === 0
797
+ ? I18n.t("queryBuilder.connection")
798
+ : I18n.t("queryBuilder.connectionOfGroup", { depth: depth }),
739
799
  size: SegmentedControl.SIZE.SMALL,
740
800
  options: [
741
- {value: COMBINATOR.AND, title: I18n.t("queryBuilder.and")},
742
- {value: COMBINATOR.OR, title: I18n.t("queryBuilder.or")}
801
+ { value: COMBINATOR.AND, title: I18n.t("queryBuilder.and") },
802
+ { value: COMBINATOR.OR, title: I18n.t("queryBuilder.or") },
743
803
  ],
744
804
  value: group.combinator,
745
- onChange: (value) => this.setCombinator(group.id, value)
805
+ onChange: (value) => this.setCombinator(group.id, value),
746
806
  });
747
807
  combinator.setStretch(false);
748
808
  this.#combinators.set(group.id, combinator);
@@ -751,13 +811,13 @@ class QueryBuilder {
751
811
  const summary = document.createElement("query_builder_summary");
752
812
  summary.className = "query_builder_summary";
753
813
  summary.setAttribute("aria-hidden", "true");
754
- summary.innerText = I18n.t("queryBuilder.rulesCount", {count: count});
814
+ summary.innerText = I18n.t("queryBuilder.rulesCount", { count: count });
755
815
  head.appendChild(summary);
756
816
  if (depth > 0) {
757
817
  const remove = document.createElement("button");
758
818
  remove.type = "button";
759
819
  remove.className = "query_builder_remove query_builder_remove_group";
760
- remove.setAttribute("aria-label", I18n.t("queryBuilder.removeGroup", {depth: depth}));
820
+ remove.setAttribute("aria-label", I18n.t("queryBuilder.removeGroup", { depth: depth }));
761
821
  const glyph = new Icon(Icons.CONTENT.REMOVE, "18px").set();
762
822
  glyph.setAttribute("aria-hidden", "true");
763
823
  remove.appendChild(glyph);
@@ -776,7 +836,7 @@ class QueryBuilder {
776
836
  if (group.children.length === 0) {
777
837
  const note = document.createElement("query_builder_group_empty");
778
838
  note.className = "query_builder_group_empty";
779
- note.innerText = this.#empty_text;
839
+ note.innerText = this.#emptyText;
780
840
  list.appendChild(note);
781
841
  return list;
782
842
  }
@@ -789,17 +849,27 @@ class QueryBuilder {
789
849
  #groupFoot(group = Object(), depth = Number()) {
790
850
  const foot = document.createElement("query_builder_group_foot");
791
851
  foot.className = "query_builder_group_foot";
792
- foot.appendChild(this.#addButton({
793
- title: I18n.t("queryBuilder.ruleShort"),
794
- label: depth === 0 ? I18n.t("queryBuilder.addRule") : I18n.t("queryBuilder.addRuleInGroup", {depth: depth}),
795
- onClick: () => this.addRule(group.id)
796
- }));
797
- if (this.#depthOf(group) < this.#max_depth) {
798
- foot.appendChild(this.#addButton({
799
- title: I18n.t("queryBuilder.groupShort"),
800
- label: depth === 0 ? I18n.t("queryBuilder.addGroup") : I18n.t("queryBuilder.addGroupInGroup", {depth: depth}),
801
- onClick: () => this.addGroup(group.id)
802
- }));
852
+ foot.appendChild(
853
+ this.#addButton({
854
+ title: I18n.t("queryBuilder.ruleShort"),
855
+ label:
856
+ depth === 0
857
+ ? I18n.t("queryBuilder.addRule")
858
+ : I18n.t("queryBuilder.addRuleInGroup", { depth: depth }),
859
+ onClick: () => this.addRule(group.id),
860
+ })
861
+ );
862
+ if (this.#depthOf(group) < this.#maxDepth) {
863
+ foot.appendChild(
864
+ this.#addButton({
865
+ title: I18n.t("queryBuilder.groupShort"),
866
+ label:
867
+ depth === 0
868
+ ? I18n.t("queryBuilder.addGroup")
869
+ : I18n.t("queryBuilder.addGroupInGroup", { depth: depth }),
870
+ onClick: () => this.addGroup(group.id),
871
+ })
872
+ );
803
873
  }
804
874
  return foot;
805
875
  }
@@ -851,7 +921,7 @@ class QueryBuilder {
851
921
 
852
922
  /** Запомнить готовое поле вместе с его узлом: по узлу его найдут после пересборки */
853
923
  #track(component = Object(), node = new HTMLElement()) {
854
- this.#controls.push({component: component, node: node});
924
+ this.#controls.push({ component: component, node: node });
855
925
  return node;
856
926
  }
857
927
 
@@ -864,33 +934,40 @@ class QueryBuilder {
864
934
  }
865
935
 
866
936
  #ruleNode(rule = Object()) {
867
- this.#rule_counter += 1;
868
- const index = this.#rule_counter;
937
+ this.#ruleCounter += 1;
938
+ const index = this.#ruleCounter;
869
939
  const field = this.#fieldOf(rule.field);
870
940
  const node = document.createElement("query_builder_rule");
871
941
  node.className = "query_builder_rule";
872
942
  node.dataset.id = rule.id;
873
943
  node.setAttribute("role", "group");
874
- node.setAttribute("aria-label", I18n.t("queryBuilder.ruleLabel", {index: index}));
875
- node.appendChild(this.#selectControl({
876
- className: "query_builder_field",
877
- label: I18n.t("queryBuilder.fieldOfRule", {index: index}),
878
- options: this.#fields.map((item) => ({value: item.key, title: item.label})),
879
- value: field.key,
880
- onChange: (value) => this.#changeField(rule.id, value)
881
- }));
882
- node.appendChild(this.#selectControl({
883
- className: "query_builder_operator",
884
- label: I18n.t("queryBuilder.operatorOfRule", {index: index}),
885
- options: OPERATORS_BY_TYPE[field.type].map((operator) => ({value: operator, title: I18n.t(OPERATOR_KEYS[operator])})),
886
- value: rule.operator,
887
- onChange: (value) => this.#changeOperator(rule.id, value)
888
- }));
944
+ node.setAttribute("aria-label", I18n.t("queryBuilder.ruleLabel", { index: index }));
945
+ node.appendChild(
946
+ this.#selectControl({
947
+ className: "query_builder_field",
948
+ label: I18n.t("queryBuilder.fieldOfRule", { index: index }),
949
+ options: this.#fields.map((item) => ({ value: item.key, title: item.label })),
950
+ value: field.key,
951
+ onChange: (value) => this.#changeField(rule.id, value),
952
+ })
953
+ );
954
+ node.appendChild(
955
+ this.#selectControl({
956
+ className: "query_builder_operator",
957
+ label: I18n.t("queryBuilder.operatorOfRule", { index: index }),
958
+ options: OPERATORS_BY_TYPE[field.type].map((operator) => ({
959
+ value: operator,
960
+ title: I18n.t(OPERATOR_KEYS[operator]),
961
+ })),
962
+ value: rule.operator,
963
+ onChange: (value) => this.#changeOperator(rule.id, value),
964
+ })
965
+ );
889
966
  if (this.#needsValue(rule.operator)) node.appendChild(this.#valueControl(rule, field, index));
890
967
  const remove = document.createElement("button");
891
968
  remove.type = "button";
892
969
  remove.className = "query_builder_remove query_builder_remove_rule";
893
- remove.setAttribute("aria-label", I18n.t("queryBuilder.removeRule", {index: index}));
970
+ remove.setAttribute("aria-label", I18n.t("queryBuilder.removeRule", { index: index }));
894
971
  const glyph = new Icon(Icons.CONTENT.REMOVE, "18px").set();
895
972
  glyph.setAttribute("aria-hidden", "true");
896
973
  remove.appendChild(glyph);
@@ -907,19 +984,23 @@ class QueryBuilder {
907
984
  #valueControl(rule = Object(), field = Object(), index = Number()) {
908
985
  const unset = rule.value === undefined || rule.value === null;
909
986
  if (field.type === TYPE.BOOLEAN || field.type === TYPE.SELECT) {
910
- const options = field.type === TYPE.BOOLEAN
911
- ? [{value: "true", title: I18n.t("queryBuilder.yes")}, {value: "false", title: I18n.t("queryBuilder.no")}]
912
- : field.options;
987
+ const options =
988
+ field.type === TYPE.BOOLEAN
989
+ ? [
990
+ { value: "true", title: I18n.t("queryBuilder.yes") },
991
+ { value: "false", title: I18n.t("queryBuilder.no") },
992
+ ]
993
+ : field.options;
913
994
  // Пустой вариант показывает «значение не выбрано» честно: модель и вид не расходятся
914
995
  return this.#selectControl({
915
996
  className: "query_builder_value",
916
- label: I18n.t("queryBuilder.valueOfRule", {index: index}),
917
- options: [{value: "", title: I18n.t(UNSET_TITLE)}].concat(options),
997
+ label: I18n.t("queryBuilder.valueOfRule", { index: index }),
998
+ options: [{ value: "", title: I18n.t(UNSET_TITLE) }].concat(options),
918
999
  value: unset ? "" : String(rule.value),
919
- onChange: (value) => this.#changeValue(rule.id, value)
1000
+ onChange: (value) => this.#changeValue(rule.id, value),
920
1001
  });
921
1002
  }
922
- const label = I18n.t("queryBuilder.valueOfRule", {index: index});
1003
+ const label = I18n.t("queryBuilder.valueOfRule", { index: index });
923
1004
  // У числа значение живёт по подтверждению: недонабранное «1e» или «-» в модель не попадает
924
1005
  if (field.type === TYPE.NUMBER) {
925
1006
  const number = new NumberInput({});
@@ -940,7 +1021,7 @@ class QueryBuilder {
940
1021
  return this.#bindValueControl(this.#track(date, date.set()), "query_builder_value", label);
941
1022
  }
942
1023
  // Строка: значение живёт по вводу, поэтому слушатель на input, а не на change
943
- const text = new TextInput({placeholder: I18n.t("queryBuilder.value")});
1024
+ const text = new TextInput({ placeholder: I18n.t("queryBuilder.value") });
944
1025
  text.setValue(unset ? "" : String(rule.value));
945
1026
  text.addInputListener(() => this.#changeValue(rule.id, text.getValue()));
946
1027
  return this.#bindValueControl(this.#track(text, text.set()), "query_builder_value", label);
@@ -964,7 +1045,7 @@ class QueryBuilder {
964
1045
  }
965
1046
  rule.value = undefined;
966
1047
  this.#render();
967
- this.#announce(I18n.t("queryBuilder.fieldChanged", {index: this.#indexOfRule(ruleId), label: field.label}));
1048
+ this.#announce(I18n.t("queryBuilder.fieldChanged", { index: this.#indexOfRule(ruleId), label: field.label }));
968
1049
  this.#refreshErrors();
969
1050
  this.#notify();
970
1051
  return this;
@@ -976,7 +1057,12 @@ class QueryBuilder {
976
1057
  rule.operator = operator;
977
1058
  if (this.#needsValue(operator) === false) rule.value = undefined;
978
1059
  this.#render();
979
- this.#announce(I18n.t("queryBuilder.operatorChanged", {index: this.#indexOfRule(ruleId), operator: I18n.t(OPERATOR_KEYS[operator])}));
1060
+ this.#announce(
1061
+ I18n.t("queryBuilder.operatorChanged", {
1062
+ index: this.#indexOfRule(ruleId),
1063
+ operator: I18n.t(OPERATOR_KEYS[operator]),
1064
+ })
1065
+ );
980
1066
  this.#refreshErrors();
981
1067
  this.#notify();
982
1068
  return this;
@@ -1028,15 +1114,19 @@ class QueryBuilder {
1028
1114
 
1029
1115
  static #groupText(group = Object(), fields = Array()) {
1030
1116
  if (group === undefined) return "";
1031
- const parts = group.children.map((child) => (child.kind === "group"
1032
- ? `(${QueryBuilder.#groupText(child, fields)})`
1033
- : QueryBuilder.#valueText(child, fields)));
1117
+ const parts = group.children.map((child) =>
1118
+ child.kind === "group"
1119
+ ? `(${QueryBuilder.#groupText(child, fields)})`
1120
+ : QueryBuilder.#valueText(child, fields)
1121
+ );
1034
1122
  if (parts.length === 0) return "";
1035
- return parts.length === 1 ? parts[0] : parts.join(` ${I18n.t(QueryBuilder.#combinatorTitle(group.combinator))} `);
1123
+ return parts.length === 1
1124
+ ? parts[0]
1125
+ : parts.join(` ${I18n.t(QueryBuilder.#combinatorTitle(group.combinator))} `);
1036
1126
  }
1037
1127
 
1038
1128
  #syncLabel() {
1039
- if (this.#title_text !== undefined && this.#title_text !== "") {
1129
+ if (this.#titleText !== undefined && this.#titleText !== "") {
1040
1130
  this.#root.setAttribute("aria-labelledby", this.#title.id);
1041
1131
  this.#root.removeAttribute("aria-label");
1042
1132
  } else {
@@ -1047,8 +1137,8 @@ class QueryBuilder {
1047
1137
  }
1048
1138
 
1049
1139
  #accessibleName() {
1050
- if (this.#title_text !== undefined && this.#title_text !== "") return this.#title_text;
1051
- if (this.#label_text !== undefined && this.#label_text !== "") return this.#label_text;
1140
+ if (this.#titleText !== undefined && this.#titleText !== "") return this.#titleText;
1141
+ if (this.#labelText !== undefined && this.#labelText !== "") return this.#labelText;
1052
1142
  return I18n.t("queryBuilder.title");
1053
1143
  }
1054
1144
 
@@ -1057,17 +1147,20 @@ class QueryBuilder {
1057
1147
  for (const rule of this.#rules()) {
1058
1148
  const node = this.#tree.querySelector(`query_builder_rule[data-id="${CSS.escape(rule.id)}"]`);
1059
1149
  if (node === null) continue;
1060
- node.classList.toggle("query_builder_rule_empty", this.#needsValue(rule.operator) && this.#isEmptyValue(rule.value));
1150
+ node.classList.toggle(
1151
+ "query_builder_rule_empty",
1152
+ this.#needsValue(rule.operator) && this.#isEmptyValue(rule.value)
1153
+ );
1061
1154
  }
1062
1155
  return this;
1063
1156
  }
1064
1157
 
1065
1158
  /** После правки показанная ошибка пересчитывается: она не должна пережить своё условие */
1066
1159
  #refreshErrors() {
1067
- if (this.#error_shown === false) return this;
1160
+ if (this.#errorShown === false) return this;
1068
1161
  const result = this.validate();
1069
1162
  if (result.valid) {
1070
- this.#error_shown = false;
1163
+ this.#errorShown = false;
1071
1164
  this.clearError();
1072
1165
  return this;
1073
1166
  }
@@ -1084,9 +1177,9 @@ class QueryBuilder {
1084
1177
  #notify() {
1085
1178
  const value = this.getValue();
1086
1179
  for (const listener of [...this.#listeners]) listener(value, this);
1087
- if (this.#on_change !== undefined) this.#on_change(value, this);
1180
+ if (this.#onChange !== undefined) this.#onChange(value, this);
1088
1181
  return this;
1089
1182
  }
1090
1183
  }
1091
1184
 
1092
- exports.QueryBuilder = QueryBuilder
1185
+ exports.QueryBuilder = QueryBuilder;