chuijs 4.0.2 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +43 -644
  3. package/framework/appLayout/default/chui_app_layout.js +308 -260
  4. package/framework/appLayout/default/global_style.css +85 -48
  5. package/framework/components/chui_accordion/accordion.js +29 -26
  6. package/framework/components/chui_accordion/styles.css +6 -5
  7. package/framework/components/chui_action_sheet/action_sheet.js +59 -33
  8. package/framework/components/chui_action_sheet/styles.css +2 -1
  9. package/framework/components/chui_affix/affix.js +11 -6
  10. package/framework/components/chui_alert/alert.js +23 -14
  11. package/framework/components/chui_avatar/avatar.js +23 -22
  12. package/framework/components/chui_avatar_group/avatar_group.js +21 -19
  13. package/framework/components/chui_backtop/backtop.js +35 -19
  14. package/framework/components/chui_badge/badge.js +15 -13
  15. package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
  16. package/framework/components/chui_button/button.js +42 -22
  17. package/framework/components/chui_button/styles.css +2 -2
  18. package/framework/components/chui_calendar/calendar.js +12 -10
  19. package/framework/components/chui_card/card.js +43 -23
  20. package/framework/components/chui_chat/chat.js +72 -33
  21. package/framework/components/chui_clipboard_history/clipboard_history.js +30 -21
  22. package/framework/components/chui_clipboard_history/styles.css +4 -2
  23. package/framework/components/chui_code/code.js +2 -2
  24. package/framework/components/chui_code/styles.css +2 -2
  25. package/framework/components/chui_code_editor/code_editor.js +47 -31
  26. package/framework/components/chui_code_editor/styles.css +3 -2
  27. package/framework/components/chui_command_palette/command_palette.js +60 -37
  28. package/framework/components/chui_console/console.js +5 -5
  29. package/framework/components/chui_console/styles.css +1 -1
  30. package/framework/components/chui_content_block/content_block.js +33 -19
  31. package/framework/components/chui_content_block/styles.css +2 -2
  32. package/framework/components/chui_context_menu/context_menu.js +9 -4
  33. package/framework/components/chui_custom_element/custom_element.js +22 -15
  34. package/framework/components/chui_data_grid/data_grid.js +396 -234
  35. package/framework/components/chui_data_grid/styles.css +10 -8
  36. package/framework/components/chui_descriptions/descriptions.js +34 -17
  37. package/framework/components/chui_details/details.js +32 -26
  38. package/framework/components/chui_details/styles.css +5 -4
  39. package/framework/components/chui_diff_viewer/diff_viewer.js +91 -66
  40. package/framework/components/chui_diff_viewer/styles.css +1 -1
  41. package/framework/components/chui_divider/divider.js +13 -11
  42. package/framework/components/chui_drawer/drawer.js +27 -25
  43. package/framework/components/chui_drop_zone/drop_zone.js +31 -21
  44. package/framework/components/chui_empty_state/empty_state.js +20 -15
  45. package/framework/components/chui_fieldset/fieldset.js +37 -20
  46. package/framework/components/chui_fieldset/styles.css +1 -1
  47. package/framework/components/chui_file_explorer/file_explorer.js +157 -86
  48. package/framework/components/chui_file_explorer/styles.css +2 -1
  49. package/framework/components/chui_form/form.js +31 -19
  50. package/framework/components/chui_form/styles.css +1 -1
  51. package/framework/components/chui_gantt/gantt.js +64 -40
  52. package/framework/components/chui_graphs/graphs.js +301 -200
  53. package/framework/components/chui_graphs/styles.css +1 -1
  54. package/framework/components/chui_hero/hero.js +40 -22
  55. package/framework/components/chui_html_block/html_block.js +6 -6
  56. package/framework/components/chui_html_block/styles.css +2 -2
  57. package/framework/components/chui_hx/hx.js +3 -3
  58. package/framework/components/chui_hx/styles.css +11 -4
  59. package/framework/components/chui_icons/icons.js +2109 -2109
  60. package/framework/components/chui_icons/styles.css +2 -2
  61. package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
  62. package/framework/components/chui_inputs/chui_check_box/styles.css +18 -18
  63. package/framework/components/chui_inputs/chui_chips/chips.js +50 -40
  64. package/framework/components/chui_inputs/chui_chips/styles.css +4 -2
  65. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +36 -24
  66. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +100 -82
  67. package/framework/components/chui_inputs/chui_combo_box/styles.css +14 -12
  68. package/framework/components/chui_inputs/chui_date/date.js +102 -66
  69. package/framework/components/chui_inputs/chui_date/styles.css +12 -11
  70. package/framework/components/chui_inputs/chui_date_range/date_range.js +40 -29
  71. package/framework/components/chui_inputs/chui_datetime/datetime.js +35 -27
  72. package/framework/components/chui_inputs/chui_email/email.js +43 -31
  73. package/framework/components/chui_inputs/chui_email/styles.css +5 -5
  74. package/framework/components/chui_inputs/chui_file/file.js +68 -41
  75. package/framework/components/chui_inputs/chui_file/styles.css +13 -12
  76. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +61 -36
  77. package/framework/components/chui_inputs/chui_masked/masked.js +39 -28
  78. package/framework/components/chui_inputs/chui_mention/mention.js +77 -30
  79. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +173 -153
  80. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +9 -7
  81. package/framework/components/chui_inputs/chui_number/number.js +58 -41
  82. package/framework/components/chui_inputs/chui_number/styles.css +7 -7
  83. package/framework/components/chui_inputs/chui_otp/otp.js +38 -29
  84. package/framework/components/chui_inputs/chui_password/password.js +58 -36
  85. package/framework/components/chui_inputs/chui_password/styles.css +8 -8
  86. package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
  87. package/framework/components/chui_inputs/chui_radio_button/styles.css +20 -20
  88. package/framework/components/chui_inputs/chui_rating/rating.js +26 -22
  89. package/framework/components/chui_inputs/chui_select_box/select_box.js +102 -78
  90. package/framework/components/chui_inputs/chui_select_box/styles.css +11 -11
  91. package/framework/components/chui_inputs/chui_slider/slider.js +29 -26
  92. package/framework/components/chui_inputs/chui_slider/styles.css +2 -1
  93. package/framework/components/chui_inputs/chui_text/styles.css +8 -8
  94. package/framework/components/chui_inputs/chui_text/text.js +65 -44
  95. package/framework/components/chui_inputs/chui_text_area/styles.css +6 -6
  96. package/framework/components/chui_inputs/chui_text_area/text_area.js +51 -28
  97. package/framework/components/chui_inputs/chui_time/styles.css +5 -3
  98. package/framework/components/chui_inputs/chui_time/time.js +38 -27
  99. package/framework/components/chui_inputs/chui_toggle/styles.css +3 -3
  100. package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
  101. package/framework/components/chui_json_editor/json_editor.js +53 -43
  102. package/framework/components/chui_json_viewer/json_viewer.js +52 -33
  103. package/framework/components/chui_json_viewer/styles.css +3 -2
  104. package/framework/components/chui_kanban/kanban.js +52 -34
  105. package/framework/components/chui_kbd/kbd.js +12 -10
  106. package/framework/components/chui_label/label.js +14 -12
  107. package/framework/components/chui_label/styles.css +2 -2
  108. package/framework/components/chui_link/link.js +27 -20
  109. package/framework/components/chui_list/list.js +31 -27
  110. package/framework/components/chui_list/styles.css +2 -1
  111. package/framework/components/chui_markdown_editor/markdown_editor.js +60 -44
  112. package/framework/components/chui_media/audio.js +326 -227
  113. package/framework/components/chui_media/audio_styles.css +40 -21
  114. package/framework/components/chui_media/image.js +70 -38
  115. package/framework/components/chui_media/image_compare.js +52 -21
  116. package/framework/components/chui_media/image_styles.css +3 -3
  117. package/framework/components/chui_media/video.js +155 -62
  118. package/framework/components/chui_media/video_styles.css +33 -16
  119. package/framework/components/chui_menu_bar/menu_bar.js +26 -24
  120. package/framework/components/chui_menu_bar/styles.css +4 -2
  121. package/framework/components/chui_modal/modal.js +44 -43
  122. package/framework/components/chui_modal/styles.css +3 -2
  123. package/framework/components/chui_notification/notification.js +50 -34
  124. package/framework/components/chui_notification/notification_download.js +31 -25
  125. package/framework/components/chui_notification/notification_download_progress.css +3 -2
  126. package/framework/components/chui_notification/notification_download_progress.js +47 -41
  127. package/framework/components/chui_notification/notification_update.js +23 -16
  128. package/framework/components/chui_notification/status_plate.js +2 -2
  129. package/framework/components/chui_notification/styles_download.css +1 -1
  130. package/framework/components/chui_notification/styles_update.css +1 -1
  131. package/framework/components/chui_org_chart/org_chart.js +74 -35
  132. package/framework/components/chui_pagination/pagination.js +62 -27
  133. package/framework/components/chui_paragraph/paragraph.js +2 -2
  134. package/framework/components/chui_paragraph/styles.css +1 -1
  135. package/framework/components/chui_popover/popover.js +49 -28
  136. package/framework/components/chui_popups/popups.js +137 -108
  137. package/framework/components/chui_popups/styles.css +2 -2
  138. package/framework/components/chui_print_button/print_button.js +33 -23
  139. package/framework/components/chui_progress_bar/progress_bar.js +23 -15
  140. package/framework/components/chui_progress_bar/styles.css +2 -2
  141. package/framework/components/chui_progress_ring/progress_ring.js +17 -15
  142. package/framework/components/chui_qrcode/qrcode.js +75 -31
  143. package/framework/components/chui_query_builder/query_builder.js +216 -123
  144. package/framework/components/chui_radio_group/radio_group.js +36 -26
  145. package/framework/components/chui_radio_group/styles.css +1 -1
  146. package/framework/components/chui_result/result.js +26 -16
  147. package/framework/components/chui_scheduler/scheduler.js +57 -35
  148. package/framework/components/chui_scheduler/styles.css +6 -2
  149. package/framework/components/chui_segmented_control/segmented_control.js +27 -21
  150. package/framework/components/chui_settings/settings.js +122 -48
  151. package/framework/components/chui_shortcut_help/shortcut_help.js +55 -32
  152. package/framework/components/chui_sidebar_nav/sidebar_nav.js +33 -23
  153. package/framework/components/chui_skeleton/skeleton.js +29 -24
  154. package/framework/components/chui_slideshow/slideshow.js +60 -41
  155. package/framework/components/chui_slideshow/styles.css +18 -12
  156. package/framework/components/chui_spinner/spinner.js +8 -8
  157. package/framework/components/chui_spinner/styles.css +0 -1
  158. package/framework/components/chui_split_button/split_button.js +23 -18
  159. package/framework/components/chui_split_button/styles.css +1 -1
  160. package/framework/components/chui_splitter/splitter.js +35 -28
  161. package/framework/components/chui_statistic/statistic.js +65 -38
  162. package/framework/components/chui_status_bar/status_bar.js +11 -9
  163. package/framework/components/chui_stepper/stepper.js +27 -22
  164. package/framework/components/chui_sticky_bar/sticky_bar.js +9 -4
  165. package/framework/components/chui_sticky_bar/styles.css +3 -1
  166. package/framework/components/chui_tabs/chui_tabs.js +28 -22
  167. package/framework/components/chui_tabs/styles.css +3 -3
  168. package/framework/components/chui_text_editor/styles.css +20 -19
  169. package/framework/components/chui_text_editor/text_editor.js +85 -61
  170. package/framework/components/chui_text_editor/text_editor_panel.js +346 -284
  171. package/framework/components/chui_theme_toggle/theme_toggle.js +27 -22
  172. package/framework/components/chui_timeline/timeline.js +14 -12
  173. package/framework/components/chui_toast_queue/toast_queue.js +52 -46
  174. package/framework/components/chui_toolbar/toolbar.js +20 -13
  175. package/framework/components/chui_tooltip/tooltip.js +37 -24
  176. package/framework/components/chui_tour/styles.css +8 -3
  177. package/framework/components/chui_tour/tour.js +61 -27
  178. package/framework/components/chui_transfer/styles.css +2 -1
  179. package/framework/components/chui_transfer/transfer.js +75 -42
  180. package/framework/components/chui_tree_table/tree_table.js +43 -29
  181. package/framework/components/chui_tree_view/styles.css +4 -2
  182. package/framework/components/chui_tree_view/tree_view.js +142 -99
  183. package/framework/components/chui_watermark/watermark.js +24 -16
  184. package/framework/components/chui_webview/styles.css +2 -2
  185. package/framework/components/chui_webview/webview.js +62 -50
  186. package/framework/components/telegram_bot/chui_telegram_bot.js +71 -64
  187. package/framework/modules/chui_a11y/chui_a11y.js +77 -46
  188. package/framework/modules/chui_animations/animations.js +42 -42
  189. package/framework/modules/chui_animations/styles.css +1 -1
  190. package/framework/modules/chui_bridge/preload.js +36 -25
  191. package/framework/modules/chui_functions.js +52 -50
  192. package/framework/modules/chui_highlight/chui_highlight.js +25 -22
  193. package/framework/modules/chui_i18n/chui_i18n.js +9 -7
  194. package/framework/modules/chui_i18n/locales/a11y.js +5 -5
  195. package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
  196. package/framework/modules/chui_i18n/locales/calendar.js +3 -3
  197. package/framework/modules/chui_i18n/locales/common.js +3 -3
  198. package/framework/modules/chui_i18n/locales/data.js +36 -26
  199. package/framework/modules/chui_i18n/locales/editors.js +40 -13
  200. package/framework/modules/chui_i18n/locales/feedback.js +3 -3
  201. package/framework/modules/chui_i18n/locales/forms.js +8 -8
  202. package/framework/modules/chui_i18n/locales/graphics.js +8 -8
  203. package/framework/modules/chui_i18n/locales/media.js +4 -4
  204. package/framework/modules/chui_i18n/locales/navigation.js +8 -8
  205. package/framework/modules/chui_i18n/locales/validate.js +3 -3
  206. package/framework/modules/chui_json/chui_json.js +9 -9
  207. package/framework/modules/chui_layout/chui_layout.js +12 -10
  208. package/framework/modules/chui_logger/chui_logger.js +29 -25
  209. package/framework/modules/chui_page/page.js +33 -27
  210. package/framework/modules/chui_qr/chui_qr.js +158 -67
  211. package/framework/modules/chui_scrollbar/chui_scrollbar.js +35 -24
  212. package/framework/modules/chui_scrollbar/styles.css +3 -1
  213. package/framework/modules/chui_services/chui_channels.js +27 -13
  214. package/framework/modules/chui_services/chui_services.js +39 -31
  215. package/framework/modules/chui_services/desktop.js +32 -31
  216. package/framework/modules/chui_sortable/chui_sortable.js +17 -12
  217. package/framework/modules/chui_validate/chui_validate.js +7 -4
  218. package/framework/tray_bar/chui_menu_items.js +136 -46
  219. package/index.d.ts +4814 -0
  220. package/index.js +385 -292
  221. package/package.json +79 -68
@@ -1,17 +1,17 @@
1
1
  const fs = require("fs");
2
2
  const node_path = require("path");
3
- const {setStyles, formatBytes, optionOr} = require("../../modules/chui_functions");
4
- const {Icon, Icons} = require("../chui_icons/icons");
5
- const {Breadcrumb} = require("../chui_breadcrumb/breadcrumb");
6
- const {RovingKeyboard} = require("../../modules/chui_a11y/chui_a11y");
7
- const {I18n} = require("../../modules/chui_i18n/chui_i18n");
3
+ const { setStyles, formatBytes, optionOr } = require("../../modules/chui_functions");
4
+ const { Icon, Icons } = require("../chui_icons/icons");
5
+ const { Breadcrumb } = require("../chui_breadcrumb/breadcrumb");
6
+ const { RovingKeyboard } = require("../../modules/chui_a11y/chui_a11y");
7
+ const { I18n } = require("../../modules/chui_i18n/chui_i18n");
8
8
 
9
9
  /** Вид записи: папка или файл */
10
- const TYPE = {FOLDER: "folder", FILE: "file"};
10
+ const TYPE = { FOLDER: "folder", FILE: "file" };
11
11
  /** Колонка сортировки */
12
- const SORT = {NAME: "name", SIZE: "size", MODIFIED: "modified"};
12
+ const SORT = { NAME: "name", SIZE: "size", MODIFIED: "modified" };
13
13
  /** Направление сортировки */
14
- const DIRECTION = {ASC: "asc", DESC: "desc"};
14
+ const DIRECTION = { ASC: "asc", DESC: "desc" };
15
15
 
16
16
  /** Значок по расширению: одна таблица на все виды файлов */
17
17
  const ICON_BY_EXTENSION = {
@@ -20,7 +20,7 @@ const ICON_BY_EXTENSION = {
20
20
  audio: "mp3 wav ogg flac m4a aac",
21
21
  video: "mp4 mkv avi webm mov",
22
22
  text: "md txt rtf pdf doc docx odt",
23
- code: "js mjs ts tsx jsx json css html htm php py rb java c cpp h sh sql yml yaml"
23
+ code: "js mjs ts tsx jsx json css html htm php py rb java c cpp h sh sql yml yaml",
24
24
  };
25
25
 
26
26
  /**
@@ -93,7 +93,7 @@ class FileExplorer {
93
93
  #selected = new Set();
94
94
  #anchor = undefined;
95
95
  #filter = "";
96
- #sort = {key: SORT.NAME, direction: DIRECTION.ASC};
96
+ #sort = { key: SORT.NAME, direction: DIRECTION.ASC };
97
97
  #show_hidden = false;
98
98
  #loading = false;
99
99
  #load_token = 0;
@@ -112,26 +112,28 @@ class FileExplorer {
112
112
  #on_select = undefined;
113
113
  #roving = undefined;
114
114
 
115
- constructor(options = {
116
- id: String(),
117
- title: String(),
118
- label: String(),
119
- path: String(),
120
- root: String(),
121
- provider: undefined,
122
- filter: String(),
123
- sort: Object(),
124
- showHidden: Boolean,
125
- selectable: Boolean,
126
- showSize: Boolean,
127
- showModified: Boolean,
128
- height: String(),
129
- emptyText: String(),
130
- errorText: String(),
131
- onOpen: undefined,
132
- onSelect: undefined,
133
- changeListener: undefined
134
- }) {
115
+ constructor(
116
+ options = {
117
+ id: String(),
118
+ title: String(),
119
+ label: String(),
120
+ path: String(),
121
+ root: String(),
122
+ provider: undefined,
123
+ filter: String(),
124
+ sort: Object(),
125
+ showHidden: Boolean,
126
+ selectable: Boolean,
127
+ showSize: Boolean,
128
+ showModified: Boolean,
129
+ height: String(),
130
+ emptyText: String(),
131
+ errorText: String(),
132
+ onOpen: undefined,
133
+ onSelect: undefined,
134
+ changeListener: undefined,
135
+ }
136
+ ) {
135
137
  setStyles(__dirname + "/styles.css", "chUiJS_FileExplorer");
136
138
  FileExplorer.#counter += 1;
137
139
  this.#id = options.id === undefined ? `chui_file_explorer_${FileExplorer.#counter}` : options.id;
@@ -169,7 +171,7 @@ class FileExplorer {
169
171
  this.#status.setAttribute("role", "status");
170
172
  this.#status.setAttribute("aria-live", "polite");
171
173
  this.#buildHead();
172
- this.#path_bar = new Breadcrumb({label: I18n.t("fileExplorer.path")});
174
+ this.#path_bar = new Breadcrumb({ label: I18n.t("fileExplorer.path") });
173
175
  this.#path_bar.set().classList.add("file_explorer_path");
174
176
  this.#root.appendChild(this.#title);
175
177
  this.#root.appendChild(this.#head);
@@ -204,7 +206,7 @@ class FileExplorer {
204
206
  /** Провайдер по умолчанию: настоящая файловая система */
205
207
  static localProvider() {
206
208
  return (path) => {
207
- const list = fs.readdirSync(String(path), {withFileTypes: true});
209
+ const list = fs.readdirSync(String(path), { withFileTypes: true });
208
210
  return list.map((entry) => {
209
211
  const full = node_path.join(String(path), entry.name);
210
212
  let size;
@@ -224,7 +226,7 @@ class FileExplorer {
224
226
  type: entry.isDirectory() ? TYPE.FOLDER : TYPE.FILE,
225
227
  size: size,
226
228
  modified: modified,
227
- hidden: entry.name.startsWith(".")
229
+ hidden: entry.name.startsWith("."),
228
230
  };
229
231
  });
230
232
  };
@@ -282,7 +284,7 @@ class FileExplorer {
282
284
  }
283
285
 
284
286
  getSort() {
285
- return {key: this.#sort.key, direction: this.#sort.direction};
287
+ return { key: this.#sort.key, direction: this.#sort.direction };
286
288
  }
287
289
 
288
290
  isShowHidden() {
@@ -309,12 +311,12 @@ class FileExplorer {
309
311
  getErrorText() {
310
312
  if (this.#error_object === undefined) return "";
311
313
  const message = this.#error_object instanceof Error ? this.#error_object.message : String(this.#error_object);
312
- return I18n.t("fileExplorer.readFailed", {message: message});
314
+ return I18n.t("fileExplorer.readFailed", { message: message });
313
315
  }
314
316
 
315
317
  /** История переходов и место в ней — для кнопок «назад/вперёд» */
316
318
  getHistory() {
317
- return {paths: [...this.#history], index: this.#history_index};
319
+ return { paths: [...this.#history], index: this.#history_index };
318
320
  }
319
321
 
320
322
  canGoBack() {
@@ -407,7 +409,10 @@ class FileExplorer {
407
409
  setShowHidden(shown = Boolean()) {
408
410
  this.#show_hidden = shown === true;
409
411
  this.#hidden.setAttribute("aria-pressed", this.#show_hidden ? "true" : "false");
410
- this.#hidden.setAttribute("aria-label", this.#show_hidden ? I18n.t("fileExplorer.hideHidden") : I18n.t("fileExplorer.showHidden"));
412
+ this.#hidden.setAttribute(
413
+ "aria-label",
414
+ this.#show_hidden ? I18n.t("fileExplorer.hideHidden") : I18n.t("fileExplorer.showHidden")
415
+ );
411
416
  this.#render();
412
417
  this.#announceState();
413
418
  return this;
@@ -416,7 +421,9 @@ class FileExplorer {
416
421
  setSelected(paths = Array(), silent = false) {
417
422
  if (!this.#selectable) return this;
418
423
  const allowed = new Set(this.#entries.map((entry) => entry.path));
419
- this.#selected = new Set((Array.isArray(paths) ? paths : []).map((path) => String(path)).filter((path) => allowed.has(path)));
424
+ this.#selected = new Set(
425
+ (Array.isArray(paths) ? paths : []).map((path) => String(path)).filter((path) => allowed.has(path))
426
+ );
420
427
  this.#anchor = this.#selected.size === 0 ? undefined : [...this.#selected][this.#selected.size - 1];
421
428
  this.#applySelection();
422
429
  if (silent === false) this.#notifySelect();
@@ -431,7 +438,7 @@ class FileExplorer {
431
438
  open(entry = Object()) {
432
439
  if (entry === undefined || entry === null) return this;
433
440
  if (entry.type === TYPE.FOLDER) return this.go(entry.path);
434
- this.#announce(I18n.t("fileExplorer.openedFile", {name: entry.name}));
441
+ this.#announce(I18n.t("fileExplorer.openedFile", { name: entry.name }));
435
442
  if (this.#on_open !== undefined) this.#on_open(Object.assign({}, entry), this);
436
443
  return this;
437
444
  }
@@ -443,13 +450,13 @@ class FileExplorer {
443
450
  }
444
451
 
445
452
  /** Загрузка папки: промис разрешается, когда данные пришли (устаревший ответ отбрасывается) */
446
- async load(path = String(), options = {history: true, keepSelection: false}) {
453
+ async load(path = String(), options = { history: true, keepSelection: false }) {
447
454
  const target = path === undefined || path === null || path === "" ? this.#path : String(path);
448
455
  const token = this.#load_token + 1;
449
456
  this.#load_token = token;
450
457
  this.#loading = true;
451
458
  this.#grid.setAttribute("aria-busy", "true");
452
- this.#status.innerText = I18n.t("fileExplorer.loading", {target: target});
459
+ this.#status.innerText = I18n.t("fileExplorer.loading", { target: target });
453
460
  let list;
454
461
  try {
455
462
  list = await Promise.resolve(this.#provider(target));
@@ -460,7 +467,9 @@ class FileExplorer {
460
467
  this.#error_object = error;
461
468
  this.#path = target;
462
469
  this.#render();
463
- this.#announce(I18n.t("fileExplorer.readFailed", {message: error instanceof Error ? error.message : String(error)}));
470
+ this.#announce(
471
+ I18n.t("fileExplorer.readFailed", { message: error instanceof Error ? error.message : String(error) })
472
+ );
464
473
  return this;
465
474
  }
466
475
  if (token !== this.#load_token) return this;
@@ -481,13 +490,13 @@ class FileExplorer {
481
490
  back() {
482
491
  if (!this.canGoBack()) return this;
483
492
  this.#history_index -= 1;
484
- return this.load(this.#history[this.#history_index], {history: false});
493
+ return this.load(this.#history[this.#history_index], { history: false });
485
494
  }
486
495
 
487
496
  forward() {
488
497
  if (!this.canGoForward()) return this;
489
498
  this.#history_index += 1;
490
- return this.load(this.#history[this.#history_index], {history: false});
499
+ return this.load(this.#history[this.#history_index], { history: false });
491
500
  }
492
501
 
493
502
  /** На уровень выше; выше корня не поднимаемся */
@@ -498,7 +507,7 @@ class FileExplorer {
498
507
 
499
508
  /** Перечитать текущую папку, сохранив выбор */
500
509
  refresh() {
501
- return this.load(this.#path, {history: false, keepSelection: true});
510
+ return this.load(this.#path, { history: false, keepSelection: true });
502
511
  }
503
512
 
504
513
  /** Фокус на запись по пути (или на первую видимую) */
@@ -526,7 +535,8 @@ class FileExplorer {
526
535
  static #normalize(list = Array(), path = String()) {
527
536
  const source = Array.isArray(list) ? list : [];
528
537
  return source.map((item, index) => {
529
- const entry = typeof item === "string" ? {name: item} : (item === null || typeof item !== "object" ? {} : item);
538
+ const entry =
539
+ typeof item === "string" ? { name: item } : item === null || typeof item !== "object" ? {} : item;
530
540
  const name = entry.name === undefined ? String(index) : String(entry.name);
531
541
  return {
532
542
  name: name,
@@ -535,7 +545,7 @@ class FileExplorer {
535
545
  size: entry.size === undefined ? undefined : Number(entry.size),
536
546
  modified: entry.modified === undefined ? undefined : entry.modified,
537
547
  hidden: entry.hidden === undefined ? name.startsWith(".") : entry.hidden === true,
538
- icon: entry.icon
548
+ icon: entry.icon,
539
549
  };
540
550
  });
541
551
  }
@@ -590,7 +600,8 @@ class FileExplorer {
590
600
  #compare(a = Object(), b = Object()) {
591
601
  const direction = this.#sort.direction === DIRECTION.DESC ? -1 : 1;
592
602
  if (a.type !== b.type) return a.type === TYPE.FOLDER ? -1 : 1;
593
- if (this.#sort.key === SORT.NAME) return direction * a.name.localeCompare(b.name, "ru", {numeric: true, sensitivity: "base"});
603
+ if (this.#sort.key === SORT.NAME)
604
+ return direction * a.name.localeCompare(b.name, "ru", { numeric: true, sensitivity: "base" });
594
605
  const value = (entry) => {
595
606
  if (this.#sort.key === SORT.SIZE) return entry.size === undefined ? undefined : Number(entry.size);
596
607
  if (entry.modified === undefined || entry.modified === null) return undefined;
@@ -599,7 +610,8 @@ class FileExplorer {
599
610
  };
600
611
  const left = value(a);
601
612
  const right = value(b);
602
- if (left === undefined && right === undefined) return direction * a.name.localeCompare(b.name, "ru", {numeric: true});
613
+ if (left === undefined && right === undefined)
614
+ return direction * a.name.localeCompare(b.name, "ru", { numeric: true });
603
615
  if (left === undefined) return 1;
604
616
  if (right === undefined) return -1;
605
617
  return direction * (left - right);
@@ -607,16 +619,29 @@ class FileExplorer {
607
619
 
608
620
  #visibleEntries() {
609
621
  const filter = this.#filter.trim().toLowerCase();
610
- const list = this.#entries.filter((entry) => (this.#show_hidden || entry.hidden !== true) &&
611
- (filter === "" || entry.name.toLowerCase().includes(filter)));
622
+ const list = this.#entries.filter(
623
+ (entry) =>
624
+ (this.#show_hidden || entry.hidden !== true) &&
625
+ (filter === "" || entry.name.toLowerCase().includes(filter))
626
+ );
612
627
  return list.sort((a, b) => this.#compare(a, b));
613
628
  }
614
629
 
615
630
  #buildHead() {
616
- this.#actions.appendChild(this.#navButton(this.#back, Icons.NAVIGATION.ARROW_BACK, I18n.t("a11y.previous"), () => this.back()));
617
- this.#actions.appendChild(this.#navButton(this.#forward, Icons.NAVIGATION.ARROW_FORWARD, I18n.t("a11y.next"), () => this.forward()));
618
- this.#actions.appendChild(this.#navButton(this.#up, Icons.NAVIGATION.ARROW_UPWARD, I18n.t("fileExplorer.up"), () => this.up()));
619
- this.#actions.appendChild(this.#navButton(this.#refresh, Icons.NAVIGATION.REFRESH, I18n.t("fileExplorer.refresh"), () => this.refresh()));
631
+ this.#actions.appendChild(
632
+ this.#navButton(this.#back, Icons.NAVIGATION.ARROW_BACK, I18n.t("a11y.previous"), () => this.back())
633
+ );
634
+ this.#actions.appendChild(
635
+ this.#navButton(this.#forward, Icons.NAVIGATION.ARROW_FORWARD, I18n.t("a11y.next"), () => this.forward())
636
+ );
637
+ this.#actions.appendChild(
638
+ this.#navButton(this.#up, Icons.NAVIGATION.ARROW_UPWARD, I18n.t("fileExplorer.up"), () => this.up())
639
+ );
640
+ this.#actions.appendChild(
641
+ this.#navButton(this.#refresh, Icons.NAVIGATION.REFRESH, I18n.t("fileExplorer.refresh"), () =>
642
+ this.refresh()
643
+ )
644
+ );
620
645
  this.#head.appendChild(this.#actions);
621
646
  this.#search.className = "file_explorer_search";
622
647
  this.#search.type = "search";
@@ -645,14 +670,20 @@ class FileExplorer {
645
670
  this.#hidden.className = "file_explorer_hidden";
646
671
  this.#hidden.type = "button";
647
672
  this.#hidden.setAttribute("aria-pressed", this.#show_hidden ? "true" : "false");
648
- this.#hidden.setAttribute("aria-label", this.#show_hidden ? I18n.t("fileExplorer.hideHidden") : I18n.t("fileExplorer.showHidden"));
649
- const glyph = new Icon(this.#show_hidden ? Icons.ACTIONS.VISIBILITY : Icons.ACTIONS.VISIBILITY_OFF, "18px").set();
673
+ this.#hidden.setAttribute(
674
+ "aria-label",
675
+ this.#show_hidden ? I18n.t("fileExplorer.hideHidden") : I18n.t("fileExplorer.showHidden")
676
+ );
677
+ const glyph = new Icon(
678
+ this.#show_hidden ? Icons.ACTIONS.VISIBILITY : Icons.ACTIONS.VISIBILITY_OFF,
679
+ "18px"
680
+ ).set();
650
681
  glyph.setAttribute("aria-hidden", "true");
651
682
  this.#hidden.appendChild(glyph);
652
683
  this.#hidden.addEventListener("click", () => this.setShowHidden(!this.#show_hidden));
653
684
  this.#head.appendChild(this.#hidden);
654
685
  // У панели одна остановка обхода: по кнопкам ходят стрелки/Home/End
655
- this.#roving = new RovingKeyboard(this.#actions, {itemSelector: "button"});
686
+ this.#roving = new RovingKeyboard(this.#actions, { itemSelector: "button" });
656
687
  return this;
657
688
  }
658
689
 
@@ -672,27 +703,40 @@ class FileExplorer {
672
703
  const cell = document.createElement("file_explorer_head_cell");
673
704
  cell.className = "file_explorer_head_cell";
674
705
  cell.setAttribute("role", "columnheader");
675
- cell.setAttribute("aria-sort", this.#sort.key === key
676
- ? (this.#sort.direction === DIRECTION.DESC ? "descending" : "ascending")
677
- : "none");
706
+ cell.setAttribute(
707
+ "aria-sort",
708
+ this.#sort.key === key ? (this.#sort.direction === DIRECTION.DESC ? "descending" : "ascending") : "none"
709
+ );
678
710
  const button = document.createElement("button");
679
711
  button.type = "button";
680
712
  button.className = "file_explorer_sort";
681
- button.setAttribute("aria-label", I18n.t("fileExplorer.sortBy", {title: title}));
713
+ button.setAttribute("aria-label", I18n.t("fileExplorer.sortBy", { title: title }));
682
714
  const text = document.createElement("file_explorer_sort_title");
683
715
  text.innerText = title;
684
716
  button.appendChild(text);
685
717
  if (this.#sort.key === key) {
686
- const glyph = new Icon(this.#sort.direction === DIRECTION.DESC ? Icons.NAVIGATION.ARROW_DOWNWARD : Icons.NAVIGATION.ARROW_UPWARD, "16px").set();
718
+ const glyph = new Icon(
719
+ this.#sort.direction === DIRECTION.DESC
720
+ ? Icons.NAVIGATION.ARROW_DOWNWARD
721
+ : Icons.NAVIGATION.ARROW_UPWARD,
722
+ "16px"
723
+ ).set();
687
724
  glyph.setAttribute("aria-hidden", "true");
688
725
  button.appendChild(glyph);
689
726
  }
690
727
  button.addEventListener("click", () => {
691
728
  // Повторный клик по активной колонке переворачивает порядок: «без сортировки»
692
729
  // у списка файлов смысла не имеет, поэтому цикла из трёх состояний здесь нет
693
- if (this.#sort.key === key) this.setSort(key, this.#sort.direction === DIRECTION.ASC ? DIRECTION.DESC : DIRECTION.ASC);
730
+ if (this.#sort.key === key)
731
+ this.setSort(key, this.#sort.direction === DIRECTION.ASC ? DIRECTION.DESC : DIRECTION.ASC);
694
732
  else this.setSort(key, DIRECTION.ASC);
695
- this.#announce(I18n.t("fileExplorer.sorted", {title: title, direction: this.#sort.direction === DIRECTION.ASC ? I18n.t("data.ascending") : I18n.t("data.descending")}));
733
+ this.#announce(
734
+ I18n.t("fileExplorer.sorted", {
735
+ title: title,
736
+ direction:
737
+ this.#sort.direction === DIRECTION.ASC ? I18n.t("data.ascending") : I18n.t("data.descending"),
738
+ })
739
+ );
696
740
  });
697
741
  cell.appendChild(button);
698
742
  return cell;
@@ -713,9 +757,12 @@ class FileExplorer {
713
757
  return cell;
714
758
  }
715
759
  cell.classList.add("file_explorer_cell_meta");
716
- cell.innerText = key === SORT.SIZE
717
- ? (entry.size === undefined ? "" : formatBytes(entry.size))
718
- : FileExplorer.#dateText(entry.modified);
760
+ cell.innerText =
761
+ key === SORT.SIZE
762
+ ? entry.size === undefined
763
+ ? ""
764
+ : formatBytes(entry.size)
765
+ : FileExplorer.#dateText(entry.modified);
719
766
  return cell;
720
767
  }
721
768
 
@@ -737,13 +784,17 @@ class FileExplorer {
737
784
  #render() {
738
785
  // Строки пересобираются, а фокус живёт на строке: запоминаем её до перерисовки
739
786
  const active = document.activeElement;
740
- const focused = active === null || active === undefined || !this.#grid.contains(active) ? null : active.closest("file_explorer_row");
787
+ const focused =
788
+ active === null || active === undefined || !this.#grid.contains(active)
789
+ ? null
790
+ : active.closest("file_explorer_row");
741
791
  if (focused !== null) this.#focus_path = focused.dataset.path;
742
792
  this.#head_row.innerHTML = "";
743
793
  this.#body.innerHTML = "";
744
794
  this.#head_row.appendChild(this.#sortButton(SORT.NAME, I18n.t("fileExplorer.columnName")));
745
795
  if (this.#show_size) this.#head_row.appendChild(this.#sortButton(SORT.SIZE, I18n.t("fileExplorer.columnSize")));
746
- if (this.#show_modified) this.#head_row.appendChild(this.#sortButton(SORT.MODIFIED, I18n.t("fileExplorer.columnModified")));
796
+ if (this.#show_modified)
797
+ this.#head_row.appendChild(this.#sortButton(SORT.MODIFIED, I18n.t("fileExplorer.columnModified")));
747
798
  // Ширины колонок задаёт компонент: сетка шапки и сетка строк обязаны совпасть,
748
799
  // а какие колонки показаны, знает только он
749
800
  const columns = ["minmax(0, 1fr)"];
@@ -757,7 +808,12 @@ class FileExplorer {
757
808
  this.#empty.innerText = this.isFiltered() ? I18n.t("common.nothingFound") : this.#empty_text;
758
809
  this.#error.hidden = this.#error_object === undefined;
759
810
  this.#error.innerText = this.getErrorText();
760
- this.#grid.setAttribute("aria-label", I18n.t("fileExplorer.gridLabel", {path: this.#path === "" ? I18n.t("fileExplorer.noFolderInline") : this.#path}));
811
+ this.#grid.setAttribute(
812
+ "aria-label",
813
+ I18n.t("fileExplorer.gridLabel", {
814
+ path: this.#path === "" ? I18n.t("fileExplorer.noFolderInline") : this.#path,
815
+ })
816
+ );
761
817
  this.#grid.setAttribute("aria-rowcount", String(visible.length + 1));
762
818
  this.#grid.setAttribute("aria-busy", this.#loading ? "true" : "false");
763
819
  this.#back.disabled = !this.canGoBack();
@@ -772,31 +828,35 @@ class FileExplorer {
772
828
 
773
829
  #renderPath() {
774
830
  const items = this.#pathItems();
775
- this.#path_bar.setItems(items.map((item, index) => (index === items.length - 1
776
- ? {title: item.title}
777
- : {title: item.title, clickEvent: () => this.go(item.path)})));
831
+ this.#path_bar.setItems(
832
+ items.map((item, index) =>
833
+ index === items.length - 1
834
+ ? { title: item.title }
835
+ : { title: item.title, clickEvent: () => this.go(item.path) }
836
+ )
837
+ );
778
838
  return this;
779
839
  }
780
840
 
781
841
  /** Звенья пути: с корнем оставляем только путь от него */
782
842
  #pathItems() {
783
843
  const full = String(this.#path);
784
- if (full === "") return [{title: I18n.t("fileExplorer.noFolder"), path: ""}];
844
+ if (full === "") return [{ title: I18n.t("fileExplorer.noFolder"), path: "" }];
785
845
  const root = this.#root_path === undefined ? undefined : String(this.#root_path).replace(/[\\/]+$/, "");
786
846
  const items = [];
787
- if (full.startsWith("/")) items.push({title: "/", path: "/"});
788
- else if (/^[A-Za-z]:/.test(full)) items.push({title: `${full.slice(0, 2)}/`, path: `${full.slice(0, 2)}/`});
847
+ if (full.startsWith("/")) items.push({ title: "/", path: "/" });
848
+ else if (/^[A-Za-z]:/.test(full)) items.push({ title: `${full.slice(0, 2)}/`, path: `${full.slice(0, 2)}/` });
789
849
  const base = items.length > 0 ? items[0].path : "";
790
850
  const rest = full.slice(base.length).replace(/^[\\/]+/, "");
791
851
  let current = base;
792
852
  for (const part of rest.split(/[\\/]+/).filter((piece) => piece !== "")) {
793
- current = current === "" ? part : (current.endsWith("/") ? `${current}${part}` : `${current}/${part}`);
794
- items.push({title: part, path: current});
853
+ current = current === "" ? part : current.endsWith("/") ? `${current}${part}` : `${current}/${part}`;
854
+ items.push({ title: part, path: current });
795
855
  }
796
- if (items.length === 0) items.push({title: full, path: full});
856
+ if (items.length === 0) items.push({ title: full, path: full });
797
857
  if (root !== undefined && root !== "") {
798
858
  const index = items.findIndex((item) => item.path === root);
799
- if (index > 0) return [{title: items[index].title, path: root}].concat(items.slice(index + 1));
859
+ if (index > 0) return [{ title: items[index].title, path: root }].concat(items.slice(index + 1));
800
860
  }
801
861
  return items;
802
862
  }
@@ -839,7 +899,10 @@ class FileExplorer {
839
899
  }
840
900
 
841
901
  #currentRow(target = undefined) {
842
- const row = target === undefined || target === null || typeof target.closest !== "function" ? null : target.closest("file_explorer_row");
902
+ const row =
903
+ target === undefined || target === null || typeof target.closest !== "function"
904
+ ? null
905
+ : target.closest("file_explorer_row");
843
906
  if (row !== null) return row;
844
907
  return this.#body.querySelector('file_explorer_row[tabindex="0"]');
845
908
  }
@@ -891,7 +954,11 @@ class FileExplorer {
891
954
 
892
955
  #notifySelect() {
893
956
  const entries = this.getSelected();
894
- this.#announce(entries.length === 0 ? I18n.t("fileExplorer.selectionCleared") : I18n.t("fileExplorer.selectedCount", {count: entries.length}));
957
+ this.#announce(
958
+ entries.length === 0
959
+ ? I18n.t("fileExplorer.selectionCleared")
960
+ : I18n.t("fileExplorer.selectedCount", { count: entries.length })
961
+ );
895
962
  for (const listener of [...this.#listeners]) listener(entries, this);
896
963
  if (this.#on_select !== undefined) this.#on_select(entries, this);
897
964
  return this;
@@ -906,10 +973,14 @@ class FileExplorer {
906
973
  const visible = this.#visibleEntries().length;
907
974
  const total = this.#entries.filter((entry) => this.#show_hidden || entry.hidden !== true).length;
908
975
  if (this.isFiltered()) {
909
- this.#status.innerText = visible === 0 ? I18n.t("common.nothingFound") : I18n.t("fileExplorer.foundCount", {found: visible, total: total});
976
+ this.#status.innerText =
977
+ visible === 0
978
+ ? I18n.t("common.nothingFound")
979
+ : I18n.t("fileExplorer.foundCount", { found: visible, total: total });
910
980
  return this;
911
981
  }
912
- this.#status.innerText = visible === 0 ? this.#empty_text : I18n.t("fileExplorer.entriesCount", {count: visible});
982
+ this.#status.innerText =
983
+ visible === 0 ? this.#empty_text : I18n.t("fileExplorer.entriesCount", { count: visible });
913
984
  return this;
914
985
  }
915
986
 
@@ -1034,4 +1105,4 @@ class FileExplorer {
1034
1105
  };
1035
1106
  }
1036
1107
 
1037
- exports.FileExplorer = FileExplorer
1108
+ exports.FileExplorer = FileExplorer;
@@ -108,7 +108,8 @@ chui_file_explorer {
108
108
  height: var(--control_height);
109
109
  margin: 0;
110
110
  /* Место под кнопку очистки, чтобы текст не заезжал под неё */
111
- padding-block: 0 0; padding-inline: 12px 40px;
111
+ padding-block: 0 0;
112
+ padding-inline: 12px 40px;
112
113
  border: 1px solid var(--border_color);
113
114
  border-radius: var(--border_radius);
114
115
  background: var(--element_background);
@@ -1,20 +1,22 @@
1
- const {Button} = require("../chui_button/button");
1
+ const { Button } = require("../chui_button/button");
2
2
 
3
3
  class Form {
4
4
  #id = require("randomstring").generate();
5
- #chui_form_main = document.createElement("chui_form_main")
6
- #form = document.createElement("form")
5
+ #chui_form_main = document.createElement("chui_form_main");
6
+ #form = document.createElement("form");
7
7
  #components = [];
8
8
  #submit_event = undefined;
9
9
  #validate_on_submit = true;
10
- constructor(options = {
11
- action: String(),
12
- method: String(),
13
- components: [],
14
- submitEvent: () => {},
15
- validateOnSubmit: Boolean()
16
- }) {
17
- require('../../modules/chui_functions').setStyles(__dirname + "/styles.css", 'chUiJS_Forms');
10
+ constructor(
11
+ options = {
12
+ action: String(),
13
+ method: String(),
14
+ components: [],
15
+ submitEvent: () => {},
16
+ validateOnSubmit: Boolean(),
17
+ }
18
+ ) {
19
+ require("../../modules/chui_functions").setStyles(__dirname + "/styles.css", "chUiJS_Forms");
18
20
  this.#chui_form_main.id = this.#id;
19
21
  this.#chui_form_main.appendChild(this.#form);
20
22
 
@@ -43,7 +45,7 @@ class Form {
43
45
  }
44
46
  }
45
47
  if (this.#submit_event !== undefined) this.#submit_event(event, this.getValues(), this);
46
- }
48
+ };
47
49
  /** Проверить все поля формы: сами ошибки выставляются в поля */
48
50
  validate() {
49
51
  this.clearErrors();
@@ -54,7 +56,11 @@ class Form {
54
56
  const result = field.validate();
55
57
  if (!result.valid) {
56
58
  if (typeof field.setError === "function") field.setError(result.message);
57
- errors.push({ name: typeof field.getName === "function" ? field.getName() : undefined, message: result.message, rule: result.rule });
59
+ errors.push({
60
+ name: typeof field.getName === "function" ? field.getName() : undefined,
61
+ message: result.message,
62
+ rule: result.rule,
63
+ });
58
64
  if (first === undefined && typeof field.focus === "function") first = field;
59
65
  }
60
66
  }
@@ -111,9 +117,13 @@ class Form {
111
117
  return this;
112
118
  }
113
119
  //addSubmitEvent(listener = () => {}) { this.#form.addEventListener("submit", listener); }
114
- set() { return this.#chui_form_main }
115
- static SubmitButton(title = String()) { return new SubmitButton(title); }
116
- static METHOD = { GET: "GET", POST: "POST" }
120
+ set() {
121
+ return this.#chui_form_main;
122
+ }
123
+ static SubmitButton(title = String()) {
124
+ return new SubmitButton(title);
125
+ }
126
+ static METHOD = { GET: "GET", POST: "POST" };
117
127
  }
118
128
 
119
129
  /**
@@ -127,9 +137,11 @@ class Form {
127
137
  class SubmitButton {
128
138
  #button = undefined;
129
139
  constructor(title = String()) {
130
- this.#button = new Button({title: title});
140
+ this.#button = new Button({ title: title });
141
+ }
142
+ set() {
143
+ return this.#button.set();
131
144
  }
132
- set() { return this.#button.set(); }
133
145
  }
134
146
 
135
- exports.Form = Form
147
+ exports.Form = Form;
@@ -3,4 +3,4 @@ chui_form_main {
3
3
  }
4
4
 
5
5
  /* Своих правил для кнопки отправки нет: `SubmitButton` — это `Button`, у него вид
6
- и состояния из framework/components/chui_button/styles.css */
6
+ и состояния из framework/components/chui_button/styles.css */