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.
- package/CHANGELOG.md +61 -0
- package/README.md +43 -644
- package/framework/appLayout/default/chui_app_layout.js +308 -260
- package/framework/appLayout/default/global_style.css +85 -48
- package/framework/components/chui_accordion/accordion.js +29 -26
- package/framework/components/chui_accordion/styles.css +6 -5
- package/framework/components/chui_action_sheet/action_sheet.js +59 -33
- package/framework/components/chui_action_sheet/styles.css +2 -1
- package/framework/components/chui_affix/affix.js +11 -6
- package/framework/components/chui_alert/alert.js +23 -14
- package/framework/components/chui_avatar/avatar.js +23 -22
- package/framework/components/chui_avatar_group/avatar_group.js +21 -19
- package/framework/components/chui_backtop/backtop.js +35 -19
- package/framework/components/chui_badge/badge.js +15 -13
- package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
- package/framework/components/chui_button/button.js +42 -22
- package/framework/components/chui_button/styles.css +2 -2
- package/framework/components/chui_calendar/calendar.js +12 -10
- package/framework/components/chui_card/card.js +43 -23
- package/framework/components/chui_chat/chat.js +72 -33
- package/framework/components/chui_clipboard_history/clipboard_history.js +30 -21
- package/framework/components/chui_clipboard_history/styles.css +4 -2
- package/framework/components/chui_code/code.js +2 -2
- package/framework/components/chui_code/styles.css +2 -2
- package/framework/components/chui_code_editor/code_editor.js +47 -31
- package/framework/components/chui_code_editor/styles.css +3 -2
- package/framework/components/chui_command_palette/command_palette.js +60 -37
- package/framework/components/chui_console/console.js +5 -5
- package/framework/components/chui_console/styles.css +1 -1
- package/framework/components/chui_content_block/content_block.js +33 -19
- package/framework/components/chui_content_block/styles.css +2 -2
- package/framework/components/chui_context_menu/context_menu.js +9 -4
- package/framework/components/chui_custom_element/custom_element.js +22 -15
- package/framework/components/chui_data_grid/data_grid.js +396 -234
- package/framework/components/chui_data_grid/styles.css +10 -8
- package/framework/components/chui_descriptions/descriptions.js +34 -17
- package/framework/components/chui_details/details.js +32 -26
- package/framework/components/chui_details/styles.css +5 -4
- package/framework/components/chui_diff_viewer/diff_viewer.js +91 -66
- package/framework/components/chui_diff_viewer/styles.css +1 -1
- package/framework/components/chui_divider/divider.js +13 -11
- package/framework/components/chui_drawer/drawer.js +27 -25
- package/framework/components/chui_drop_zone/drop_zone.js +31 -21
- package/framework/components/chui_empty_state/empty_state.js +20 -15
- package/framework/components/chui_fieldset/fieldset.js +37 -20
- package/framework/components/chui_fieldset/styles.css +1 -1
- package/framework/components/chui_file_explorer/file_explorer.js +157 -86
- package/framework/components/chui_file_explorer/styles.css +2 -1
- package/framework/components/chui_form/form.js +31 -19
- package/framework/components/chui_form/styles.css +1 -1
- package/framework/components/chui_gantt/gantt.js +64 -40
- package/framework/components/chui_graphs/graphs.js +301 -200
- package/framework/components/chui_graphs/styles.css +1 -1
- package/framework/components/chui_hero/hero.js +40 -22
- package/framework/components/chui_html_block/html_block.js +6 -6
- package/framework/components/chui_html_block/styles.css +2 -2
- package/framework/components/chui_hx/hx.js +3 -3
- package/framework/components/chui_hx/styles.css +11 -4
- package/framework/components/chui_icons/icons.js +2109 -2109
- package/framework/components/chui_icons/styles.css +2 -2
- package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
- package/framework/components/chui_inputs/chui_check_box/styles.css +18 -18
- package/framework/components/chui_inputs/chui_chips/chips.js +50 -40
- package/framework/components/chui_inputs/chui_chips/styles.css +4 -2
- package/framework/components/chui_inputs/chui_color_picker/color_picker.js +36 -24
- package/framework/components/chui_inputs/chui_combo_box/combo_box.js +100 -82
- package/framework/components/chui_inputs/chui_combo_box/styles.css +14 -12
- package/framework/components/chui_inputs/chui_date/date.js +102 -66
- package/framework/components/chui_inputs/chui_date/styles.css +12 -11
- package/framework/components/chui_inputs/chui_date_range/date_range.js +40 -29
- package/framework/components/chui_inputs/chui_datetime/datetime.js +35 -27
- package/framework/components/chui_inputs/chui_email/email.js +43 -31
- package/framework/components/chui_inputs/chui_email/styles.css +5 -5
- package/framework/components/chui_inputs/chui_file/file.js +68 -41
- package/framework/components/chui_inputs/chui_file/styles.css +13 -12
- package/framework/components/chui_inputs/chui_hotkey/hotkey.js +61 -36
- package/framework/components/chui_inputs/chui_masked/masked.js +39 -28
- package/framework/components/chui_inputs/chui_mention/mention.js +77 -30
- package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +173 -153
- package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +9 -7
- package/framework/components/chui_inputs/chui_number/number.js +58 -41
- package/framework/components/chui_inputs/chui_number/styles.css +7 -7
- package/framework/components/chui_inputs/chui_otp/otp.js +38 -29
- package/framework/components/chui_inputs/chui_password/password.js +58 -36
- package/framework/components/chui_inputs/chui_password/styles.css +8 -8
- package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
- package/framework/components/chui_inputs/chui_radio_button/styles.css +20 -20
- package/framework/components/chui_inputs/chui_rating/rating.js +26 -22
- package/framework/components/chui_inputs/chui_select_box/select_box.js +102 -78
- package/framework/components/chui_inputs/chui_select_box/styles.css +11 -11
- package/framework/components/chui_inputs/chui_slider/slider.js +29 -26
- package/framework/components/chui_inputs/chui_slider/styles.css +2 -1
- package/framework/components/chui_inputs/chui_text/styles.css +8 -8
- package/framework/components/chui_inputs/chui_text/text.js +65 -44
- package/framework/components/chui_inputs/chui_text_area/styles.css +6 -6
- package/framework/components/chui_inputs/chui_text_area/text_area.js +51 -28
- package/framework/components/chui_inputs/chui_time/styles.css +5 -3
- package/framework/components/chui_inputs/chui_time/time.js +38 -27
- package/framework/components/chui_inputs/chui_toggle/styles.css +3 -3
- package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
- package/framework/components/chui_json_editor/json_editor.js +53 -43
- package/framework/components/chui_json_viewer/json_viewer.js +52 -33
- package/framework/components/chui_json_viewer/styles.css +3 -2
- package/framework/components/chui_kanban/kanban.js +52 -34
- package/framework/components/chui_kbd/kbd.js +12 -10
- package/framework/components/chui_label/label.js +14 -12
- package/framework/components/chui_label/styles.css +2 -2
- package/framework/components/chui_link/link.js +27 -20
- package/framework/components/chui_list/list.js +31 -27
- package/framework/components/chui_list/styles.css +2 -1
- package/framework/components/chui_markdown_editor/markdown_editor.js +60 -44
- package/framework/components/chui_media/audio.js +326 -227
- package/framework/components/chui_media/audio_styles.css +40 -21
- package/framework/components/chui_media/image.js +70 -38
- package/framework/components/chui_media/image_compare.js +52 -21
- package/framework/components/chui_media/image_styles.css +3 -3
- package/framework/components/chui_media/video.js +155 -62
- package/framework/components/chui_media/video_styles.css +33 -16
- package/framework/components/chui_menu_bar/menu_bar.js +26 -24
- package/framework/components/chui_menu_bar/styles.css +4 -2
- package/framework/components/chui_modal/modal.js +44 -43
- package/framework/components/chui_modal/styles.css +3 -2
- package/framework/components/chui_notification/notification.js +50 -34
- package/framework/components/chui_notification/notification_download.js +31 -25
- package/framework/components/chui_notification/notification_download_progress.css +3 -2
- package/framework/components/chui_notification/notification_download_progress.js +47 -41
- package/framework/components/chui_notification/notification_update.js +23 -16
- package/framework/components/chui_notification/status_plate.js +2 -2
- package/framework/components/chui_notification/styles_download.css +1 -1
- package/framework/components/chui_notification/styles_update.css +1 -1
- package/framework/components/chui_org_chart/org_chart.js +74 -35
- package/framework/components/chui_pagination/pagination.js +62 -27
- package/framework/components/chui_paragraph/paragraph.js +2 -2
- package/framework/components/chui_paragraph/styles.css +1 -1
- package/framework/components/chui_popover/popover.js +49 -28
- package/framework/components/chui_popups/popups.js +137 -108
- package/framework/components/chui_popups/styles.css +2 -2
- package/framework/components/chui_print_button/print_button.js +33 -23
- package/framework/components/chui_progress_bar/progress_bar.js +23 -15
- package/framework/components/chui_progress_bar/styles.css +2 -2
- package/framework/components/chui_progress_ring/progress_ring.js +17 -15
- package/framework/components/chui_qrcode/qrcode.js +75 -31
- package/framework/components/chui_query_builder/query_builder.js +216 -123
- package/framework/components/chui_radio_group/radio_group.js +36 -26
- package/framework/components/chui_radio_group/styles.css +1 -1
- package/framework/components/chui_result/result.js +26 -16
- package/framework/components/chui_scheduler/scheduler.js +57 -35
- package/framework/components/chui_scheduler/styles.css +6 -2
- package/framework/components/chui_segmented_control/segmented_control.js +27 -21
- package/framework/components/chui_settings/settings.js +122 -48
- package/framework/components/chui_shortcut_help/shortcut_help.js +55 -32
- package/framework/components/chui_sidebar_nav/sidebar_nav.js +33 -23
- package/framework/components/chui_skeleton/skeleton.js +29 -24
- package/framework/components/chui_slideshow/slideshow.js +60 -41
- package/framework/components/chui_slideshow/styles.css +18 -12
- package/framework/components/chui_spinner/spinner.js +8 -8
- package/framework/components/chui_spinner/styles.css +0 -1
- package/framework/components/chui_split_button/split_button.js +23 -18
- package/framework/components/chui_split_button/styles.css +1 -1
- package/framework/components/chui_splitter/splitter.js +35 -28
- package/framework/components/chui_statistic/statistic.js +65 -38
- package/framework/components/chui_status_bar/status_bar.js +11 -9
- package/framework/components/chui_stepper/stepper.js +27 -22
- package/framework/components/chui_sticky_bar/sticky_bar.js +9 -4
- package/framework/components/chui_sticky_bar/styles.css +3 -1
- package/framework/components/chui_tabs/chui_tabs.js +28 -22
- package/framework/components/chui_tabs/styles.css +3 -3
- package/framework/components/chui_text_editor/styles.css +20 -19
- package/framework/components/chui_text_editor/text_editor.js +85 -61
- package/framework/components/chui_text_editor/text_editor_panel.js +346 -284
- package/framework/components/chui_theme_toggle/theme_toggle.js +27 -22
- package/framework/components/chui_timeline/timeline.js +14 -12
- package/framework/components/chui_toast_queue/toast_queue.js +52 -46
- package/framework/components/chui_toolbar/toolbar.js +20 -13
- package/framework/components/chui_tooltip/tooltip.js +37 -24
- package/framework/components/chui_tour/styles.css +8 -3
- package/framework/components/chui_tour/tour.js +61 -27
- package/framework/components/chui_transfer/styles.css +2 -1
- package/framework/components/chui_transfer/transfer.js +75 -42
- package/framework/components/chui_tree_table/tree_table.js +43 -29
- package/framework/components/chui_tree_view/styles.css +4 -2
- package/framework/components/chui_tree_view/tree_view.js +142 -99
- package/framework/components/chui_watermark/watermark.js +24 -16
- package/framework/components/chui_webview/styles.css +2 -2
- package/framework/components/chui_webview/webview.js +62 -50
- package/framework/components/telegram_bot/chui_telegram_bot.js +71 -64
- package/framework/modules/chui_a11y/chui_a11y.js +77 -46
- package/framework/modules/chui_animations/animations.js +42 -42
- package/framework/modules/chui_animations/styles.css +1 -1
- package/framework/modules/chui_bridge/preload.js +36 -25
- package/framework/modules/chui_functions.js +52 -50
- package/framework/modules/chui_highlight/chui_highlight.js +25 -22
- package/framework/modules/chui_i18n/chui_i18n.js +9 -7
- package/framework/modules/chui_i18n/locales/a11y.js +5 -5
- package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
- package/framework/modules/chui_i18n/locales/calendar.js +3 -3
- package/framework/modules/chui_i18n/locales/common.js +3 -3
- package/framework/modules/chui_i18n/locales/data.js +36 -26
- package/framework/modules/chui_i18n/locales/editors.js +40 -13
- package/framework/modules/chui_i18n/locales/feedback.js +3 -3
- package/framework/modules/chui_i18n/locales/forms.js +8 -8
- package/framework/modules/chui_i18n/locales/graphics.js +8 -8
- package/framework/modules/chui_i18n/locales/media.js +4 -4
- package/framework/modules/chui_i18n/locales/navigation.js +8 -8
- package/framework/modules/chui_i18n/locales/validate.js +3 -3
- package/framework/modules/chui_json/chui_json.js +9 -9
- package/framework/modules/chui_layout/chui_layout.js +12 -10
- package/framework/modules/chui_logger/chui_logger.js +29 -25
- package/framework/modules/chui_page/page.js +33 -27
- package/framework/modules/chui_qr/chui_qr.js +158 -67
- package/framework/modules/chui_scrollbar/chui_scrollbar.js +35 -24
- package/framework/modules/chui_scrollbar/styles.css +3 -1
- package/framework/modules/chui_services/chui_channels.js +27 -13
- package/framework/modules/chui_services/chui_services.js +39 -31
- package/framework/modules/chui_services/desktop.js +32 -31
- package/framework/modules/chui_sortable/chui_sortable.js +17 -12
- package/framework/modules/chui_validate/chui_validate.js +7 -4
- package/framework/tray_bar/chui_menu_items.js +136 -46
- package/index.d.ts +4814 -0
- package/index.js +385 -292
- 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(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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)
|
|
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)
|
|
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(
|
|
611
|
-
(
|
|
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(
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
this.#actions.appendChild(
|
|
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(
|
|
649
|
-
|
|
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(
|
|
676
|
-
|
|
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(
|
|
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)
|
|
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(
|
|
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 =
|
|
717
|
-
|
|
718
|
-
|
|
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 =
|
|
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)
|
|
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(
|
|
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(
|
|
776
|
-
|
|
777
|
-
|
|
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 :
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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;
|
|
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(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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({
|
|
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() {
|
|
115
|
-
|
|
116
|
-
|
|
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;
|