chuijs 4.0.1 → 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 +113 -0
- package/README.md +43 -632
- package/framework/appLayout/default/chui_app_layout.js +314 -273
- package/framework/appLayout/default/global_style.css +93 -53
- 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 +56 -26
- 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_page/styles.css +3 -26
- 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 +76 -11
- package/framework/modules/chui_services/chui_services.js +39 -31
- package/framework/modules/chui_services/desktop.js +149 -30
- 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 +449 -334
- package/package.json +79 -68
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const {setStyles} = require("../../modules/chui_functions");
|
|
2
|
-
const {A11Y_FOCUSABLE_SELECTOR} = require("../../modules/chui_a11y/chui_a11y");
|
|
3
|
-
const {store: shared_store} = require("../../modules/chui_store/chui_store");
|
|
4
|
-
const {ThemeToggle} = require("../chui_theme_toggle/theme_toggle");
|
|
5
|
-
const {Toggle} = require("../chui_inputs/chui_toggle/toggle");
|
|
6
|
-
const {I18n} = require("../../modules/chui_i18n/chui_i18n");
|
|
1
|
+
const { setStyles } = require("../../modules/chui_functions");
|
|
2
|
+
const { A11Y_FOCUSABLE_SELECTOR } = require("../../modules/chui_a11y/chui_a11y");
|
|
3
|
+
const { store: shared_store } = require("../../modules/chui_store/chui_store");
|
|
4
|
+
const { ThemeToggle } = require("../chui_theme_toggle/theme_toggle");
|
|
5
|
+
const { Toggle } = require("../chui_inputs/chui_toggle/toggle");
|
|
6
|
+
const { I18n } = require("../../modules/chui_i18n/chui_i18n");
|
|
7
7
|
|
|
8
8
|
/** Заполнено ли текстовое поле: пустая строка равнозначна отсутствию */
|
|
9
9
|
const hasText = (value) => value !== undefined && value !== null && String(value).trim() !== "";
|
|
@@ -81,15 +81,17 @@ class Settings {
|
|
|
81
81
|
/** Последние известные значения строк: расхождение со снимком и есть правка пользователя */
|
|
82
82
|
#seen = new Map();
|
|
83
83
|
|
|
84
|
-
constructor(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
84
|
+
constructor(
|
|
85
|
+
options = {
|
|
86
|
+
id: String(),
|
|
87
|
+
title: String(),
|
|
88
|
+
description: String(),
|
|
89
|
+
sections: [],
|
|
90
|
+
store: undefined,
|
|
91
|
+
storeKey: String(),
|
|
92
|
+
onChange: undefined,
|
|
93
|
+
}
|
|
94
|
+
) {
|
|
93
95
|
setStyles(__dirname + "/styles.css", "chUiJS_Settings");
|
|
94
96
|
Settings.#counter += 1;
|
|
95
97
|
this.#id = options.id === undefined ? `chui_settings_${Settings.#counter}` : options.id;
|
|
@@ -128,7 +130,13 @@ class Settings {
|
|
|
128
130
|
|
|
129
131
|
/** Строки в порядке добавления: `{title, name, node, control, disabled}` */
|
|
130
132
|
getControls() {
|
|
131
|
-
return this.#rows.map((row) => ({
|
|
133
|
+
return this.#rows.map((row) => ({
|
|
134
|
+
title: row.title,
|
|
135
|
+
name: row.name,
|
|
136
|
+
node: row.node,
|
|
137
|
+
control: row.control,
|
|
138
|
+
disabled: row.disabled,
|
|
139
|
+
}));
|
|
132
140
|
}
|
|
133
141
|
|
|
134
142
|
/** Контрол строки: адрес — описание из `Settings.Row(...)`, название или имя */
|
|
@@ -252,13 +260,15 @@ class Settings {
|
|
|
252
260
|
* действие, а не значение) ничего не меняет и потому ничего не сообщает.
|
|
253
261
|
*/
|
|
254
262
|
#onUserEdit = (event) => {
|
|
255
|
-
if (event.type === "click" && event.target instanceof Element && event.target.closest("button") !== null)
|
|
256
|
-
|
|
263
|
+
if (event.type === "click" && event.target instanceof Element && event.target.closest("button") !== null)
|
|
264
|
+
return;
|
|
265
|
+
if (this.#store_key === undefined && this.#change_listeners.length === 0 && this.#on_change === undefined)
|
|
266
|
+
return;
|
|
257
267
|
const changed = this.#changedRows();
|
|
258
268
|
if (changed.length === 0) return;
|
|
259
269
|
if (this.#store_key !== undefined) this.save();
|
|
260
270
|
for (const record of changed) this.#emitChange(record);
|
|
261
|
-
}
|
|
271
|
+
};
|
|
262
272
|
|
|
263
273
|
/**
|
|
264
274
|
* Строки, значение которых разошлось со снимком; снимок тут же обновляется, поэтому одна и та же
|
|
@@ -284,7 +294,7 @@ class Settings {
|
|
|
284
294
|
section: record.section,
|
|
285
295
|
title: record.title,
|
|
286
296
|
name: record.name,
|
|
287
|
-
value: this.#readValue(record.control)
|
|
297
|
+
value: this.#readValue(record.control),
|
|
288
298
|
};
|
|
289
299
|
for (const listener of [...this.#change_listeners]) listener(change, this);
|
|
290
300
|
if (this.#on_change !== undefined) this.#on_change(change, this);
|
|
@@ -337,7 +347,8 @@ class Settings {
|
|
|
337
347
|
node.appendChild(head);
|
|
338
348
|
}
|
|
339
349
|
const rows = document.createElement("settings_rows");
|
|
340
|
-
for (const row of section.rows === undefined ? [] : section.rows)
|
|
350
|
+
for (const row of section.rows === undefined ? [] : section.rows)
|
|
351
|
+
rows.appendChild(this.#buildRow(row, section));
|
|
341
352
|
node.appendChild(rows);
|
|
342
353
|
return node;
|
|
343
354
|
}
|
|
@@ -352,7 +363,8 @@ class Settings {
|
|
|
352
363
|
node.classList.toggle("settings_row_stretch", row.stretch === true);
|
|
353
364
|
const description_id = solo ? undefined : this.#buildRowText(row, node);
|
|
354
365
|
const holder = document.createElement("settings_row_control");
|
|
355
|
-
const control =
|
|
366
|
+
const control =
|
|
367
|
+
row.control === undefined ? undefined : row.control instanceof Element ? row.control : row.control.set();
|
|
356
368
|
if (control !== undefined) {
|
|
357
369
|
holder.appendChild(control);
|
|
358
370
|
this.#applyControlA11y(control, titled ? String(row.title) : String(), description_id);
|
|
@@ -364,16 +376,17 @@ class Settings {
|
|
|
364
376
|
section: section,
|
|
365
377
|
title: titled ? String(row.title) : String(),
|
|
366
378
|
// Ключ строки: имя постоянно, а название видно пользователю и меняется при переименовании
|
|
367
|
-
name: named ? String(row.name) :
|
|
379
|
+
name: named ? String(row.name) : titled ? String(row.title) : String(),
|
|
368
380
|
node: node,
|
|
369
381
|
holder: holder,
|
|
370
382
|
control: row.control,
|
|
371
383
|
disabled: false,
|
|
372
|
-
natives: []
|
|
384
|
+
natives: [],
|
|
373
385
|
};
|
|
374
386
|
// Запрет панель ставит и полям готового узла, поэтому их исходное состояние запоминаем заранее —
|
|
375
387
|
// иначе включение вернуло бы строку в другое состояние, чем было до выключения
|
|
376
|
-
for (const native of holder.querySelectorAll(Settings.#NATIVE_CONTROLS))
|
|
388
|
+
for (const native of holder.querySelectorAll(Settings.#NATIVE_CONTROLS))
|
|
389
|
+
record.natives.push({ node: native, disabled: native.disabled });
|
|
377
390
|
this.#rows.push(record);
|
|
378
391
|
if (row.disabled === true) this.#setRowDisabled(record, true);
|
|
379
392
|
return node;
|
|
@@ -419,15 +432,21 @@ class Settings {
|
|
|
419
432
|
/** Строка по описанию из `Settings.Row(...)`, названию или имени (у строки-контрола их может и не быть) */
|
|
420
433
|
#findRow(row_or_title = undefined) {
|
|
421
434
|
if (row_or_title === undefined || row_or_title === null) return undefined;
|
|
422
|
-
return this.#rows.find(
|
|
423
|
-
|
|
424
|
-
|
|
435
|
+
return this.#rows.find(
|
|
436
|
+
(row) =>
|
|
437
|
+
row.row === row_or_title ||
|
|
438
|
+
(row.title.length > 0 && row.title === row_or_title) ||
|
|
439
|
+
(row.name.length > 0 && row.name === row_or_title)
|
|
440
|
+
);
|
|
425
441
|
}
|
|
426
442
|
|
|
427
443
|
/** Раздел по описанию из `Settings.Section(...)` или по заголовку (у раздела без заголовка — только описание) */
|
|
428
444
|
#findSection(section_or_title = undefined) {
|
|
429
445
|
if (section_or_title === undefined || section_or_title === null) return undefined;
|
|
430
|
-
return this.#sections.find(
|
|
446
|
+
return this.#sections.find(
|
|
447
|
+
(section) =>
|
|
448
|
+
section === section_or_title || (hasText(section.title) && String(section.title) === section_or_title)
|
|
449
|
+
);
|
|
431
450
|
}
|
|
432
451
|
|
|
433
452
|
/** Карта «ключ — значение» по отобранным строкам; строка без имени и названия ключа дать не может */
|
|
@@ -459,18 +478,22 @@ class Settings {
|
|
|
459
478
|
* выбранные значения (свой `value` вернул бы только первый пункт).
|
|
460
479
|
*/
|
|
461
480
|
#readValue(control = undefined) {
|
|
462
|
-
if (control !== undefined && control !== null && typeof control.getValue === "function")
|
|
481
|
+
if (control !== undefined && control !== null && typeof control.getValue === "function")
|
|
482
|
+
return control.getValue();
|
|
463
483
|
const field = Settings.#valueField(control);
|
|
464
484
|
if (field === undefined) return undefined;
|
|
465
485
|
if (field.type === "checkbox" || field.type === "radio") return field.checked;
|
|
466
|
-
if (field.tagName === "SELECT" && field.multiple === true)
|
|
486
|
+
if (field.tagName === "SELECT" && field.multiple === true)
|
|
487
|
+
return Array.from(field.selectedOptions, (option) => option.value);
|
|
467
488
|
return field.value;
|
|
468
489
|
}
|
|
469
490
|
|
|
470
491
|
/** Поле готового узла, с которого панель читает значение */
|
|
471
492
|
static #valueField(control = undefined) {
|
|
472
493
|
if (!(control instanceof Element)) return undefined;
|
|
473
|
-
const field = control.matches(Settings.#NATIVE_VALUES)
|
|
494
|
+
const field = control.matches(Settings.#NATIVE_VALUES)
|
|
495
|
+
? control
|
|
496
|
+
: control.querySelector(Settings.#NATIVE_VALUES);
|
|
474
497
|
return field === null ? undefined : field;
|
|
475
498
|
}
|
|
476
499
|
|
|
@@ -517,46 +540,97 @@ class Settings {
|
|
|
517
540
|
*/
|
|
518
541
|
#applyControlA11y(control = new HTMLElement(), label = String(), description_id = undefined) {
|
|
519
542
|
const role = control.getAttribute("role");
|
|
520
|
-
const target =
|
|
521
|
-
|
|
522
|
-
|
|
543
|
+
const target =
|
|
544
|
+
role === null || role === "presentation"
|
|
545
|
+
? control.matches(Settings.#FOCUSABLE)
|
|
546
|
+
? control
|
|
547
|
+
: control.querySelector(Settings.#FOCUSABLE)
|
|
548
|
+
: control;
|
|
523
549
|
if (target === null) return;
|
|
524
550
|
if (description_id !== undefined) target.setAttribute("aria-describedby", description_id);
|
|
525
551
|
if (label.length === 0) return;
|
|
526
552
|
if (target.getAttribute("aria-label") !== null) return;
|
|
527
553
|
const wrapper = target.closest("label");
|
|
528
|
-
const labelled =
|
|
529
|
-
|
|
554
|
+
const labelled =
|
|
555
|
+
(wrapper !== null && wrapper.innerText.trim().length > 0) ||
|
|
556
|
+
(target.id !== "" && control.querySelector(`label[for="${target.id}"]`) !== null);
|
|
530
557
|
if (!labelled) target.setAttribute("aria-label", label);
|
|
531
558
|
}
|
|
532
559
|
|
|
533
|
-
static Section(options = {title: String(), description: String(), rows: []}) {
|
|
534
|
-
return {title: options.title, description: options.description, rows: options.rows};
|
|
560
|
+
static Section(options = { title: String(), description: String(), rows: [] }) {
|
|
561
|
+
return { title: options.title, description: options.description, rows: options.rows };
|
|
535
562
|
}
|
|
536
563
|
|
|
537
|
-
static Row(
|
|
538
|
-
|
|
564
|
+
static Row(
|
|
565
|
+
options = {
|
|
566
|
+
title: String(),
|
|
567
|
+
description: String(),
|
|
568
|
+
name: String(),
|
|
569
|
+
control: undefined,
|
|
570
|
+
disabled: Boolean(),
|
|
571
|
+
stretch: Boolean(),
|
|
572
|
+
}
|
|
573
|
+
) {
|
|
574
|
+
return {
|
|
575
|
+
title: options.title,
|
|
576
|
+
description: options.description,
|
|
577
|
+
name: options.name,
|
|
578
|
+
control: options.control,
|
|
579
|
+
disabled: options.disabled === true,
|
|
580
|
+
stretch: options.stretch === true,
|
|
581
|
+
};
|
|
539
582
|
}
|
|
540
583
|
|
|
541
584
|
/** Строка с переключателем темы: `control` — сам `ThemeToggle` */
|
|
542
|
-
static ThemeRow(
|
|
585
|
+
static ThemeRow(
|
|
586
|
+
options = {
|
|
587
|
+
title: I18n.t("graphics.settingsTheme"),
|
|
588
|
+
description: String(),
|
|
589
|
+
name: String(),
|
|
590
|
+
modes: [],
|
|
591
|
+
labels: {},
|
|
592
|
+
onChange: undefined,
|
|
593
|
+
disabled: Boolean(),
|
|
594
|
+
}
|
|
595
|
+
) {
|
|
543
596
|
const toggle = new ThemeToggle({
|
|
544
597
|
modes: options.modes,
|
|
545
598
|
labels: options.labels,
|
|
546
599
|
label: options.title === undefined ? I18n.t("graphics.settingsAppearance") : options.title,
|
|
547
|
-
onChange: options.onChange
|
|
600
|
+
onChange: options.onChange,
|
|
601
|
+
});
|
|
602
|
+
return Settings.Row({
|
|
603
|
+
title: options.title === undefined ? I18n.t("graphics.settingsTheme") : options.title,
|
|
604
|
+
description: options.description,
|
|
605
|
+
name: options.name,
|
|
606
|
+
control: toggle,
|
|
607
|
+
disabled: options.disabled,
|
|
548
608
|
});
|
|
549
|
-
return Settings.Row({title: options.title === undefined ? I18n.t("graphics.settingsTheme") : options.title, description: options.description, name: options.name, control: toggle, disabled: options.disabled});
|
|
550
609
|
}
|
|
551
610
|
|
|
552
611
|
/** Строка с флажком: `control` — сам `Toggle` */
|
|
553
|
-
static ToggleRow(
|
|
612
|
+
static ToggleRow(
|
|
613
|
+
options = {
|
|
614
|
+
title: String(),
|
|
615
|
+
description: String(),
|
|
616
|
+
name: String(),
|
|
617
|
+
value: Boolean(),
|
|
618
|
+
onChange: undefined,
|
|
619
|
+
disabled: Boolean(),
|
|
620
|
+
}
|
|
621
|
+
) {
|
|
554
622
|
// Подпись строки сразу уходит в сам переключатель: вне Settings он остаётся без имени
|
|
555
|
-
const toggle = new Toggle({label: options.title});
|
|
623
|
+
const toggle = new Toggle({ label: options.title });
|
|
556
624
|
if (options.value !== undefined) toggle.setValue(options.value === true);
|
|
557
625
|
if (options.onChange !== undefined) toggle.addChangeListener(options.onChange);
|
|
558
|
-
return Settings.Row({
|
|
626
|
+
return Settings.Row({
|
|
627
|
+
title: options.title,
|
|
628
|
+
description: options.description,
|
|
629
|
+
name: options.name,
|
|
630
|
+
control: toggle,
|
|
631
|
+
disabled: options.disabled,
|
|
632
|
+
});
|
|
559
633
|
}
|
|
560
634
|
}
|
|
561
635
|
|
|
562
|
-
exports.Settings = Settings
|
|
636
|
+
exports.Settings = Settings;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const {setStyles, optionOr} = require(
|
|
2
|
-
const {TextInput} = require(
|
|
3
|
-
const {Kbd} = require(
|
|
4
|
-
const {I18n} = require(
|
|
1
|
+
const { setStyles, optionOr } = require("../../modules/chui_functions");
|
|
2
|
+
const { TextInput } = require("../chui_inputs/chui_text/text");
|
|
3
|
+
const { Kbd } = require("../chui_kbd/kbd");
|
|
4
|
+
const { I18n } = require("../../modules/chui_i18n/chui_i18n");
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Шпаргалка горячих клавиш: сочетания с пояснениями, разложенные по группам.
|
|
@@ -59,11 +59,20 @@ class ShortcutHelp {
|
|
|
59
59
|
#empty_text = undefined;
|
|
60
60
|
#kbd_size = Kbd.SIZE.DEFAULT;
|
|
61
61
|
|
|
62
|
-
constructor(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
constructor(
|
|
63
|
+
options = {
|
|
64
|
+
id: String(),
|
|
65
|
+
title: undefined,
|
|
66
|
+
groups: [],
|
|
67
|
+
items: [],
|
|
68
|
+
columns: Number(),
|
|
69
|
+
searchable: Boolean(),
|
|
70
|
+
searchPlaceholder: String(),
|
|
71
|
+
emptyText: String(),
|
|
72
|
+
label: String(),
|
|
73
|
+
kbdSize: String(),
|
|
74
|
+
}
|
|
75
|
+
) {
|
|
67
76
|
setStyles(__dirname + "/styles.css", "chUiJS_ShortcutHelp");
|
|
68
77
|
ShortcutHelp.#counter += 1;
|
|
69
78
|
this.#id = optionOr(options.id, `chui_shortcut_help_${ShortcutHelp.#counter}`);
|
|
@@ -110,7 +119,11 @@ class ShortcutHelp {
|
|
|
110
119
|
getGroups() {
|
|
111
120
|
return this.#source.map((group) => ({
|
|
112
121
|
title: group.title,
|
|
113
|
-
items: group.items.map((item) => ({
|
|
122
|
+
items: group.items.map((item) => ({
|
|
123
|
+
keys: [...item.keys],
|
|
124
|
+
description: item.description,
|
|
125
|
+
label: item.label,
|
|
126
|
+
})),
|
|
114
127
|
}));
|
|
115
128
|
}
|
|
116
129
|
|
|
@@ -129,7 +142,10 @@ class ShortcutHelp {
|
|
|
129
142
|
|
|
130
143
|
/** Сколько строк видно с учётом фильтра */
|
|
131
144
|
getVisibleCount() {
|
|
132
|
-
return this.#groups.reduce(
|
|
145
|
+
return this.#groups.reduce(
|
|
146
|
+
(sum, group) => sum + group.rows.filter((row) => row.node.hidden !== true).length,
|
|
147
|
+
0
|
|
148
|
+
);
|
|
133
149
|
}
|
|
134
150
|
|
|
135
151
|
// SET
|
|
@@ -143,7 +159,9 @@ class ShortcutHelp {
|
|
|
143
159
|
setTitle(text = undefined) {
|
|
144
160
|
this.#title_hidden = text === null;
|
|
145
161
|
this.#title_value = typeof text === "string" && text !== "" ? text : undefined;
|
|
146
|
-
this.#title.innerText = this.#title_hidden
|
|
162
|
+
this.#title.innerText = this.#title_hidden
|
|
163
|
+
? ""
|
|
164
|
+
: optionOr(this.#title_value, I18n.t("navigation.shortcutHelp"));
|
|
147
165
|
this.#title.hidden = this.#title_hidden;
|
|
148
166
|
this.#syncAria();
|
|
149
167
|
return this;
|
|
@@ -172,12 +190,15 @@ class ShortcutHelp {
|
|
|
172
190
|
placeholder: optionOr(this.#placeholder, I18n.t("navigation.shortcutHelpSearch")),
|
|
173
191
|
width: "100%",
|
|
174
192
|
// Слушатель обновляет и строки, и объявление найденного числа
|
|
175
|
-
inputListener: () => this.#syncSearch()
|
|
193
|
+
inputListener: () => this.#syncSearch(),
|
|
176
194
|
});
|
|
177
195
|
// Видимой подписи у поля нет, а пл҃ейсхолдер — не имя: имя ставим явно
|
|
178
196
|
const search_field = this.#input.set().querySelector("input");
|
|
179
197
|
if (search_field !== null) {
|
|
180
|
-
search_field.setAttribute(
|
|
198
|
+
search_field.setAttribute(
|
|
199
|
+
"aria-label",
|
|
200
|
+
optionOr(this.#placeholder, I18n.t("navigation.shortcutHelpSearch"))
|
|
201
|
+
);
|
|
181
202
|
}
|
|
182
203
|
this.#search.appendChild(this.#input.set());
|
|
183
204
|
}
|
|
@@ -189,7 +210,7 @@ class ShortcutHelp {
|
|
|
189
210
|
|
|
190
211
|
/** Заменить содержимое целиком */
|
|
191
212
|
setGroups(groups = []) {
|
|
192
|
-
this.#source = ShortcutHelp.#normalizeSource({groups: groups});
|
|
213
|
+
this.#source = ShortcutHelp.#normalizeSource({ groups: groups });
|
|
193
214
|
this.#render();
|
|
194
215
|
return this;
|
|
195
216
|
}
|
|
@@ -197,7 +218,7 @@ class ShortcutHelp {
|
|
|
197
218
|
/** Добавить группу: `add({title: 'Правка', items: [...]})` */
|
|
198
219
|
addGroup(group = undefined) {
|
|
199
220
|
if (group === undefined || group === null) return this;
|
|
200
|
-
this.#source = ShortcutHelp.#normalizeSource({groups: [...this.#source, group]});
|
|
221
|
+
this.#source = ShortcutHelp.#normalizeSource({ groups: [...this.#source, group] });
|
|
201
222
|
this.#render();
|
|
202
223
|
return this;
|
|
203
224
|
}
|
|
@@ -217,27 +238,30 @@ class ShortcutHelp {
|
|
|
217
238
|
/** `groups` плюс короткая форма `items` (одна группа без заголовка) */
|
|
218
239
|
static #normalizeSource(options = {}) {
|
|
219
240
|
const groups = [];
|
|
220
|
-
const items = (options.items === undefined ? [] : options.items).map((item) =>
|
|
221
|
-
|
|
241
|
+
const items = (options.items === undefined ? [] : options.items).map((item) =>
|
|
242
|
+
ShortcutHelp.#normalizeItem(item)
|
|
243
|
+
);
|
|
244
|
+
if (items.length > 0) groups.push({ title: "", items: items });
|
|
222
245
|
for (const group of options.groups === undefined ? [] : options.groups) {
|
|
223
246
|
groups.push({
|
|
224
247
|
title: group.title === undefined ? "" : String(group.title),
|
|
225
|
-
items: (group.items === undefined ? [] : group.items).map((item) => ShortcutHelp.#normalizeItem(item))
|
|
248
|
+
items: (group.items === undefined ? [] : group.items).map((item) => ShortcutHelp.#normalizeItem(item)),
|
|
226
249
|
});
|
|
227
250
|
}
|
|
228
251
|
return groups;
|
|
229
252
|
}
|
|
230
253
|
|
|
231
254
|
static #normalizeItem(item = {}) {
|
|
232
|
-
const keys =
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
.
|
|
236
|
-
|
|
255
|
+
const keys =
|
|
256
|
+
item.keys === undefined || item.keys === null
|
|
257
|
+
? []
|
|
258
|
+
: (Array.isArray(item.keys) ? item.keys : String(item.keys).split("+"))
|
|
259
|
+
.map((key) => String(key).trim())
|
|
260
|
+
.filter((key) => key.length > 0);
|
|
237
261
|
return {
|
|
238
262
|
keys: keys,
|
|
239
263
|
description: item.description === undefined ? "" : String(item.description),
|
|
240
|
-
label: item.label
|
|
264
|
+
label: item.label,
|
|
241
265
|
};
|
|
242
266
|
}
|
|
243
267
|
|
|
@@ -270,7 +294,7 @@ class ShortcutHelp {
|
|
|
270
294
|
if (item.keys.length > 0) {
|
|
271
295
|
const keys = document.createElement("shortcut_help_keys");
|
|
272
296
|
// Сочетание рисует Kbd: клавиша — настоящий <kbd>, значковым нужен label
|
|
273
|
-
keys.appendChild(new Kbd({keys: item.keys, size: this.#kbd_size, label: item.label}).set());
|
|
297
|
+
keys.appendChild(new Kbd({ keys: item.keys, size: this.#kbd_size, label: item.label }).set());
|
|
274
298
|
line.appendChild(keys);
|
|
275
299
|
}
|
|
276
300
|
const text = document.createElement("shortcut_help_text");
|
|
@@ -278,11 +302,11 @@ class ShortcutHelp {
|
|
|
278
302
|
line.appendChild(text);
|
|
279
303
|
row.appendChild(line);
|
|
280
304
|
list.appendChild(row);
|
|
281
|
-
rows.push({node: row, search: `${item.description} ${item.keys.join(" ")}`.toLowerCase()});
|
|
305
|
+
rows.push({ node: row, search: `${item.description} ${item.keys.join(" ")}`.toLowerCase() });
|
|
282
306
|
}
|
|
283
307
|
node.appendChild(list);
|
|
284
308
|
this.#groups_node.appendChild(node);
|
|
285
|
-
this.#groups.push({node: node, rows: rows});
|
|
309
|
+
this.#groups.push({ node: node, rows: rows });
|
|
286
310
|
});
|
|
287
311
|
this.#empty.innerText = optionOr(this.#empty_text, I18n.t("navigation.shortcutHelpEmpty"));
|
|
288
312
|
this.#syncSearch();
|
|
@@ -313,9 +337,8 @@ class ShortcutHelp {
|
|
|
313
337
|
#syncSearch() {
|
|
314
338
|
this.#search.hidden = this.#searchable !== true;
|
|
315
339
|
const visible = this.#filter(this.#input === undefined ? "" : this.#input.getValue());
|
|
316
|
-
this.#status.innerText =
|
|
317
|
-
? I18n.t("navigation.shortcutHelpCount", {count: visible})
|
|
318
|
-
: "";
|
|
340
|
+
this.#status.innerText =
|
|
341
|
+
this.#searchable === true ? I18n.t("navigation.shortcutHelpCount", { count: visible }) : "";
|
|
319
342
|
// Без поиска пустая строка не показывается: скрывать нечего
|
|
320
343
|
if (this.#searchable !== true) this.#empty.hidden = true;
|
|
321
344
|
}
|
|
@@ -333,4 +356,4 @@ class ShortcutHelp {
|
|
|
333
356
|
}
|
|
334
357
|
}
|
|
335
358
|
|
|
336
|
-
exports.ShortcutHelp = ShortcutHelp
|
|
359
|
+
exports.ShortcutHelp = ShortcutHelp;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const {setStyles} = require("../../modules/chui_functions");
|
|
2
|
-
const {Icon, Icons} = require("../chui_icons/icons");
|
|
3
|
-
const {I18n} = require("../../modules/chui_i18n/chui_i18n");
|
|
1
|
+
const { setStyles } = require("../../modules/chui_functions");
|
|
2
|
+
const { Icon, Icons } = require("../chui_icons/icons");
|
|
3
|
+
const { I18n } = require("../../modules/chui_i18n/chui_i18n");
|
|
4
4
|
|
|
5
5
|
/** Служебные ключи пункта: всё остальное — данные пункта */
|
|
6
6
|
const SERVICE_KEYS = ["id", "type", "title", "icon", "badge", "children", "disabled", "href"];
|
|
@@ -69,18 +69,20 @@ class SidebarNav {
|
|
|
69
69
|
#active_id = undefined;
|
|
70
70
|
#focus_id = undefined;
|
|
71
71
|
|
|
72
|
-
constructor(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
constructor(
|
|
73
|
+
options = {
|
|
74
|
+
id: String(),
|
|
75
|
+
title: String(),
|
|
76
|
+
label: String(),
|
|
77
|
+
items: Array(),
|
|
78
|
+
value: String(),
|
|
79
|
+
collapsible: Boolean(),
|
|
80
|
+
collapsed: Boolean(),
|
|
81
|
+
onSelect: undefined,
|
|
82
|
+
onToggle: undefined,
|
|
83
|
+
changeEvent: undefined,
|
|
84
|
+
}
|
|
85
|
+
) {
|
|
84
86
|
setStyles(__dirname + "/styles.css", "chUiJS_SidebarNav");
|
|
85
87
|
SidebarNav.#counter += 1;
|
|
86
88
|
this.#id = options.id === undefined ? `chui_sidebar_nav_${SidebarNav.#counter}` : options.id;
|
|
@@ -203,7 +205,7 @@ class SidebarNav {
|
|
|
203
205
|
let section = undefined;
|
|
204
206
|
for (const item of Array.isArray(items) ? items : []) {
|
|
205
207
|
if (item !== null && typeof item === "object" && item.type === "section") {
|
|
206
|
-
section = {type: "section", title: item.title === undefined ? "" : String(item.title), children: []};
|
|
208
|
+
section = { type: "section", title: item.title === undefined ? "" : String(item.title), children: [] };
|
|
207
209
|
this.#items.push(section);
|
|
208
210
|
continue;
|
|
209
211
|
}
|
|
@@ -285,7 +287,10 @@ class SidebarNav {
|
|
|
285
287
|
this.#root.classList.toggle("sidebar_nav_collapsed", this.#collapsed);
|
|
286
288
|
if (this.#collapse !== undefined) {
|
|
287
289
|
this.#collapse.setAttribute("aria-expanded", this.#collapsed ? "false" : "true");
|
|
288
|
-
this.#collapse.setAttribute(
|
|
290
|
+
this.#collapse.setAttribute(
|
|
291
|
+
"aria-label",
|
|
292
|
+
this.#collapsed ? I18n.t("navigation.sidebarExpand") : I18n.t("navigation.sidebarCollapse")
|
|
293
|
+
);
|
|
289
294
|
}
|
|
290
295
|
this.#render();
|
|
291
296
|
return this;
|
|
@@ -319,7 +324,7 @@ class SidebarNav {
|
|
|
319
324
|
|
|
320
325
|
// === ВНУТРЕННЕЕ ===
|
|
321
326
|
static #toNode(item = Object()) {
|
|
322
|
-
const source = typeof item === "string" ? {title: item} : item;
|
|
327
|
+
const source = typeof item === "string" ? { title: item } : item;
|
|
323
328
|
const data = {};
|
|
324
329
|
for (const key of Object.keys(source === null ? {} : source)) {
|
|
325
330
|
if (!SERVICE_KEYS.includes(key)) data[key] = source[key];
|
|
@@ -341,13 +346,17 @@ class SidebarNav {
|
|
|
341
346
|
|
|
342
347
|
#describeEntry(node) {
|
|
343
348
|
if (node.type === "section") {
|
|
344
|
-
return {
|
|
349
|
+
return {
|
|
350
|
+
type: "section",
|
|
351
|
+
title: node.title,
|
|
352
|
+
children: node.children.map((child) => this.#describeEntry(child)),
|
|
353
|
+
};
|
|
345
354
|
}
|
|
346
355
|
return this.#describe(node);
|
|
347
356
|
}
|
|
348
357
|
|
|
349
358
|
#describe(node) {
|
|
350
|
-
const descriptor = {id: node.id, title: node.title, icon: node.icon};
|
|
359
|
+
const descriptor = { id: node.id, title: node.title, icon: node.icon };
|
|
351
360
|
if (node.badge !== undefined) descriptor.badge = node.badge;
|
|
352
361
|
for (const key of Object.keys(node.data)) descriptor[key] = node.data[key];
|
|
353
362
|
descriptor.disabled = node.disabled;
|
|
@@ -377,7 +386,8 @@ class SidebarNav {
|
|
|
377
386
|
#siblingsOf(node) {
|
|
378
387
|
const parent = this.#parentNode(node);
|
|
379
388
|
if (parent !== undefined) return parent.children;
|
|
380
|
-
for (const entry of this.#items)
|
|
389
|
+
for (const entry of this.#items)
|
|
390
|
+
if (entry.type === "section" && entry.children.includes(node)) return entry.children;
|
|
381
391
|
return this.#items;
|
|
382
392
|
}
|
|
383
393
|
|
|
@@ -604,7 +614,7 @@ class SidebarNav {
|
|
|
604
614
|
const link = target === undefined ? null : target.closest(".sidebar_nav_link");
|
|
605
615
|
if (link !== null && link !== undefined) return link;
|
|
606
616
|
const id = this.#active_id;
|
|
607
|
-
return id === undefined ? null : this.#links().find((node) => node.dataset.id === id) ?? null;
|
|
617
|
+
return id === undefined ? null : (this.#links().find((node) => node.dataset.id === id) ?? null);
|
|
608
618
|
}
|
|
609
619
|
|
|
610
620
|
#onClick = (event) => {
|
|
@@ -663,4 +673,4 @@ class SidebarNav {
|
|
|
663
673
|
};
|
|
664
674
|
}
|
|
665
675
|
|
|
666
|
-
exports.SidebarNav = SidebarNav
|
|
676
|
+
exports.SidebarNav = SidebarNav;
|