chuijs 4.0.2 → 4.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +597 -0
- package/README.md +43 -644
- package/framework/appLayout/default/chui_app_layout.js +602 -496
- package/framework/appLayout/default/global_style.css +288 -97
- package/framework/appLayout/default/main_theme_style.css +188 -101
- package/framework/components/chui_accordion/accordion.js +38 -35
- package/framework/components/chui_accordion/styles.css +13 -12
- package/framework/components/chui_action_sheet/action_sheet.js +93 -64
- package/framework/components/chui_action_sheet/styles.css +12 -5
- package/framework/components/chui_actions_bar/actions_bar.js +338 -0
- package/framework/components/chui_actions_bar/styles.css +139 -0
- package/framework/components/chui_affix/affix.js +16 -11
- package/framework/components/chui_affix/styles.css +5 -0
- package/framework/components/chui_alert/alert.js +34 -19
- package/framework/components/chui_alert/styles.css +7 -0
- package/framework/components/chui_avatar/avatar.js +36 -35
- package/framework/components/chui_avatar/styles.css +1 -1
- package/framework/components/chui_avatar_group/avatar_group.js +25 -23
- package/framework/components/chui_avatar_group/styles.css +1 -1
- package/framework/components/chui_backtop/backtop.js +60 -21
- package/framework/components/chui_backtop/styles.css +21 -0
- package/framework/components/chui_badge/badge.js +30 -28
- package/framework/components/chui_badge/styles.css +6 -6
- package/framework/components/chui_banner/banner.js +222 -0
- package/framework/components/chui_banner/styles.css +170 -0
- package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
- package/framework/components/chui_breadcrumb/styles.css +1 -1
- package/framework/components/chui_button/button.js +52 -36
- package/framework/components/chui_button/styles.css +7 -7
- package/framework/components/chui_calendar/calendar.js +18 -16
- package/framework/components/chui_card/card.js +52 -32
- package/framework/components/chui_card_scroll/card_scroll.js +169 -0
- package/framework/components/chui_card_scroll/styles.css +86 -0
- package/framework/components/chui_chat/chat.js +140 -79
- package/framework/components/chui_chat/styles.css +18 -7
- package/framework/components/chui_clipboard_history/clipboard_history.js +53 -39
- package/framework/components/chui_clipboard_history/styles.css +13 -9
- package/framework/components/chui_code/code.js +10 -10
- package/framework/components/chui_code/styles.css +4 -4
- package/framework/components/chui_code_editor/code_editor.js +73 -57
- package/framework/components/chui_code_editor/styles.css +6 -5
- package/framework/components/chui_command_palette/command_palette.js +87 -64
- package/framework/components/chui_command_palette/styles.css +5 -5
- package/framework/components/chui_console/console.js +13 -13
- package/framework/components/chui_console/styles.css +6 -3
- package/framework/components/chui_content_block/content_block.js +35 -21
- package/framework/components/chui_content_block/styles.css +2 -2
- package/framework/components/chui_context_menu/context_menu.js +171 -58
- package/framework/components/chui_context_menu/styles.css +82 -8
- package/framework/components/chui_custom_element/custom_element.js +25 -18
- package/framework/components/chui_data_grid/data_grid.js +633 -471
- package/framework/components/chui_data_grid/styles.css +24 -22
- package/framework/components/chui_descriptions/descriptions.js +34 -17
- package/framework/components/chui_descriptions/styles.css +1 -1
- package/framework/components/chui_details/details.js +42 -36
- package/framework/components/chui_details/styles.css +12 -11
- package/framework/components/chui_diff_viewer/diff_viewer.js +172 -147
- package/framework/components/chui_diff_viewer/styles.css +10 -10
- package/framework/components/chui_divider/divider.js +19 -17
- package/framework/components/chui_divider/styles.css +2 -2
- package/framework/components/chui_drawer/drawer.js +63 -38
- package/framework/components/chui_drawer/styles.css +18 -4
- package/framework/components/chui_drop_zone/drop_zone.js +37 -27
- package/framework/components/chui_drop_zone/styles.css +10 -6
- package/framework/components/chui_empty_state/empty_state.js +20 -15
- package/framework/components/chui_fieldset/fieldset.js +40 -23
- package/framework/components/chui_fieldset/styles.css +6 -6
- package/framework/components/chui_file_explorer/file_explorer.js +260 -189
- package/framework/components/chui_file_explorer/styles.css +8 -7
- package/framework/components/chui_form/form.js +40 -28
- package/framework/components/chui_form/styles.css +1 -1
- package/framework/components/chui_gantt/gantt.js +102 -78
- package/framework/components/chui_gantt/styles.css +5 -5
- package/framework/components/chui_graphs/graphs.js +376 -239
- package/framework/components/chui_graphs/styles.css +27 -6
- package/framework/components/chui_hero/hero.js +98 -37
- package/framework/components/chui_hero/styles.css +176 -7
- package/framework/components/chui_html_block/html_block.js +8 -8
- package/framework/components/chui_html_block/styles.css +3 -3
- package/framework/components/chui_hx/hx.js +3 -3
- package/framework/components/chui_hx/styles.css +13 -6
- package/framework/components/chui_icons/icons.js +2115 -2115
- package/framework/components/chui_icons/styles.css +4 -3
- package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
- package/framework/components/chui_inputs/chui_check_box/styles.css +30 -21
- package/framework/components/chui_inputs/chui_chips/chips.js +141 -70
- package/framework/components/chui_inputs/chui_chips/styles.css +32 -7
- package/framework/components/chui_inputs/chui_color_picker/color_picker.js +55 -38
- package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
- package/framework/components/chui_inputs/chui_combo_box/combo_box.js +127 -109
- package/framework/components/chui_inputs/chui_combo_box/styles.css +23 -21
- package/framework/components/chui_inputs/chui_date/date.js +161 -127
- package/framework/components/chui_inputs/chui_date/styles.css +20 -19
- package/framework/components/chui_inputs/chui_date_range/date_range.js +61 -50
- package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
- package/framework/components/chui_inputs/chui_datetime/datetime.js +47 -39
- package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
- package/framework/components/chui_inputs/chui_email/email.js +48 -36
- package/framework/components/chui_inputs/chui_email/styles.css +11 -11
- package/framework/components/chui_inputs/chui_file/file.js +71 -44
- package/framework/components/chui_inputs/chui_file/styles.css +23 -19
- package/framework/components/chui_inputs/chui_hotkey/hotkey.js +101 -76
- package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
- package/framework/components/chui_inputs/chui_masked/masked.js +83 -72
- package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
- package/framework/components/chui_inputs/chui_mention/mention.js +87 -40
- package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
- package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +242 -212
- package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +23 -15
- package/framework/components/chui_inputs/chui_number/number.js +84 -70
- package/framework/components/chui_inputs/chui_number/styles.css +13 -13
- package/framework/components/chui_inputs/chui_otp/otp.js +71 -62
- package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
- package/framework/components/chui_inputs/chui_password/password.js +72 -56
- package/framework/components/chui_inputs/chui_password/styles.css +15 -15
- package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
- package/framework/components/chui_inputs/chui_radio_button/styles.css +22 -22
- package/framework/components/chui_inputs/chui_rating/rating.js +54 -50
- package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
- package/framework/components/chui_inputs/chui_select_box/select_box.js +132 -108
- package/framework/components/chui_inputs/chui_select_box/styles.css +21 -21
- package/framework/components/chui_inputs/chui_slider/slider.js +41 -38
- package/framework/components/chui_inputs/chui_slider/styles.css +7 -5
- package/framework/components/chui_inputs/chui_text/styles.css +14 -14
- package/framework/components/chui_inputs/chui_text/text.js +69 -52
- package/framework/components/chui_inputs/chui_text_area/styles.css +14 -14
- package/framework/components/chui_inputs/chui_text_area/text_area.js +59 -36
- package/framework/components/chui_inputs/chui_time/styles.css +18 -20
- package/framework/components/chui_inputs/chui_time/time.js +71 -49
- package/framework/components/chui_inputs/chui_toggle/styles.css +13 -6
- package/framework/components/chui_inputs/chui_toggle/toggle.js +27 -27
- package/framework/components/chui_json_editor/json_editor.js +137 -127
- package/framework/components/chui_json_editor/styles.css +5 -5
- package/framework/components/chui_json_viewer/json_viewer.js +133 -114
- package/framework/components/chui_json_viewer/styles.css +9 -8
- package/framework/components/chui_kanban/kanban.js +78 -60
- package/framework/components/chui_kanban/styles.css +8 -4
- package/framework/components/chui_kbd/kbd.js +12 -10
- package/framework/components/chui_kbd/styles.css +1 -1
- package/framework/components/chui_label/label.js +31 -29
- package/framework/components/chui_label/styles.css +3 -3
- package/framework/components/chui_link/link.js +36 -29
- package/framework/components/chui_link/styles.css +11 -4
- package/framework/components/chui_list/list.js +42 -38
- package/framework/components/chui_list/styles.css +4 -3
- package/framework/components/chui_markdown_editor/markdown_editor.js +125 -109
- package/framework/components/chui_markdown_editor/styles.css +5 -5
- package/framework/components/chui_media/audio.js +457 -364
- package/framework/components/chui_media/audio_styles.css +74 -37
- package/framework/components/chui_media/image.js +99 -64
- package/framework/components/chui_media/image_compare.js +86 -55
- package/framework/components/chui_media/image_compare_styles.css +5 -5
- package/framework/components/chui_media/image_styles.css +4 -4
- package/framework/components/chui_media/video.js +264 -171
- package/framework/components/chui_media/video_styles.css +57 -24
- package/framework/components/chui_menu_bar/menu_bar.js +67 -65
- package/framework/components/chui_menu_bar/styles.css +14 -12
- package/framework/components/chui_message_bar/message_bar.js +551 -0
- package/framework/components/chui_message_bar/styles.css +248 -0
- package/framework/components/chui_modal/modal.js +81 -56
- package/framework/components/chui_modal/styles.css +3 -2
- package/framework/components/chui_notification/notification.js +107 -69
- package/framework/components/chui_notification/notification_download.js +28 -77
- package/framework/components/chui_notification/notification_download_card.js +115 -0
- package/framework/components/chui_notification/notification_download_progress.css +5 -4
- package/framework/components/chui_notification/notification_download_progress.js +73 -105
- package/framework/components/chui_notification/notification_update.js +44 -37
- package/framework/components/chui_notification/status_plate.css +3 -3
- package/framework/components/chui_notification/status_plate.js +2 -2
- package/framework/components/chui_notification/styles.css +6 -1
- package/framework/components/chui_notification/styles_download.css +2 -2
- package/framework/components/chui_notification/styles_update.css +3 -3
- package/framework/components/chui_org_chart/org_chart.js +101 -62
- package/framework/components/chui_org_chart/styles.css +2 -2
- package/framework/components/chui_pagination/pagination.js +65 -30
- package/framework/components/chui_pagination/styles.css +1 -1
- package/framework/components/chui_paragraph/paragraph.js +2 -2
- package/framework/components/chui_paragraph/styles.css +3 -3
- package/framework/components/chui_popover/popover.js +77 -50
- package/framework/components/chui_popover/styles.css +1 -1
- package/framework/components/chui_popups/popups.js +210 -181
- package/framework/components/chui_popups/styles.css +7 -7
- package/framework/components/chui_print_button/print_button.js +48 -33
- package/framework/components/chui_progress_bar/progress_bar.js +49 -19
- package/framework/components/chui_progress_bar/styles.css +6 -6
- package/framework/components/chui_progress_ring/progress_ring.js +32 -30
- package/framework/components/chui_progress_ring/styles.css +1 -1
- package/framework/components/chui_qrcode/qrcode.js +85 -41
- package/framework/components/chui_query_builder/query_builder.js +263 -170
- package/framework/components/chui_query_builder/styles.css +4 -4
- package/framework/components/chui_radio_group/radio_group.js +36 -26
- package/framework/components/chui_radio_group/styles.css +2 -2
- package/framework/components/chui_result/result.js +41 -31
- package/framework/components/chui_result/styles.css +3 -3
- package/framework/components/chui_scheduler/scheduler.js +126 -104
- package/framework/components/chui_scheduler/styles.css +11 -7
- package/framework/components/chui_screen_spinner/screen_spinner.js +167 -0
- package/framework/components/chui_screen_spinner/styles.css +49 -0
- package/framework/components/chui_segmented_control/segmented_control.js +90 -27
- package/framework/components/chui_segmented_control/styles.css +32 -6
- package/framework/components/chui_settings/settings.js +160 -87
- package/framework/components/chui_settings/styles.css +4 -4
- package/framework/components/chui_shortcut_help/shortcut_help.js +82 -61
- package/framework/components/chui_sidebar_nav/sidebar_nav.js +132 -53
- package/framework/components/chui_sidebar_nav/styles.css +9 -3
- package/framework/components/chui_skeleton/skeleton.js +29 -24
- package/framework/components/chui_slideshow/slideshow.js +122 -103
- package/framework/components/chui_slideshow/styles.css +22 -16
- package/framework/components/chui_spinner/spinner.js +17 -17
- package/framework/components/chui_spinner/styles.css +0 -1
- package/framework/components/chui_split_button/split_button.js +53 -30
- package/framework/components/chui_split_button/styles.css +22 -6
- package/framework/components/chui_splitter/splitter.js +46 -39
- package/framework/components/chui_splitter/styles.css +2 -2
- package/framework/components/chui_statistic/statistic.js +111 -84
- package/framework/components/chui_status_bar/status_bar.js +11 -9
- package/framework/components/chui_status_bar/styles.css +2 -2
- package/framework/components/chui_stepper/stepper.js +230 -54
- package/framework/components/chui_stepper/styles.css +79 -14
- package/framework/components/chui_sticky_bar/sticky_bar.js +53 -17
- package/framework/components/chui_sticky_bar/styles.css +11 -7
- package/framework/components/chui_tabs/chui_tabs.js +100 -46
- package/framework/components/chui_tabs/styles.css +43 -15
- package/framework/components/chui_text_editor/styles.css +24 -23
- package/framework/components/chui_text_editor/text_editor.js +103 -79
- package/framework/components/chui_text_editor/text_editor_panel.js +428 -367
- package/framework/components/chui_theme_toggle/theme_toggle.js +46 -25
- package/framework/components/chui_timeline/styles.css +3 -1
- package/framework/components/chui_timeline/timeline.js +14 -12
- package/framework/components/chui_toast_queue/styles.css +11 -11
- package/framework/components/chui_toast_queue/toast_queue.js +82 -73
- package/framework/components/chui_toolbar/styles.css +2 -2
- package/framework/components/chui_toolbar/toolbar.js +20 -13
- package/framework/components/chui_tooltip/styles.css +2 -2
- package/framework/components/chui_tooltip/tooltip.js +40 -27
- package/framework/components/chui_tour/styles.css +12 -7
- package/framework/components/chui_tour/tour.js +132 -98
- package/framework/components/chui_transfer/styles.css +8 -7
- package/framework/components/chui_transfer/transfer.js +143 -123
- package/framework/components/chui_tree_table/styles.css +4 -4
- package/framework/components/chui_tree_table/tree_table.js +88 -74
- package/framework/components/chui_tree_view/styles.css +14 -10
- package/framework/components/chui_tree_view/tree_view.js +298 -253
- package/framework/components/chui_user_bar/styles.css +145 -0
- package/framework/components/chui_user_bar/user_bar.js +402 -0
- package/framework/components/chui_user_list_bar/styles.css +173 -0
- package/framework/components/chui_user_list_bar/user_list_bar.js +485 -0
- package/framework/components/chui_watermark/watermark.js +41 -33
- package/framework/components/chui_webview/styles.css +2 -2
- package/framework/components/chui_webview/webview.js +64 -52
- package/framework/components/chui_write_bar/styles.css +172 -0
- package/framework/components/chui_write_bar/write_bar.js +320 -0
- package/framework/main_window.js +1234 -0
- package/framework/modules/chui_a11y/chui_a11y.js +153 -123
- package/framework/modules/chui_animations/animations.js +105 -43
- package/framework/modules/chui_animations/motion.js +120 -0
- package/framework/modules/chui_animations/styles.css +37 -4
- package/framework/modules/chui_bridge/preload.js +36 -25
- package/framework/modules/chui_functions.js +69 -63
- package/framework/modules/chui_highlight/chui_highlight.js +25 -22
- package/framework/modules/chui_highlight/styles.css +13 -10
- package/framework/modules/chui_i18n/chui_i18n.js +12 -10
- 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 +65 -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 +12 -8
- package/framework/modules/chui_i18n/locales/validate.js +3 -3
- package/framework/modules/chui_json/chui_json.js +11 -11
- package/framework/modules/chui_layout/chui_layout.js +12 -10
- package/framework/modules/chui_logger/chui_logger.js +47 -28
- package/framework/modules/chui_page/page.js +39 -33
- package/framework/modules/chui_palette/palette.js +61 -0
- package/framework/modules/chui_qr/chui_qr.js +179 -88
- package/framework/modules/chui_scrollbar/chui_scrollbar.js +79 -68
- package/framework/modules/chui_scrollbar/styles.css +4 -2
- package/framework/modules/chui_services/chui_channels.js +27 -13
- package/framework/modules/chui_services/chui_services.js +47 -39
- package/framework/modules/chui_services/desktop.js +108 -101
- package/framework/modules/chui_sortable/chui_sortable.js +33 -28
- package/framework/modules/chui_validate/chui_validate.js +10 -7
- package/framework/tray_bar/chui_menu_items.js +136 -46
- package/index.d.ts +5046 -0
- package/index.js +199 -1254
- package/package.json +81 -68
- package/framework/components/telegram_bot/chui_telegram_bot.js +0 -184
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const {SERVICES_CHANNELS, SERVICES_CALLS, SERVICES_SYNC_CALLS, APP_PATH_NAMES} = require("./chui_channels");
|
|
1
|
+
const { SERVICES_CHANNELS, SERVICES_CALLS, SERVICES_SYNC_CALLS, APP_PATH_NAMES } = require("./chui_channels");
|
|
2
|
+
const { crossFade } = require("../chui_animations/motion");
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Десктоп-сервисы со стороны страницы: буфер обмена, последние документы, прогресс на иконке
|
|
@@ -43,25 +44,25 @@ class Desktop {
|
|
|
43
44
|
remove: (target = undefined) => Desktop.#call("clipboardHistoryRemove", target),
|
|
44
45
|
clear: () => Desktop.#call("clipboardHistoryClear"),
|
|
45
46
|
/** Подписка на изменение истории; возвращает функцию отписки */
|
|
46
|
-
onChange: (listener = () => {}) => Desktop.#subscribeHistory(listener)
|
|
47
|
-
}
|
|
47
|
+
onChange: (listener = () => {}) => Desktop.#subscribeHistory(listener),
|
|
48
|
+
},
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
static recent = {
|
|
51
52
|
add: (path = String(), name = undefined) => Desktop.#call("recentAdd", path, name),
|
|
52
53
|
clear: () => Desktop.#call("recentClear"),
|
|
53
|
-
list: () => Desktop.#call("recentList")
|
|
54
|
+
list: () => Desktop.#call("recentList"),
|
|
54
55
|
};
|
|
55
56
|
|
|
56
57
|
static progress = {
|
|
57
58
|
/** `progress.set(0.4)` — 40%; `mode` — TaskbarProgress.MODE */
|
|
58
59
|
set: (value = Number(), mode = "normal") => Desktop.#call("progressSet", value, mode),
|
|
59
|
-
clear: () => Desktop.#call("progressClear")
|
|
60
|
+
clear: () => Desktop.#call("progressClear"),
|
|
60
61
|
};
|
|
61
62
|
|
|
62
63
|
static shell = {
|
|
63
64
|
/** Открыть адрес в браузере по умолчанию; `false` — схема не разрешена */
|
|
64
|
-
openExternal: (url = String()) => Desktop.#call("shellOpenExternal", String(url))
|
|
65
|
+
openExternal: (url = String()) => Desktop.#call("shellOpenExternal", String(url)),
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
/**
|
|
@@ -78,7 +79,7 @@ class Desktop {
|
|
|
78
79
|
page: (options = {}) => Desktop.#call("printPage", options),
|
|
79
80
|
html: (html = String(), options = {}) => Desktop.#call("printHtml", String(html), options),
|
|
80
81
|
/** `{saved, path, canceled}`; с `options.path` диалог сохранения не открывается */
|
|
81
|
-
pdf: (html = String(), options = {}) => Desktop.#call("printPdf", String(html), options)
|
|
82
|
+
pdf: (html = String(), options = {}) => Desktop.#call("printPdf", String(html), options),
|
|
82
83
|
};
|
|
83
84
|
|
|
84
85
|
static shortcuts = {
|
|
@@ -86,12 +87,16 @@ class Desktop {
|
|
|
86
87
|
off: (accelerator = String(), handler = () => {}) => Desktop.#unsubscribe(accelerator, handler),
|
|
87
88
|
offAll: () => Desktop.#unsubscribeAll(),
|
|
88
89
|
/** Комбинации, на которые подписано это окно */
|
|
89
|
-
get: () => [...Desktop.#
|
|
90
|
+
get: () => [...Desktop.#shortcutHandlers.keys()],
|
|
90
91
|
};
|
|
91
92
|
|
|
92
93
|
/**
|
|
93
94
|
* Тема приложения. Палитры в стилях разложены по `prefers-color-scheme`, поэтому смена
|
|
94
|
-
* источника меняет цвета без правок в DOM
|
|
95
|
+
* источника меняет цвета без правок в DOM: Chromium сам сообщает странице новое значение
|
|
96
|
+
* запроса. Смена идёт кроссфейдом (`crossFade` в `chui_animations/motion`) — обычный
|
|
97
|
+
* CSS-переход на изменение из запроса браузер не запускает, и без него тема переключалась бы
|
|
98
|
+
* кадром. Смену системной схемы при источнике «system» так показать нельзя: её присылает
|
|
99
|
+
* сама система, и снимка «до» в этот момент уже нет.
|
|
95
100
|
*
|
|
96
101
|
* ```javascript
|
|
97
102
|
* await Desktop.theme.set(Desktop.theme.SOURCE.DARK); // 'dark' | 'light' | 'system'
|
|
@@ -99,14 +104,15 @@ class Desktop {
|
|
|
99
104
|
* ```
|
|
100
105
|
*/
|
|
101
106
|
static theme = {
|
|
102
|
-
SOURCE: {SYSTEM: "system", LIGHT: "light", DARK: "dark"},
|
|
107
|
+
SOURCE: { SYSTEM: "system", LIGHT: "light", DARK: "dark" },
|
|
103
108
|
/** @returns {Promise<{theme: string, source: string}>} фактическая тема и выбранный источник */
|
|
104
109
|
get: () => Desktop.#call("themeGet"),
|
|
105
|
-
set: (source = String()) =>
|
|
110
|
+
set: (source = String()) =>
|
|
111
|
+
crossFade(() => Desktop.#call("themeSet", String(source)), { waitFor: "(prefers-color-scheme: dark)" }),
|
|
106
112
|
/** Переключить светлую и тёмную */
|
|
107
|
-
toggle: () => Desktop.#call("themeToggle"),
|
|
113
|
+
toggle: () => crossFade(() => Desktop.#call("themeToggle"), { waitFor: "(prefers-color-scheme: dark)" }),
|
|
108
114
|
/** Подписка на смену темы; возвращает функцию отписки */
|
|
109
|
-
onChange: (listener = () => {}) => Desktop.#subscribeTheme(listener)
|
|
115
|
+
onChange: (listener = () => {}) => Desktop.#subscribeTheme(listener),
|
|
110
116
|
};
|
|
111
117
|
|
|
112
118
|
/**
|
|
@@ -122,7 +128,7 @@ class Desktop {
|
|
|
122
128
|
get: () => Desktop.#call("localeGet"),
|
|
123
129
|
set: (locale = String()) => Desktop.#call("localeSet", String(locale)),
|
|
124
130
|
/** Подписка на смену языка; возвращает функцию отписки */
|
|
125
|
-
onChange: (listener = () => {}) => Desktop.#subscribeLocale(listener)
|
|
131
|
+
onChange: (listener = () => {}) => Desktop.#subscribeLocale(listener),
|
|
126
132
|
};
|
|
127
133
|
|
|
128
134
|
/**
|
|
@@ -194,7 +200,7 @@ class Desktop {
|
|
|
194
200
|
* Отвечает значением, а не промисом (синхронный канал), как и `quit()`.
|
|
195
201
|
* @returns {boolean} `true` — перезапуск начат
|
|
196
202
|
*/
|
|
197
|
-
restart: () => Desktop.#callSync("appRestartSync")
|
|
203
|
+
restart: () => Desktop.#callSync("appRestartSync"),
|
|
198
204
|
};
|
|
199
205
|
|
|
200
206
|
/**
|
|
@@ -208,7 +214,7 @@ class Desktop {
|
|
|
208
214
|
static dialog = {
|
|
209
215
|
open: (options = Object()) => Desktop.#call("dialogOpen", options),
|
|
210
216
|
save: (options = Object()) => Desktop.#call("dialogSave", options),
|
|
211
|
-
message: (options = Object()) => Desktop.#call("dialogMessage", options)
|
|
217
|
+
message: (options = Object()) => Desktop.#call("dialogMessage", options),
|
|
212
218
|
};
|
|
213
219
|
|
|
214
220
|
/**
|
|
@@ -223,25 +229,25 @@ class Desktop {
|
|
|
223
229
|
/** @returns {Promise<number>} размер кеша в байтах */
|
|
224
230
|
getCacheSize: () => Desktop.#call("sessionCacheSize"),
|
|
225
231
|
clearCache: () => Desktop.#call("sessionClearCache"),
|
|
226
|
-
clearStorageData: (options = Object()) => Desktop.#call("sessionClearStorage", options)
|
|
232
|
+
clearStorageData: (options = Object()) => Desktop.#call("sessionClearStorage", options),
|
|
227
233
|
};
|
|
228
234
|
|
|
229
235
|
// accelerator → набор обработчиков этого окна
|
|
230
|
-
static #
|
|
231
|
-
static #
|
|
232
|
-
static #
|
|
233
|
-
static #
|
|
234
|
-
static #
|
|
235
|
-
static #
|
|
236
|
-
static #
|
|
237
|
-
static #
|
|
238
|
-
static #
|
|
239
|
-
static #
|
|
240
|
-
static #
|
|
241
|
-
static #
|
|
236
|
+
static #shortcutHandlers = new Map();
|
|
237
|
+
static #shortcutEventBound = false;
|
|
238
|
+
static #shortcutBridgeUnsubscribe = undefined;
|
|
239
|
+
static #themeHandlers = new Set();
|
|
240
|
+
static #themeEventBound = false;
|
|
241
|
+
static #themeBridgeUnsubscribe = undefined;
|
|
242
|
+
static #localeHandlers = new Set();
|
|
243
|
+
static #localeEventBound = false;
|
|
244
|
+
static #localeBridgeUnsubscribe = undefined;
|
|
245
|
+
static #historyHandlers = new Set();
|
|
246
|
+
static #historyEventBound = false;
|
|
247
|
+
static #historyBridgeUnsubscribe = undefined;
|
|
242
248
|
// Пути приложения, уже полученные значением: `sendSync` останавливает страницу на время
|
|
243
249
|
// ответа, поэтому за одним и тем же именем в main ходят один раз
|
|
244
|
-
static #
|
|
250
|
+
static #appPaths = new Map();
|
|
245
251
|
|
|
246
252
|
static #bridge() {
|
|
247
253
|
if (typeof window === "undefined" || window.chui === undefined) return undefined;
|
|
@@ -252,7 +258,7 @@ class Desktop {
|
|
|
252
258
|
static #call(method = String(), ...args) {
|
|
253
259
|
const services = Desktop.#bridge();
|
|
254
260
|
if (services !== undefined && typeof services[method] === "function") return services[method](...args);
|
|
255
|
-
const {ipcRenderer} = require("electron");
|
|
261
|
+
const { ipcRenderer } = require("electron");
|
|
256
262
|
return ipcRenderer.invoke(SERVICES_CALLS[method], ...args);
|
|
257
263
|
}
|
|
258
264
|
|
|
@@ -263,9 +269,10 @@ class Desktop {
|
|
|
263
269
|
*/
|
|
264
270
|
static #callSync(method = String(), ...args) {
|
|
265
271
|
const services = Desktop.#bridge();
|
|
266
|
-
const answer =
|
|
267
|
-
|
|
268
|
-
|
|
272
|
+
const answer =
|
|
273
|
+
services !== undefined && typeof services[method] === "function"
|
|
274
|
+
? services[method](...args)
|
|
275
|
+
: require("electron").ipcRenderer.sendSync(SERVICES_SYNC_CALLS[method], ...args);
|
|
269
276
|
if (answer === null || typeof answer !== "object") return answer;
|
|
270
277
|
if (answer.error !== undefined) throw new Error(answer.error);
|
|
271
278
|
return answer.value;
|
|
@@ -280,11 +287,9 @@ class Desktop {
|
|
|
280
287
|
* страницы одним и тем же вызовом.
|
|
281
288
|
*/
|
|
282
289
|
static #appPath(name = String()) {
|
|
283
|
-
if (Desktop.#
|
|
284
|
-
const value = Desktop.#inMainProcess()
|
|
285
|
-
|
|
286
|
-
: Desktop.#callSync("appPathSync", name);
|
|
287
|
-
Desktop.#app_paths.set(name, value);
|
|
290
|
+
if (Desktop.#appPaths.has(name)) return Desktop.#appPaths.get(name);
|
|
291
|
+
const value = Desktop.#inMainProcess() ? Desktop.#appPathInMain(name) : Desktop.#callSync("appPathSync", name);
|
|
292
|
+
Desktop.#appPaths.set(name, value);
|
|
288
293
|
return value;
|
|
289
294
|
}
|
|
290
295
|
|
|
@@ -310,37 +315,39 @@ class Desktop {
|
|
|
310
315
|
*/
|
|
311
316
|
static #electronObject(name = String()) {
|
|
312
317
|
if (Desktop.#inMainProcess() === false) {
|
|
313
|
-
throw new Error(
|
|
318
|
+
throw new Error(
|
|
319
|
+
`Desktop.app: сырой «${name}» доступен только в main-процессе — со страницы возьмите Desktop.app.info(), Desktop.session.* или свой канал из security.channels`
|
|
320
|
+
);
|
|
314
321
|
}
|
|
315
322
|
return require("electron")[name];
|
|
316
323
|
}
|
|
317
324
|
|
|
318
325
|
static #subscribe(accelerator = String(), handler = () => {}) {
|
|
319
|
-
const handlers = Desktop.#
|
|
326
|
+
const handlers = Desktop.#shortcutHandlers.get(accelerator) ?? new Set();
|
|
320
327
|
const first = handlers.size === 0;
|
|
321
328
|
handlers.add(handler);
|
|
322
|
-
Desktop.#
|
|
323
|
-
if (!Desktop.#
|
|
329
|
+
Desktop.#shortcutHandlers.set(accelerator, handlers);
|
|
330
|
+
if (!Desktop.#shortcutEventBound) Desktop.#bindShortcutEvent();
|
|
324
331
|
// В main клавиша регистрируется один раз на все окна, поэтому подписка — на первую
|
|
325
332
|
if (first) Desktop.#call("shortcutSubscribe", accelerator);
|
|
326
333
|
return () => Desktop.#unsubscribe(accelerator, handler);
|
|
327
334
|
}
|
|
328
335
|
|
|
329
336
|
static #unsubscribe(accelerator = String(), handler = () => {}) {
|
|
330
|
-
const handlers = Desktop.#
|
|
337
|
+
const handlers = Desktop.#shortcutHandlers.get(accelerator);
|
|
331
338
|
if (handlers === undefined) return Desktop;
|
|
332
339
|
handlers.delete(handler);
|
|
333
340
|
if (handlers.size === 0) {
|
|
334
|
-
Desktop.#
|
|
341
|
+
Desktop.#shortcutHandlers.delete(accelerator);
|
|
335
342
|
Desktop.#call("shortcutUnsubscribe", accelerator);
|
|
336
343
|
}
|
|
337
|
-
if (Desktop.#
|
|
344
|
+
if (Desktop.#shortcutHandlers.size === 0) Desktop.#unbindShortcutEvent();
|
|
338
345
|
return Desktop;
|
|
339
346
|
}
|
|
340
347
|
|
|
341
348
|
static #unsubscribeAll() {
|
|
342
|
-
for (const accelerator of [...Desktop.#
|
|
343
|
-
Desktop.#
|
|
349
|
+
for (const accelerator of [...Desktop.#shortcutHandlers.keys()]) {
|
|
350
|
+
Desktop.#shortcutHandlers.delete(accelerator);
|
|
344
351
|
Desktop.#call("shortcutUnsubscribe", accelerator);
|
|
345
352
|
}
|
|
346
353
|
Desktop.#unbindShortcutEvent();
|
|
@@ -349,31 +356,31 @@ class Desktop {
|
|
|
349
356
|
|
|
350
357
|
/** Событие приходит из main: сработала глобальная клавиша */
|
|
351
358
|
static #onShortcutEvent = (accelerator = String()) => {
|
|
352
|
-
const handlers = Desktop.#
|
|
359
|
+
const handlers = Desktop.#shortcutHandlers.get(accelerator);
|
|
353
360
|
if (handlers === undefined) return;
|
|
354
361
|
for (const handler of [...handlers]) handler(accelerator);
|
|
355
362
|
};
|
|
356
363
|
|
|
357
364
|
static #bindShortcutEvent() {
|
|
358
|
-
Desktop.#
|
|
365
|
+
Desktop.#shortcutEventBound = true;
|
|
359
366
|
const services = Desktop.#bridge();
|
|
360
367
|
if (services !== undefined && typeof services.onShortcut === "function") {
|
|
361
|
-
Desktop.#
|
|
368
|
+
Desktop.#shortcutBridgeUnsubscribe = services.onShortcut(Desktop.#onShortcutEvent);
|
|
362
369
|
return;
|
|
363
370
|
}
|
|
364
|
-
const {ipcRenderer} = require("electron");
|
|
371
|
+
const { ipcRenderer } = require("electron");
|
|
365
372
|
ipcRenderer.on(SERVICES_CHANNELS.SHORTCUT_EVENT, Desktop.#ipcShortcutEvent);
|
|
366
373
|
}
|
|
367
374
|
|
|
368
375
|
static #unbindShortcutEvent() {
|
|
369
|
-
if (!Desktop.#
|
|
370
|
-
Desktop.#
|
|
371
|
-
if (Desktop.#
|
|
372
|
-
Desktop.#
|
|
373
|
-
Desktop.#
|
|
376
|
+
if (!Desktop.#shortcutEventBound) return;
|
|
377
|
+
Desktop.#shortcutEventBound = false;
|
|
378
|
+
if (Desktop.#shortcutBridgeUnsubscribe !== undefined) {
|
|
379
|
+
Desktop.#shortcutBridgeUnsubscribe();
|
|
380
|
+
Desktop.#shortcutBridgeUnsubscribe = undefined;
|
|
374
381
|
return;
|
|
375
382
|
}
|
|
376
|
-
const {ipcRenderer} = require("electron");
|
|
383
|
+
const { ipcRenderer } = require("electron");
|
|
377
384
|
ipcRenderer.removeListener(SERVICES_CHANNELS.SHORTCUT_EVENT, Desktop.#ipcShortcutEvent);
|
|
378
385
|
}
|
|
379
386
|
|
|
@@ -382,43 +389,43 @@ class Desktop {
|
|
|
382
389
|
};
|
|
383
390
|
|
|
384
391
|
static #subscribeTheme(listener = () => {}) {
|
|
385
|
-
Desktop.#
|
|
386
|
-
if (!Desktop.#
|
|
392
|
+
Desktop.#themeHandlers.add(listener);
|
|
393
|
+
if (!Desktop.#themeEventBound) Desktop.#bindThemeEvent();
|
|
387
394
|
return () => Desktop.#unsubscribeTheme(listener);
|
|
388
395
|
}
|
|
389
396
|
|
|
390
397
|
static #unsubscribeTheme(listener = () => {}) {
|
|
391
|
-
Desktop.#
|
|
392
|
-
if (Desktop.#
|
|
398
|
+
Desktop.#themeHandlers.delete(listener);
|
|
399
|
+
if (Desktop.#themeHandlers.size === 0) Desktop.#unbindThemeEvent();
|
|
393
400
|
return Desktop;
|
|
394
401
|
}
|
|
395
402
|
|
|
396
403
|
/** Событие приходит из main: тема изменилась (системой или по выбору пользователя) */
|
|
397
404
|
static #onThemeEvent = (theme = String()) => {
|
|
398
|
-
for (const listener of [...Desktop.#
|
|
405
|
+
for (const listener of [...Desktop.#themeHandlers]) listener(theme);
|
|
399
406
|
};
|
|
400
407
|
|
|
401
408
|
static #bindThemeEvent() {
|
|
402
|
-
Desktop.#
|
|
409
|
+
Desktop.#themeEventBound = true;
|
|
403
410
|
const bridge = typeof window === "undefined" ? undefined : window.chui;
|
|
404
411
|
const theme = bridge === undefined ? undefined : bridge.theme;
|
|
405
412
|
if (theme !== undefined && typeof theme.onChange === "function") {
|
|
406
|
-
Desktop.#
|
|
413
|
+
Desktop.#themeBridgeUnsubscribe = theme.onChange(Desktop.#onThemeEvent);
|
|
407
414
|
return;
|
|
408
415
|
}
|
|
409
|
-
const {ipcRenderer} = require("electron");
|
|
416
|
+
const { ipcRenderer } = require("electron");
|
|
410
417
|
ipcRenderer.on(SERVICES_CHANNELS.THEME_EVENT, Desktop.#ipcThemeEvent);
|
|
411
418
|
}
|
|
412
419
|
|
|
413
420
|
static #unbindThemeEvent() {
|
|
414
|
-
if (!Desktop.#
|
|
415
|
-
Desktop.#
|
|
416
|
-
if (Desktop.#
|
|
417
|
-
Desktop.#
|
|
418
|
-
Desktop.#
|
|
421
|
+
if (!Desktop.#themeEventBound) return;
|
|
422
|
+
Desktop.#themeEventBound = false;
|
|
423
|
+
if (Desktop.#themeBridgeUnsubscribe !== undefined) {
|
|
424
|
+
Desktop.#themeBridgeUnsubscribe();
|
|
425
|
+
Desktop.#themeBridgeUnsubscribe = undefined;
|
|
419
426
|
return;
|
|
420
427
|
}
|
|
421
|
-
const {ipcRenderer} = require("electron");
|
|
428
|
+
const { ipcRenderer } = require("electron");
|
|
422
429
|
ipcRenderer.removeListener(SERVICES_CHANNELS.THEME_EVENT, Desktop.#ipcThemeEvent);
|
|
423
430
|
}
|
|
424
431
|
|
|
@@ -427,43 +434,43 @@ class Desktop {
|
|
|
427
434
|
};
|
|
428
435
|
|
|
429
436
|
static #subscribeLocale(listener = () => {}) {
|
|
430
|
-
Desktop.#
|
|
431
|
-
if (!Desktop.#
|
|
437
|
+
Desktop.#localeHandlers.add(listener);
|
|
438
|
+
if (!Desktop.#localeEventBound) Desktop.#bindLocaleEvent();
|
|
432
439
|
return () => Desktop.#unsubscribeLocale(listener);
|
|
433
440
|
}
|
|
434
441
|
|
|
435
442
|
static #unsubscribeLocale(listener = () => {}) {
|
|
436
|
-
Desktop.#
|
|
437
|
-
if (Desktop.#
|
|
443
|
+
Desktop.#localeHandlers.delete(listener);
|
|
444
|
+
if (Desktop.#localeHandlers.size === 0) Desktop.#unbindLocaleEvent();
|
|
438
445
|
return Desktop;
|
|
439
446
|
}
|
|
440
447
|
|
|
441
448
|
/** Событие приходит из main: приложение сменило язык */
|
|
442
449
|
static #onLocaleEvent = (locale = String()) => {
|
|
443
|
-
for (const listener of [...Desktop.#
|
|
450
|
+
for (const listener of [...Desktop.#localeHandlers]) listener(locale);
|
|
444
451
|
};
|
|
445
452
|
|
|
446
453
|
static #bindLocaleEvent() {
|
|
447
|
-
Desktop.#
|
|
454
|
+
Desktop.#localeEventBound = true;
|
|
448
455
|
const bridge = typeof window === "undefined" ? undefined : window.chui;
|
|
449
456
|
const locale = bridge === undefined ? undefined : bridge.locale;
|
|
450
457
|
if (locale !== undefined && typeof locale.onChange === "function") {
|
|
451
|
-
Desktop.#
|
|
458
|
+
Desktop.#localeBridgeUnsubscribe = locale.onChange(Desktop.#onLocaleEvent);
|
|
452
459
|
return;
|
|
453
460
|
}
|
|
454
|
-
const {ipcRenderer} = require("electron");
|
|
461
|
+
const { ipcRenderer } = require("electron");
|
|
455
462
|
ipcRenderer.on(SERVICES_CHANNELS.LOCALE_EVENT, Desktop.#ipcLocaleEvent);
|
|
456
463
|
}
|
|
457
464
|
|
|
458
465
|
static #unbindLocaleEvent() {
|
|
459
|
-
if (!Desktop.#
|
|
460
|
-
Desktop.#
|
|
461
|
-
if (Desktop.#
|
|
462
|
-
Desktop.#
|
|
463
|
-
Desktop.#
|
|
466
|
+
if (!Desktop.#localeEventBound) return;
|
|
467
|
+
Desktop.#localeEventBound = false;
|
|
468
|
+
if (Desktop.#localeBridgeUnsubscribe !== undefined) {
|
|
469
|
+
Desktop.#localeBridgeUnsubscribe();
|
|
470
|
+
Desktop.#localeBridgeUnsubscribe = undefined;
|
|
464
471
|
return;
|
|
465
472
|
}
|
|
466
|
-
const {ipcRenderer} = require("electron");
|
|
473
|
+
const { ipcRenderer } = require("electron");
|
|
467
474
|
ipcRenderer.removeListener(SERVICES_CHANNELS.LOCALE_EVENT, Desktop.#ipcLocaleEvent);
|
|
468
475
|
}
|
|
469
476
|
|
|
@@ -472,41 +479,41 @@ class Desktop {
|
|
|
472
479
|
};
|
|
473
480
|
|
|
474
481
|
static #subscribeHistory(listener = () => {}) {
|
|
475
|
-
Desktop.#
|
|
476
|
-
if (!Desktop.#
|
|
482
|
+
Desktop.#historyHandlers.add(listener);
|
|
483
|
+
if (!Desktop.#historyEventBound) Desktop.#bindHistoryEvent();
|
|
477
484
|
return () => Desktop.#unsubscribeHistory(listener);
|
|
478
485
|
}
|
|
479
486
|
|
|
480
487
|
static #unsubscribeHistory(listener = () => {}) {
|
|
481
|
-
Desktop.#
|
|
482
|
-
if (Desktop.#
|
|
488
|
+
Desktop.#historyHandlers.delete(listener);
|
|
489
|
+
if (Desktop.#historyHandlers.size === 0) Desktop.#unbindHistoryEvent();
|
|
483
490
|
return Desktop;
|
|
484
491
|
}
|
|
485
492
|
|
|
486
493
|
static #onHistoryEvent = (items = []) => {
|
|
487
|
-
for (const listener of [...Desktop.#
|
|
494
|
+
for (const listener of [...Desktop.#historyHandlers]) listener(items);
|
|
488
495
|
};
|
|
489
496
|
|
|
490
497
|
static #bindHistoryEvent() {
|
|
491
|
-
Desktop.#
|
|
498
|
+
Desktop.#historyEventBound = true;
|
|
492
499
|
const services = Desktop.#bridge();
|
|
493
500
|
if (services !== undefined && typeof services.onClipboardHistory === "function") {
|
|
494
|
-
Desktop.#
|
|
501
|
+
Desktop.#historyBridgeUnsubscribe = services.onClipboardHistory(Desktop.#onHistoryEvent);
|
|
495
502
|
return;
|
|
496
503
|
}
|
|
497
|
-
const {ipcRenderer} = require("electron");
|
|
504
|
+
const { ipcRenderer } = require("electron");
|
|
498
505
|
ipcRenderer.on(SERVICES_CHANNELS.CLIPBOARD_HISTORY_EVENT, Desktop.#ipcHistoryEvent);
|
|
499
506
|
}
|
|
500
507
|
|
|
501
508
|
static #unbindHistoryEvent() {
|
|
502
|
-
if (!Desktop.#
|
|
503
|
-
Desktop.#
|
|
504
|
-
if (Desktop.#
|
|
505
|
-
Desktop.#
|
|
506
|
-
Desktop.#
|
|
509
|
+
if (!Desktop.#historyEventBound) return;
|
|
510
|
+
Desktop.#historyEventBound = false;
|
|
511
|
+
if (Desktop.#historyBridgeUnsubscribe !== undefined) {
|
|
512
|
+
Desktop.#historyBridgeUnsubscribe();
|
|
513
|
+
Desktop.#historyBridgeUnsubscribe = undefined;
|
|
507
514
|
return;
|
|
508
515
|
}
|
|
509
|
-
const {ipcRenderer} = require("electron");
|
|
516
|
+
const { ipcRenderer } = require("electron");
|
|
510
517
|
ipcRenderer.removeListener(SERVICES_CHANNELS.CLIPBOARD_HISTORY_EVENT, Desktop.#ipcHistoryEvent);
|
|
511
518
|
}
|
|
512
519
|
|
|
@@ -515,4 +522,4 @@ class Desktop {
|
|
|
515
522
|
};
|
|
516
523
|
}
|
|
517
524
|
|
|
518
|
-
exports.Desktop = Desktop
|
|
525
|
+
exports.Desktop = Desktop;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {setStyles} = require("../chui_functions");
|
|
1
|
+
const { setStyles } = require("../chui_functions");
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Перестановка элементов внутри контейнера: строки списка, карточки, пункты меню.
|
|
@@ -27,35 +27,38 @@ const {setStyles} = require("../chui_functions");
|
|
|
27
27
|
class Sortable {
|
|
28
28
|
static AXIS = {
|
|
29
29
|
Y: "y",
|
|
30
|
-
X: "x"
|
|
30
|
+
X: "x",
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
#container = undefined;
|
|
34
|
-
#
|
|
35
|
-
#
|
|
34
|
+
#itemSelector = undefined;
|
|
35
|
+
#handleSelector = undefined;
|
|
36
36
|
#axis = Sortable.AXIS.Y;
|
|
37
|
-
#
|
|
37
|
+
#onReorder = undefined;
|
|
38
38
|
#enabled = true;
|
|
39
39
|
#source = undefined;
|
|
40
40
|
#before = undefined;
|
|
41
|
-
#
|
|
41
|
+
#orderBefore = [];
|
|
42
42
|
// Точка отсчёта отмены: сюда возвращает cancel(), и только здесь, а не в каждой перестановке
|
|
43
43
|
#baseline = [];
|
|
44
44
|
#bound = false;
|
|
45
45
|
|
|
46
|
-
constructor(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
constructor(
|
|
47
|
+
container = new HTMLElement(),
|
|
48
|
+
options = {
|
|
49
|
+
itemSelector: String(),
|
|
50
|
+
handleSelector: String(),
|
|
51
|
+
axis: String(),
|
|
52
|
+
enabled: Boolean(),
|
|
53
|
+
onReorder: undefined,
|
|
54
|
+
}
|
|
55
|
+
) {
|
|
53
56
|
setStyles(__dirname + "/styles.css", "chUiJS_Sortable");
|
|
54
57
|
this.#container = container;
|
|
55
|
-
this.#
|
|
56
|
-
this.#
|
|
58
|
+
this.#itemSelector = options.itemSelector === undefined ? "*" : options.itemSelector;
|
|
59
|
+
this.#handleSelector = options.handleSelector;
|
|
57
60
|
this.#axis = options.axis === undefined ? Sortable.AXIS.Y : options.axis;
|
|
58
|
-
this.#
|
|
61
|
+
this.#onReorder = options.onReorder;
|
|
59
62
|
this.#enabled = options.enabled !== false;
|
|
60
63
|
this.#container.addEventListener("dragstart", this.#onDragStart);
|
|
61
64
|
this.#container.addEventListener("dragover", this.#onDragOver);
|
|
@@ -86,7 +89,7 @@ class Sortable {
|
|
|
86
89
|
|
|
87
90
|
/** Порядок изменился после последней перестановки (или с момента refresh) */
|
|
88
91
|
isChanged() {
|
|
89
|
-
return !Sortable.#sameOrder(this.#
|
|
92
|
+
return !Sortable.#sameOrder(this.#orderBefore, this.#items());
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
// SET
|
|
@@ -105,8 +108,8 @@ class Sortable {
|
|
|
105
108
|
if (item.getAttribute("tabindex") === null) item.setAttribute("tabindex", "0");
|
|
106
109
|
item.classList.add("sortable_item");
|
|
107
110
|
}
|
|
108
|
-
this.#
|
|
109
|
-
this.#baseline = [...this.#
|
|
111
|
+
this.#orderBefore = this.#items();
|
|
112
|
+
this.#baseline = [...this.#orderBefore];
|
|
110
113
|
return this;
|
|
111
114
|
}
|
|
112
115
|
|
|
@@ -115,7 +118,7 @@ class Sortable {
|
|
|
115
118
|
// Возврат идёт к точке отсчёта refresh(), а не к порядку последней перестановки: иначе
|
|
116
119
|
// отмена после перетаскивания ничего бы не делала (порядок сверялся бы сам с собой)
|
|
117
120
|
for (const item of this.#baseline) this.#container.appendChild(item);
|
|
118
|
-
this.#
|
|
121
|
+
this.#orderBefore = this.#items();
|
|
119
122
|
return this;
|
|
120
123
|
}
|
|
121
124
|
|
|
@@ -137,15 +140,15 @@ class Sortable {
|
|
|
137
140
|
// === ВНУТРЕННЕЕ ===
|
|
138
141
|
// Только прямые дети контейнера: вложенные списки сортируются своим Sortable
|
|
139
142
|
#items() {
|
|
140
|
-
return [...this.#container.children].filter((child) => child.matches(this.#
|
|
143
|
+
return [...this.#container.children].filter((child) => child.matches(this.#itemSelector));
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
#itemFromEvent(event) {
|
|
144
147
|
const target = event.target instanceof Element ? event.target : null;
|
|
145
148
|
if (target === null) return null;
|
|
146
|
-
const item = target.closest(this.#
|
|
149
|
+
const item = target.closest(this.#itemSelector);
|
|
147
150
|
if (item === null || item.parentElement !== this.#container) return null;
|
|
148
|
-
if (this.#
|
|
151
|
+
if (this.#handleSelector !== undefined && target.closest(this.#handleSelector) === null) return null;
|
|
149
152
|
return item;
|
|
150
153
|
}
|
|
151
154
|
|
|
@@ -170,9 +173,9 @@ class Sortable {
|
|
|
170
173
|
const before = this.#before;
|
|
171
174
|
this.#source = undefined;
|
|
172
175
|
this.#before = undefined;
|
|
173
|
-
if (Sortable.#sameOrder(this.#
|
|
174
|
-
this.#
|
|
175
|
-
if (this.#
|
|
176
|
+
if (Sortable.#sameOrder(this.#orderBefore, this.#items())) return;
|
|
177
|
+
this.#orderBefore = this.#items();
|
|
178
|
+
if (this.#onReorder !== undefined) this.#onReorder(this.getOrder(), { source: source, before: before });
|
|
176
179
|
}
|
|
177
180
|
|
|
178
181
|
static #sameOrder(left = [], right = []) {
|
|
@@ -218,7 +221,9 @@ class Sortable {
|
|
|
218
221
|
const forward = this.#axis === Sortable.AXIS.X ? "ArrowRight" : "ArrowDown";
|
|
219
222
|
if (event.key !== backward && event.key !== forward) return;
|
|
220
223
|
const items = this.#items();
|
|
221
|
-
const current = items.findIndex(
|
|
224
|
+
const current = items.findIndex(
|
|
225
|
+
(item) => item === document.activeElement || item.contains(document.activeElement)
|
|
226
|
+
);
|
|
222
227
|
if (current === -1) return;
|
|
223
228
|
const next = event.key === backward ? current - 1 : current + 1;
|
|
224
229
|
if (next < 0 || next >= items.length) return;
|
|
@@ -235,4 +240,4 @@ class Sortable {
|
|
|
235
240
|
};
|
|
236
241
|
}
|
|
237
242
|
|
|
238
|
-
exports.Sortable = Sortable
|
|
243
|
+
exports.Sortable = Sortable;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Общие тексты берутся из словаря текущего языка (`I18n`), поэтому и они переводятся
|
|
16
16
|
* вместе с интерфейсом; свои тексты поля (`messages`) задаются строками и не переводятся.
|
|
17
17
|
*/
|
|
18
|
-
const {I18n} = require("../chui_i18n/chui_i18n");
|
|
18
|
+
const { I18n } = require("../chui_i18n/chui_i18n");
|
|
19
19
|
|
|
20
20
|
/** Ключ словаря для каждого правила: значения-параметры подставляет `I18n.t` */
|
|
21
21
|
const MESSAGE_KEYS = {
|
|
@@ -25,7 +25,7 @@ const MESSAGE_KEYS = {
|
|
|
25
25
|
minLength: "validate.minLength",
|
|
26
26
|
maxLength: "validate.maxLength",
|
|
27
27
|
pattern: "validate.pattern",
|
|
28
|
-
email: "validate.email"
|
|
28
|
+
email: "validate.email",
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
// Сборник общих сообщений остаётся доступен как прежде, но текст берётся из текущей локали:
|
|
@@ -34,7 +34,7 @@ const DEFAULT_MESSAGES = {};
|
|
|
34
34
|
for (const rule of Object.keys(MESSAGE_KEYS)) {
|
|
35
35
|
Object.defineProperty(DEFAULT_MESSAGES, rule, {
|
|
36
36
|
enumerable: true,
|
|
37
|
-
get: () => I18n.t(MESSAGE_KEYS[rule])
|
|
37
|
+
get: () => I18n.t(MESSAGE_KEYS[rule]),
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -63,7 +63,10 @@ const fail = (rule, rules) => ({ valid: false, rule: rule, message: messageFor(r
|
|
|
63
63
|
|
|
64
64
|
/** Проверка значения по правилам: {valid, rule?, message?} */
|
|
65
65
|
function check(value, rules = {}) {
|
|
66
|
-
const empty =
|
|
66
|
+
const empty =
|
|
67
|
+
typeof value === "boolean"
|
|
68
|
+
? value === false
|
|
69
|
+
: String(value === undefined || value === null ? "" : value).trim() === "";
|
|
67
70
|
if (empty) {
|
|
68
71
|
return rules.required === true ? fail("required", rules) : { valid: true };
|
|
69
72
|
}
|
|
@@ -73,9 +76,9 @@ function check(value, rules = {}) {
|
|
|
73
76
|
if (rules.max !== undefined && (Number.isNaN(number) || number > rules.max)) return fail("max", rules);
|
|
74
77
|
if (rules.minLength !== undefined && text.length < rules.minLength) return fail("minLength", rules);
|
|
75
78
|
if (rules.maxLength !== undefined && text.length > rules.maxLength) return fail("maxLength", rules);
|
|
76
|
-
const
|
|
77
|
-
const pattern =
|
|
78
|
-
if (pattern !== undefined && !new RegExp(pattern).test(text)) return fail(
|
|
79
|
+
const isEmail = rules.type === "email";
|
|
80
|
+
const pattern = isEmail ? EMAIL_PATTERN : rules.pattern;
|
|
81
|
+
if (pattern !== undefined && !new RegExp(pattern).test(text)) return fail(isEmail ? "email" : "pattern", rules);
|
|
79
82
|
if (typeof rules.validate === "function") {
|
|
80
83
|
const custom = rules.validate(value);
|
|
81
84
|
if (custom !== undefined && custom !== null && custom !== true) {
|