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
|
-
const {setStyles} = require("../../modules/chui_functions");
|
|
2
|
-
const {Validate} = require("../../modules/chui_validate/chui_validate");
|
|
3
|
-
const {SegmentedControl} = require("../chui_segmented_control/segmented_control");
|
|
4
|
-
const {Select} = require("../chui_inputs/chui_select_box/select_box");
|
|
5
|
-
const {TextInput} = require("../chui_inputs/chui_text/text");
|
|
6
|
-
const {NumberInput} = require("../chui_inputs/chui_number/number");
|
|
7
|
-
const {DateInput} = require("../chui_inputs/chui_date/date");
|
|
8
|
-
const {I18n} = require("../../modules/chui_i18n/chui_i18n");
|
|
9
|
-
const {Icon, Icons} = require("../chui_icons/icons");
|
|
1
|
+
const { setStyles } = require("../../modules/chui_functions");
|
|
2
|
+
const { Validate } = require("../../modules/chui_validate/chui_validate");
|
|
3
|
+
const { SegmentedControl } = require("../chui_segmented_control/segmented_control");
|
|
4
|
+
const { Select } = require("../chui_inputs/chui_select_box/select_box");
|
|
5
|
+
const { TextInput } = require("../chui_inputs/chui_text/text");
|
|
6
|
+
const { NumberInput } = require("../chui_inputs/chui_number/number");
|
|
7
|
+
const { DateInput } = require("../chui_inputs/chui_date/date");
|
|
8
|
+
const { I18n } = require("../../modules/chui_i18n/chui_i18n");
|
|
9
|
+
const { Icon, Icons } = require("../chui_icons/icons");
|
|
10
10
|
|
|
11
11
|
/** Соединение условий внутри группы */
|
|
12
|
-
const COMBINATOR = {AND: "and", OR: "or"};
|
|
12
|
+
const COMBINATOR = { AND: "and", OR: "or" };
|
|
13
13
|
/** Типы полей: от типа зависят и операторы, и вид поля значения */
|
|
14
|
-
const TYPE = {STRING: "string", NUMBER: "number", BOOLEAN: "boolean", DATE: "date", SELECT: "select"};
|
|
14
|
+
const TYPE = { STRING: "string", NUMBER: "number", BOOLEAN: "boolean", DATE: "date", SELECT: "select" };
|
|
15
15
|
const TYPES = [TYPE.STRING, TYPE.NUMBER, TYPE.BOOLEAN, TYPE.DATE, TYPE.SELECT];
|
|
16
16
|
/** Операторы сравнения */
|
|
17
17
|
const OPERATOR = {
|
|
@@ -26,7 +26,7 @@ const OPERATOR = {
|
|
|
26
26
|
LESS: "less",
|
|
27
27
|
LESS_OR_EQUAL: "less_or_equal",
|
|
28
28
|
IS_EMPTY: "is_empty",
|
|
29
|
-
IS_NOT_EMPTY: "is_not_empty"
|
|
29
|
+
IS_NOT_EMPTY: "is_not_empty",
|
|
30
30
|
};
|
|
31
31
|
/** Операторы словами — для подписей контролов и `toText()`: внутренние ключи словаря */
|
|
32
32
|
const OPERATOR_KEYS = {
|
|
@@ -41,23 +41,46 @@ const OPERATOR_KEYS = {
|
|
|
41
41
|
less: "queryBuilder.operator.less",
|
|
42
42
|
less_or_equal: "queryBuilder.operator.lessOrEqual",
|
|
43
43
|
is_empty: "queryBuilder.operator.isEmpty",
|
|
44
|
-
is_not_empty: "queryBuilder.operator.isNotEmpty"
|
|
44
|
+
is_not_empty: "queryBuilder.operator.isNotEmpty",
|
|
45
45
|
};
|
|
46
46
|
// Публичная таблица отдаёт уже переведённый текст: геттеры читают словарь в момент обращения
|
|
47
47
|
const OPERATOR_TITLES = {};
|
|
48
48
|
for (const key of Object.keys(OPERATOR_KEYS)) {
|
|
49
|
-
Object.defineProperty(OPERATOR_TITLES, key, {enumerable: true, get: () => I18n.t(OPERATOR_KEYS[key])});
|
|
49
|
+
Object.defineProperty(OPERATOR_TITLES, key, { enumerable: true, get: () => I18n.t(OPERATOR_KEYS[key]) });
|
|
50
50
|
}
|
|
51
51
|
/** Операторы по типу поля: «содержит» у числа и «больше» у логического смысла не имеют */
|
|
52
52
|
const OPERATORS_BY_TYPE = {
|
|
53
|
-
string: [
|
|
54
|
-
OPERATOR.
|
|
55
|
-
|
|
56
|
-
OPERATOR.
|
|
57
|
-
|
|
58
|
-
OPERATOR.
|
|
53
|
+
string: [
|
|
54
|
+
OPERATOR.EQUALS,
|
|
55
|
+
OPERATOR.NOT_EQUALS,
|
|
56
|
+
OPERATOR.CONTAINS,
|
|
57
|
+
OPERATOR.NOT_CONTAINS,
|
|
58
|
+
OPERATOR.STARTS_WITH,
|
|
59
|
+
OPERATOR.ENDS_WITH,
|
|
60
|
+
OPERATOR.IS_EMPTY,
|
|
61
|
+
OPERATOR.IS_NOT_EMPTY,
|
|
62
|
+
],
|
|
63
|
+
number: [
|
|
64
|
+
OPERATOR.EQUALS,
|
|
65
|
+
OPERATOR.NOT_EQUALS,
|
|
66
|
+
OPERATOR.GREATER,
|
|
67
|
+
OPERATOR.GREATER_OR_EQUAL,
|
|
68
|
+
OPERATOR.LESS,
|
|
69
|
+
OPERATOR.LESS_OR_EQUAL,
|
|
70
|
+
OPERATOR.IS_EMPTY,
|
|
71
|
+
OPERATOR.IS_NOT_EMPTY,
|
|
72
|
+
],
|
|
73
|
+
date: [
|
|
74
|
+
OPERATOR.EQUALS,
|
|
75
|
+
OPERATOR.GREATER,
|
|
76
|
+
OPERATOR.GREATER_OR_EQUAL,
|
|
77
|
+
OPERATOR.LESS,
|
|
78
|
+
OPERATOR.LESS_OR_EQUAL,
|
|
79
|
+
OPERATOR.IS_EMPTY,
|
|
80
|
+
OPERATOR.IS_NOT_EMPTY,
|
|
81
|
+
],
|
|
59
82
|
boolean: [OPERATOR.EQUALS, OPERATOR.NOT_EQUALS],
|
|
60
|
-
select: [OPERATOR.EQUALS, OPERATOR.NOT_EQUALS, OPERATOR.IS_EMPTY, OPERATOR.IS_NOT_EMPTY]
|
|
83
|
+
select: [OPERATOR.EQUALS, OPERATOR.NOT_EQUALS, OPERATOR.IS_EMPTY, OPERATOR.IS_NOT_EMPTY],
|
|
61
84
|
};
|
|
62
85
|
/** Операторы, которым значение не нужно: у них поле значения не рисуется */
|
|
63
86
|
const VALUELESS = new Set([OPERATOR.IS_EMPTY, OPERATOR.IS_NOT_EMPTY]);
|
|
@@ -143,21 +166,23 @@ class QueryBuilder {
|
|
|
143
166
|
#label_text = undefined;
|
|
144
167
|
#empty_text = undefined;
|
|
145
168
|
|
|
146
|
-
constructor(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
169
|
+
constructor(
|
|
170
|
+
options = {
|
|
171
|
+
id: String(),
|
|
172
|
+
name: String(),
|
|
173
|
+
title: String(),
|
|
174
|
+
label: String(),
|
|
175
|
+
fields: Array(),
|
|
176
|
+
value: undefined,
|
|
177
|
+
maxDepth: Number(),
|
|
178
|
+
emptyText: String(),
|
|
179
|
+
required: Boolean(),
|
|
180
|
+
messages: Object(),
|
|
181
|
+
disabled: Boolean(),
|
|
182
|
+
changeListener: undefined,
|
|
183
|
+
onChange: undefined,
|
|
184
|
+
}
|
|
185
|
+
) {
|
|
161
186
|
setStyles(__dirname + "/styles.css", "chUiJS_QueryBuilder");
|
|
162
187
|
QueryBuilder.#counter += 1;
|
|
163
188
|
this.#id = options.id === undefined ? `chui_query_builder_${QueryBuilder.#counter}` : options.id;
|
|
@@ -187,14 +212,27 @@ class QueryBuilder {
|
|
|
187
212
|
if (options.value === undefined) this.clear(true);
|
|
188
213
|
else this.setValue(options.value);
|
|
189
214
|
// Правила формы и поля читают пустой запрос как пустое значение: за него отвечает required
|
|
190
|
-
Validate.installField(
|
|
215
|
+
Validate.installField(
|
|
216
|
+
this,
|
|
217
|
+
options,
|
|
218
|
+
this.#root,
|
|
219
|
+
this.#error,
|
|
220
|
+
() => (this.isEmpty() ? "" : this.getText()),
|
|
221
|
+
this.#tree
|
|
222
|
+
);
|
|
191
223
|
const base_validate = this.validate;
|
|
192
224
|
this.validate = () => {
|
|
193
225
|
const result = base_validate();
|
|
194
226
|
if (result.valid === false) return result;
|
|
195
|
-
const empty = this.#rules().find(
|
|
227
|
+
const empty = this.#rules().find(
|
|
228
|
+
(rule) => this.#needsValue(rule.operator) && this.#isEmptyValue(rule.value)
|
|
229
|
+
);
|
|
196
230
|
if (empty === undefined) return result;
|
|
197
|
-
return {
|
|
231
|
+
return {
|
|
232
|
+
valid: false,
|
|
233
|
+
rule: "query",
|
|
234
|
+
message: I18n.t("queryBuilder.valueMissing", { index: this.#indexOfRule(empty.id) }),
|
|
235
|
+
};
|
|
198
236
|
};
|
|
199
237
|
this.setDisabled(options.disabled === true);
|
|
200
238
|
if (options.changeListener !== undefined) this.addChangeListener(options.changeListener);
|
|
@@ -220,7 +258,9 @@ class QueryBuilder {
|
|
|
220
258
|
|
|
221
259
|
/** Описания полей: копии того, что задано в `setFields()` */
|
|
222
260
|
getFields() {
|
|
223
|
-
return this.#fields.map((field) =>
|
|
261
|
+
return this.#fields.map((field) =>
|
|
262
|
+
Object.assign({}, field, { options: field.options.map((option) => Object.assign({}, option)) })
|
|
263
|
+
);
|
|
224
264
|
}
|
|
225
265
|
|
|
226
266
|
/** Дерево запроса: `{id, combinator, children}`, у условий есть `id` */
|
|
@@ -235,7 +275,7 @@ class QueryBuilder {
|
|
|
235
275
|
|
|
236
276
|
/** Плоский список условий `[{field, operator, value}]` — в порядке обхода дерева */
|
|
237
277
|
getConditions() {
|
|
238
|
-
return this.#rules().map((rule) => ({field: rule.field, operator: rule.operator, value: rule.value}));
|
|
278
|
+
return this.#rules().map((rule) => ({ field: rule.field, operator: rule.operator, value: rule.value }));
|
|
239
279
|
}
|
|
240
280
|
|
|
241
281
|
/** Идентификаторы условий в порядке обхода — для `removeRule()` и `focus()` */
|
|
@@ -328,10 +368,12 @@ class QueryBuilder {
|
|
|
328
368
|
key: String(field.key),
|
|
329
369
|
label: field.label === undefined ? String(field.key) : String(field.label),
|
|
330
370
|
type: TYPES.includes(type) ? type : TYPE.STRING,
|
|
331
|
-
options: Array.isArray(field.options)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
371
|
+
options: Array.isArray(field.options)
|
|
372
|
+
? field.options.map((option) => ({
|
|
373
|
+
value: String(option.value),
|
|
374
|
+
title: option.title === undefined ? String(option.value) : String(option.title),
|
|
375
|
+
}))
|
|
376
|
+
: [],
|
|
335
377
|
};
|
|
336
378
|
});
|
|
337
379
|
for (const rule of this.#rules()) {
|
|
@@ -374,7 +416,9 @@ class QueryBuilder {
|
|
|
374
416
|
if (group.combinator === next) return this;
|
|
375
417
|
group.combinator = next;
|
|
376
418
|
this.#render();
|
|
377
|
-
this.#announce(
|
|
419
|
+
this.#announce(
|
|
420
|
+
I18n.t("queryBuilder.connectionChanged", { combinator: I18n.t(QueryBuilder.#combinatorTitle(next)) })
|
|
421
|
+
);
|
|
378
422
|
this.#notify();
|
|
379
423
|
return this;
|
|
380
424
|
}
|
|
@@ -391,7 +435,7 @@ class QueryBuilder {
|
|
|
391
435
|
const rule = this.#emptyRule(field);
|
|
392
436
|
group.children.push(rule);
|
|
393
437
|
this.#render();
|
|
394
|
-
this.#announce(I18n.t("queryBuilder.ruleAdded", {index: this.#indexOfRule(rule.id)}));
|
|
438
|
+
this.#announce(I18n.t("queryBuilder.ruleAdded", { index: this.#indexOfRule(rule.id) }));
|
|
395
439
|
this.#refreshErrors();
|
|
396
440
|
this.#notify();
|
|
397
441
|
return rule.id;
|
|
@@ -412,11 +456,13 @@ class QueryBuilder {
|
|
|
412
456
|
kind: "group",
|
|
413
457
|
id: this.#nextId("group"),
|
|
414
458
|
combinator: COMBINATOR.AND,
|
|
415
|
-
children: [this.#emptyRule(field)]
|
|
459
|
+
children: [this.#emptyRule(field)],
|
|
416
460
|
};
|
|
417
461
|
group.children.push(nested);
|
|
418
462
|
this.#render();
|
|
419
|
-
this.#announce(
|
|
463
|
+
this.#announce(
|
|
464
|
+
I18n.t("queryBuilder.groupAdded", { index: this.#groups().findIndex((item) => item.id === nested.id) + 1 })
|
|
465
|
+
);
|
|
420
466
|
this.#refreshErrors();
|
|
421
467
|
this.#notify();
|
|
422
468
|
return nested.id;
|
|
@@ -428,7 +474,7 @@ class QueryBuilder {
|
|
|
428
474
|
if (index === 0) return this;
|
|
429
475
|
this.#removeNode(id);
|
|
430
476
|
this.#render();
|
|
431
|
-
this.#announce(I18n.t("queryBuilder.ruleRemoved", {index: index}));
|
|
477
|
+
this.#announce(I18n.t("queryBuilder.ruleRemoved", { index: index }));
|
|
432
478
|
this.#refreshErrors();
|
|
433
479
|
this.#notify();
|
|
434
480
|
return this;
|
|
@@ -441,7 +487,7 @@ class QueryBuilder {
|
|
|
441
487
|
if (index === -1) return this;
|
|
442
488
|
this.#removeNode(id);
|
|
443
489
|
this.#render();
|
|
444
|
-
this.#announce(I18n.t("queryBuilder.groupRemoved", {index: index + 1}));
|
|
490
|
+
this.#announce(I18n.t("queryBuilder.groupRemoved", { index: index + 1 }));
|
|
445
491
|
this.#refreshErrors();
|
|
446
492
|
this.#notify();
|
|
447
493
|
return this;
|
|
@@ -449,7 +495,7 @@ class QueryBuilder {
|
|
|
449
495
|
|
|
450
496
|
/** Убрать все условия и группы: остаётся пустой корень */
|
|
451
497
|
clear(silent = false) {
|
|
452
|
-
this.#value = {kind: "group", id: this.#nextId("group"), combinator: COMBINATOR.AND, children: []};
|
|
498
|
+
this.#value = { kind: "group", id: this.#nextId("group"), combinator: COMBINATOR.AND, children: [] };
|
|
453
499
|
this.#render();
|
|
454
500
|
if (silent === false) this.#notify();
|
|
455
501
|
return this;
|
|
@@ -472,9 +518,10 @@ class QueryBuilder {
|
|
|
472
518
|
focus(id = undefined) {
|
|
473
519
|
const rules = this.#rules();
|
|
474
520
|
const rule = id === undefined ? rules[0] : rules.find((item) => item.id === id);
|
|
475
|
-
const selector =
|
|
476
|
-
|
|
477
|
-
|
|
521
|
+
const selector =
|
|
522
|
+
rule === undefined
|
|
523
|
+
? "query_builder_rule .query_builder_field input"
|
|
524
|
+
: `query_builder_rule[data-id="${CSS.escape(rule.id)}"] .query_builder_field input`;
|
|
478
525
|
const node = this.#tree.querySelector(selector);
|
|
479
526
|
if (node !== null) node.focus();
|
|
480
527
|
return this;
|
|
@@ -525,7 +572,7 @@ class QueryBuilder {
|
|
|
525
572
|
id: this.#nextId("rule"),
|
|
526
573
|
field: field.key,
|
|
527
574
|
operator: OPERATORS_BY_TYPE[field.type][0],
|
|
528
|
-
value: undefined
|
|
575
|
+
value: undefined,
|
|
529
576
|
};
|
|
530
577
|
}
|
|
531
578
|
|
|
@@ -534,7 +581,7 @@ class QueryBuilder {
|
|
|
534
581
|
const found = this.#fields.find((field) => field.key === key);
|
|
535
582
|
if (found !== undefined) return found;
|
|
536
583
|
return this.#fields[0] === undefined
|
|
537
|
-
? {key: String(key), label: String(key), type: TYPE.STRING, options: []}
|
|
584
|
+
? { key: String(key), label: String(key), type: TYPE.STRING, options: [] }
|
|
538
585
|
: this.#fields[0];
|
|
539
586
|
}
|
|
540
587
|
|
|
@@ -545,7 +592,7 @@ class QueryBuilder {
|
|
|
545
592
|
kind: "group",
|
|
546
593
|
id: typeof source.id === "string" ? source.id : this.#nextId("group"),
|
|
547
594
|
combinator: source.combinator === COMBINATOR.OR ? COMBINATOR.OR : COMBINATOR.AND,
|
|
548
|
-
children: []
|
|
595
|
+
children: [],
|
|
549
596
|
};
|
|
550
597
|
const children = Array.isArray(source.children) ? source.children : [];
|
|
551
598
|
for (const child of children) {
|
|
@@ -563,7 +610,7 @@ class QueryBuilder {
|
|
|
563
610
|
id: typeof child.id === "string" ? child.id : this.#nextId("rule"),
|
|
564
611
|
field: field.key,
|
|
565
612
|
operator: operators.includes(child.operator) ? child.operator : operators[0],
|
|
566
|
-
value: child.value
|
|
613
|
+
value: child.value,
|
|
567
614
|
});
|
|
568
615
|
}
|
|
569
616
|
return group;
|
|
@@ -573,9 +620,11 @@ class QueryBuilder {
|
|
|
573
620
|
return {
|
|
574
621
|
id: group.id,
|
|
575
622
|
combinator: group.combinator,
|
|
576
|
-
children: group.children.map((child) =>
|
|
577
|
-
|
|
578
|
-
|
|
623
|
+
children: group.children.map((child) =>
|
|
624
|
+
child.kind === "group"
|
|
625
|
+
? QueryBuilder.#describeGroup(child)
|
|
626
|
+
: { id: child.id, field: child.field, operator: child.operator, value: child.value }
|
|
627
|
+
),
|
|
579
628
|
};
|
|
580
629
|
}
|
|
581
630
|
|
|
@@ -630,7 +679,7 @@ class QueryBuilder {
|
|
|
630
679
|
}
|
|
631
680
|
return undefined;
|
|
632
681
|
};
|
|
633
|
-
return this.#value === undefined ? 1 : walk(this.#value, 1) ?? 1;
|
|
682
|
+
return this.#value === undefined ? 1 : (walk(this.#value, 1) ?? 1);
|
|
634
683
|
}
|
|
635
684
|
|
|
636
685
|
/** Номер условия в порядке обхода; 0 — условия с таким `id` нет */
|
|
@@ -653,12 +702,13 @@ class QueryBuilder {
|
|
|
653
702
|
let mark = undefined;
|
|
654
703
|
if (active !== null && active !== undefined && this.#tree.contains(active)) {
|
|
655
704
|
const owner = active.closest("query_builder_rule, query_builder_group");
|
|
656
|
-
if (owner !== null)
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
705
|
+
if (owner !== null)
|
|
706
|
+
mark = {
|
|
707
|
+
owner: owner.dataset.id,
|
|
708
|
+
control: QueryBuilder.#controlMark(active),
|
|
709
|
+
// Раскрытый список должен остаться раскрытым, закрытый — закрытым
|
|
710
|
+
open: active.getAttribute("aria-expanded") === "true",
|
|
711
|
+
};
|
|
662
712
|
}
|
|
663
713
|
this.#destroyControls();
|
|
664
714
|
this.#tree.innerHTML = "";
|
|
@@ -705,7 +755,8 @@ class QueryBuilder {
|
|
|
705
755
|
* (три `Select` в строке), поэтому контрол ищется вместе с обёрткой условия.
|
|
706
756
|
*/
|
|
707
757
|
static #controlMark(node = Object()) {
|
|
708
|
-
if (node.tagName === "SEGMENTED_OPTION")
|
|
758
|
+
if (node.tagName === "SEGMENTED_OPTION")
|
|
759
|
+
return `segmented_option[data-value="${CSS.escape(node.dataset.value)}"]`;
|
|
709
760
|
const list = [...node.classList];
|
|
710
761
|
const own = list.length > 0 ? `.${CSS.escape(list[0])}` : node.tagName.toLowerCase();
|
|
711
762
|
const holder = node.closest(".query_builder_field, .query_builder_operator, .query_builder_value");
|
|
@@ -720,10 +771,16 @@ class QueryBuilder {
|
|
|
720
771
|
node.dataset.id = group.id;
|
|
721
772
|
node.style.setProperty("--query_builder_depth", String(depth));
|
|
722
773
|
node.setAttribute("role", "group");
|
|
723
|
-
node.setAttribute(
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
774
|
+
node.setAttribute(
|
|
775
|
+
"aria-label",
|
|
776
|
+
I18n.t("queryBuilder.groupAria", {
|
|
777
|
+
name:
|
|
778
|
+
depth === 0
|
|
779
|
+
? I18n.t("queryBuilder.conditions")
|
|
780
|
+
: I18n.t("queryBuilder.nestedGroup", { depth: depth }),
|
|
781
|
+
combinator: I18n.t(QueryBuilder.#combinatorTitle(group.combinator)),
|
|
782
|
+
})
|
|
783
|
+
);
|
|
727
784
|
node.appendChild(this.#groupHead(group, depth));
|
|
728
785
|
node.appendChild(this.#groupChildren(group, depth));
|
|
729
786
|
node.appendChild(this.#groupFoot(group, depth));
|
|
@@ -735,14 +792,17 @@ class QueryBuilder {
|
|
|
735
792
|
head.className = "query_builder_group_head";
|
|
736
793
|
const combinator = new SegmentedControl({
|
|
737
794
|
id: `${group.id}_combinator`,
|
|
738
|
-
label:
|
|
795
|
+
label:
|
|
796
|
+
depth === 0
|
|
797
|
+
? I18n.t("queryBuilder.connection")
|
|
798
|
+
: I18n.t("queryBuilder.connectionOfGroup", { depth: depth }),
|
|
739
799
|
size: SegmentedControl.SIZE.SMALL,
|
|
740
800
|
options: [
|
|
741
|
-
{value: COMBINATOR.AND, title: I18n.t("queryBuilder.and")},
|
|
742
|
-
{value: COMBINATOR.OR, title: I18n.t("queryBuilder.or")}
|
|
801
|
+
{ value: COMBINATOR.AND, title: I18n.t("queryBuilder.and") },
|
|
802
|
+
{ value: COMBINATOR.OR, title: I18n.t("queryBuilder.or") },
|
|
743
803
|
],
|
|
744
804
|
value: group.combinator,
|
|
745
|
-
onChange: (value) => this.setCombinator(group.id, value)
|
|
805
|
+
onChange: (value) => this.setCombinator(group.id, value),
|
|
746
806
|
});
|
|
747
807
|
combinator.setStretch(false);
|
|
748
808
|
this.#combinators.set(group.id, combinator);
|
|
@@ -751,13 +811,13 @@ class QueryBuilder {
|
|
|
751
811
|
const summary = document.createElement("query_builder_summary");
|
|
752
812
|
summary.className = "query_builder_summary";
|
|
753
813
|
summary.setAttribute("aria-hidden", "true");
|
|
754
|
-
summary.innerText = I18n.t("queryBuilder.rulesCount", {count: count});
|
|
814
|
+
summary.innerText = I18n.t("queryBuilder.rulesCount", { count: count });
|
|
755
815
|
head.appendChild(summary);
|
|
756
816
|
if (depth > 0) {
|
|
757
817
|
const remove = document.createElement("button");
|
|
758
818
|
remove.type = "button";
|
|
759
819
|
remove.className = "query_builder_remove query_builder_remove_group";
|
|
760
|
-
remove.setAttribute("aria-label", I18n.t("queryBuilder.removeGroup", {depth: depth}));
|
|
820
|
+
remove.setAttribute("aria-label", I18n.t("queryBuilder.removeGroup", { depth: depth }));
|
|
761
821
|
const glyph = new Icon(Icons.CONTENT.REMOVE, "18px").set();
|
|
762
822
|
glyph.setAttribute("aria-hidden", "true");
|
|
763
823
|
remove.appendChild(glyph);
|
|
@@ -789,17 +849,27 @@ class QueryBuilder {
|
|
|
789
849
|
#groupFoot(group = Object(), depth = Number()) {
|
|
790
850
|
const foot = document.createElement("query_builder_group_foot");
|
|
791
851
|
foot.className = "query_builder_group_foot";
|
|
792
|
-
foot.appendChild(
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
852
|
+
foot.appendChild(
|
|
853
|
+
this.#addButton({
|
|
854
|
+
title: I18n.t("queryBuilder.ruleShort"),
|
|
855
|
+
label:
|
|
856
|
+
depth === 0
|
|
857
|
+
? I18n.t("queryBuilder.addRule")
|
|
858
|
+
: I18n.t("queryBuilder.addRuleInGroup", { depth: depth }),
|
|
859
|
+
onClick: () => this.addRule(group.id),
|
|
860
|
+
})
|
|
861
|
+
);
|
|
797
862
|
if (this.#depthOf(group) < this.#max_depth) {
|
|
798
|
-
foot.appendChild(
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
863
|
+
foot.appendChild(
|
|
864
|
+
this.#addButton({
|
|
865
|
+
title: I18n.t("queryBuilder.groupShort"),
|
|
866
|
+
label:
|
|
867
|
+
depth === 0
|
|
868
|
+
? I18n.t("queryBuilder.addGroup")
|
|
869
|
+
: I18n.t("queryBuilder.addGroupInGroup", { depth: depth }),
|
|
870
|
+
onClick: () => this.addGroup(group.id),
|
|
871
|
+
})
|
|
872
|
+
);
|
|
803
873
|
}
|
|
804
874
|
return foot;
|
|
805
875
|
}
|
|
@@ -851,7 +921,7 @@ class QueryBuilder {
|
|
|
851
921
|
|
|
852
922
|
/** Запомнить готовое поле вместе с его узлом: по узлу его найдут после пересборки */
|
|
853
923
|
#track(component = Object(), node = new HTMLElement()) {
|
|
854
|
-
this.#controls.push({component: component, node: node});
|
|
924
|
+
this.#controls.push({ component: component, node: node });
|
|
855
925
|
return node;
|
|
856
926
|
}
|
|
857
927
|
|
|
@@ -871,26 +941,33 @@ class QueryBuilder {
|
|
|
871
941
|
node.className = "query_builder_rule";
|
|
872
942
|
node.dataset.id = rule.id;
|
|
873
943
|
node.setAttribute("role", "group");
|
|
874
|
-
node.setAttribute("aria-label", I18n.t("queryBuilder.ruleLabel", {index: index}));
|
|
875
|
-
node.appendChild(
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
944
|
+
node.setAttribute("aria-label", I18n.t("queryBuilder.ruleLabel", { index: index }));
|
|
945
|
+
node.appendChild(
|
|
946
|
+
this.#selectControl({
|
|
947
|
+
className: "query_builder_field",
|
|
948
|
+
label: I18n.t("queryBuilder.fieldOfRule", { index: index }),
|
|
949
|
+
options: this.#fields.map((item) => ({ value: item.key, title: item.label })),
|
|
950
|
+
value: field.key,
|
|
951
|
+
onChange: (value) => this.#changeField(rule.id, value),
|
|
952
|
+
})
|
|
953
|
+
);
|
|
954
|
+
node.appendChild(
|
|
955
|
+
this.#selectControl({
|
|
956
|
+
className: "query_builder_operator",
|
|
957
|
+
label: I18n.t("queryBuilder.operatorOfRule", { index: index }),
|
|
958
|
+
options: OPERATORS_BY_TYPE[field.type].map((operator) => ({
|
|
959
|
+
value: operator,
|
|
960
|
+
title: I18n.t(OPERATOR_KEYS[operator]),
|
|
961
|
+
})),
|
|
962
|
+
value: rule.operator,
|
|
963
|
+
onChange: (value) => this.#changeOperator(rule.id, value),
|
|
964
|
+
})
|
|
965
|
+
);
|
|
889
966
|
if (this.#needsValue(rule.operator)) node.appendChild(this.#valueControl(rule, field, index));
|
|
890
967
|
const remove = document.createElement("button");
|
|
891
968
|
remove.type = "button";
|
|
892
969
|
remove.className = "query_builder_remove query_builder_remove_rule";
|
|
893
|
-
remove.setAttribute("aria-label", I18n.t("queryBuilder.removeRule", {index: index}));
|
|
970
|
+
remove.setAttribute("aria-label", I18n.t("queryBuilder.removeRule", { index: index }));
|
|
894
971
|
const glyph = new Icon(Icons.CONTENT.REMOVE, "18px").set();
|
|
895
972
|
glyph.setAttribute("aria-hidden", "true");
|
|
896
973
|
remove.appendChild(glyph);
|
|
@@ -907,19 +984,23 @@ class QueryBuilder {
|
|
|
907
984
|
#valueControl(rule = Object(), field = Object(), index = Number()) {
|
|
908
985
|
const unset = rule.value === undefined || rule.value === null;
|
|
909
986
|
if (field.type === TYPE.BOOLEAN || field.type === TYPE.SELECT) {
|
|
910
|
-
const options =
|
|
911
|
-
|
|
912
|
-
|
|
987
|
+
const options =
|
|
988
|
+
field.type === TYPE.BOOLEAN
|
|
989
|
+
? [
|
|
990
|
+
{ value: "true", title: I18n.t("queryBuilder.yes") },
|
|
991
|
+
{ value: "false", title: I18n.t("queryBuilder.no") },
|
|
992
|
+
]
|
|
993
|
+
: field.options;
|
|
913
994
|
// Пустой вариант показывает «значение не выбрано» честно: модель и вид не расходятся
|
|
914
995
|
return this.#selectControl({
|
|
915
996
|
className: "query_builder_value",
|
|
916
|
-
label: I18n.t("queryBuilder.valueOfRule", {index: index}),
|
|
917
|
-
options: [{value: "", title: I18n.t(UNSET_TITLE)}].concat(options),
|
|
997
|
+
label: I18n.t("queryBuilder.valueOfRule", { index: index }),
|
|
998
|
+
options: [{ value: "", title: I18n.t(UNSET_TITLE) }].concat(options),
|
|
918
999
|
value: unset ? "" : String(rule.value),
|
|
919
|
-
onChange: (value) => this.#changeValue(rule.id, value)
|
|
1000
|
+
onChange: (value) => this.#changeValue(rule.id, value),
|
|
920
1001
|
});
|
|
921
1002
|
}
|
|
922
|
-
const label = I18n.t("queryBuilder.valueOfRule", {index: index});
|
|
1003
|
+
const label = I18n.t("queryBuilder.valueOfRule", { index: index });
|
|
923
1004
|
// У числа значение живёт по подтверждению: недонабранное «1e» или «-» в модель не попадает
|
|
924
1005
|
if (field.type === TYPE.NUMBER) {
|
|
925
1006
|
const number = new NumberInput({});
|
|
@@ -940,7 +1021,7 @@ class QueryBuilder {
|
|
|
940
1021
|
return this.#bindValueControl(this.#track(date, date.set()), "query_builder_value", label);
|
|
941
1022
|
}
|
|
942
1023
|
// Строка: значение живёт по вводу, поэтому слушатель на input, а не на change
|
|
943
|
-
const text = new TextInput({placeholder: I18n.t("queryBuilder.value")});
|
|
1024
|
+
const text = new TextInput({ placeholder: I18n.t("queryBuilder.value") });
|
|
944
1025
|
text.setValue(unset ? "" : String(rule.value));
|
|
945
1026
|
text.addInputListener(() => this.#changeValue(rule.id, text.getValue()));
|
|
946
1027
|
return this.#bindValueControl(this.#track(text, text.set()), "query_builder_value", label);
|
|
@@ -964,7 +1045,7 @@ class QueryBuilder {
|
|
|
964
1045
|
}
|
|
965
1046
|
rule.value = undefined;
|
|
966
1047
|
this.#render();
|
|
967
|
-
this.#announce(I18n.t("queryBuilder.fieldChanged", {index: this.#indexOfRule(ruleId), label: field.label}));
|
|
1048
|
+
this.#announce(I18n.t("queryBuilder.fieldChanged", { index: this.#indexOfRule(ruleId), label: field.label }));
|
|
968
1049
|
this.#refreshErrors();
|
|
969
1050
|
this.#notify();
|
|
970
1051
|
return this;
|
|
@@ -976,7 +1057,12 @@ class QueryBuilder {
|
|
|
976
1057
|
rule.operator = operator;
|
|
977
1058
|
if (this.#needsValue(operator) === false) rule.value = undefined;
|
|
978
1059
|
this.#render();
|
|
979
|
-
this.#announce(
|
|
1060
|
+
this.#announce(
|
|
1061
|
+
I18n.t("queryBuilder.operatorChanged", {
|
|
1062
|
+
index: this.#indexOfRule(ruleId),
|
|
1063
|
+
operator: I18n.t(OPERATOR_KEYS[operator]),
|
|
1064
|
+
})
|
|
1065
|
+
);
|
|
980
1066
|
this.#refreshErrors();
|
|
981
1067
|
this.#notify();
|
|
982
1068
|
return this;
|
|
@@ -1028,11 +1114,15 @@ class QueryBuilder {
|
|
|
1028
1114
|
|
|
1029
1115
|
static #groupText(group = Object(), fields = Array()) {
|
|
1030
1116
|
if (group === undefined) return "";
|
|
1031
|
-
const parts = group.children.map((child) =>
|
|
1032
|
-
|
|
1033
|
-
|
|
1117
|
+
const parts = group.children.map((child) =>
|
|
1118
|
+
child.kind === "group"
|
|
1119
|
+
? `(${QueryBuilder.#groupText(child, fields)})`
|
|
1120
|
+
: QueryBuilder.#valueText(child, fields)
|
|
1121
|
+
);
|
|
1034
1122
|
if (parts.length === 0) return "";
|
|
1035
|
-
return parts.length === 1
|
|
1123
|
+
return parts.length === 1
|
|
1124
|
+
? parts[0]
|
|
1125
|
+
: parts.join(` ${I18n.t(QueryBuilder.#combinatorTitle(group.combinator))} `);
|
|
1036
1126
|
}
|
|
1037
1127
|
|
|
1038
1128
|
#syncLabel() {
|
|
@@ -1057,7 +1147,10 @@ class QueryBuilder {
|
|
|
1057
1147
|
for (const rule of this.#rules()) {
|
|
1058
1148
|
const node = this.#tree.querySelector(`query_builder_rule[data-id="${CSS.escape(rule.id)}"]`);
|
|
1059
1149
|
if (node === null) continue;
|
|
1060
|
-
node.classList.toggle(
|
|
1150
|
+
node.classList.toggle(
|
|
1151
|
+
"query_builder_rule_empty",
|
|
1152
|
+
this.#needsValue(rule.operator) && this.#isEmptyValue(rule.value)
|
|
1153
|
+
);
|
|
1061
1154
|
}
|
|
1062
1155
|
return this;
|
|
1063
1156
|
}
|
|
@@ -1089,4 +1182,4 @@ class QueryBuilder {
|
|
|
1089
1182
|
}
|
|
1090
1183
|
}
|
|
1091
1184
|
|
|
1092
|
-
exports.QueryBuilder = QueryBuilder
|
|
1185
|
+
exports.QueryBuilder = QueryBuilder;
|