chuijs 4.0.3 → 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 +536 -0
- package/framework/appLayout/default/chui_app_layout.js +361 -303
- package/framework/appLayout/default/global_style.css +243 -89
- package/framework/appLayout/default/main_theme_style.css +188 -101
- package/framework/components/chui_accordion/accordion.js +17 -17
- package/framework/components/chui_accordion/styles.css +7 -7
- package/framework/components/chui_action_sheet/action_sheet.js +35 -32
- package/framework/components/chui_action_sheet/styles.css +10 -4
- 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 +4 -4
- package/framework/components/chui_affix/styles.css +5 -0
- package/framework/components/chui_alert/alert.js +11 -5
- package/framework/components/chui_alert/styles.css +7 -0
- package/framework/components/chui_avatar/avatar.js +13 -13
- package/framework/components/chui_avatar/styles.css +1 -1
- package/framework/components/chui_avatar_group/avatar_group.js +4 -4
- package/framework/components/chui_avatar_group/styles.css +1 -1
- package/framework/components/chui_backtop/backtop.js +25 -2
- package/framework/components/chui_backtop/styles.css +21 -0
- package/framework/components/chui_badge/badge.js +15 -15
- 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/styles.css +1 -1
- package/framework/components/chui_button/button.js +24 -28
- package/framework/components/chui_button/styles.css +5 -5
- package/framework/components/chui_calendar/calendar.js +6 -6
- package/framework/components/chui_card/card.js +14 -14
- 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 +73 -51
- package/framework/components/chui_chat/styles.css +18 -7
- package/framework/components/chui_clipboard_history/clipboard_history.js +25 -20
- package/framework/components/chui_clipboard_history/styles.css +10 -8
- package/framework/components/chui_code/code.js +8 -8
- package/framework/components/chui_code/styles.css +2 -2
- package/framework/components/chui_code_editor/code_editor.js +26 -26
- package/framework/components/chui_code_editor/styles.css +3 -3
- package/framework/components/chui_command_palette/command_palette.js +29 -29
- package/framework/components/chui_command_palette/styles.css +5 -5
- package/framework/components/chui_console/console.js +9 -9
- package/framework/components/chui_console/styles.css +5 -2
- package/framework/components/chui_content_block/content_block.js +2 -2
- package/framework/components/chui_context_menu/context_menu.js +162 -54
- package/framework/components/chui_context_menu/styles.css +82 -8
- package/framework/components/chui_custom_element/custom_element.js +11 -11
- package/framework/components/chui_data_grid/data_grid.js +268 -268
- package/framework/components/chui_data_grid/styles.css +14 -14
- package/framework/components/chui_descriptions/styles.css +1 -1
- package/framework/components/chui_details/details.js +12 -12
- package/framework/components/chui_details/styles.css +7 -7
- package/framework/components/chui_diff_viewer/diff_viewer.js +88 -88
- package/framework/components/chui_diff_viewer/styles.css +9 -9
- package/framework/components/chui_divider/divider.js +6 -6
- package/framework/components/chui_divider/styles.css +2 -2
- package/framework/components/chui_drawer/drawer.js +37 -14
- package/framework/components/chui_drawer/styles.css +18 -4
- package/framework/components/chui_drop_zone/drop_zone.js +6 -6
- package/framework/components/chui_drop_zone/styles.css +10 -6
- package/framework/components/chui_fieldset/fieldset.js +6 -6
- package/framework/components/chui_fieldset/styles.css +5 -5
- package/framework/components/chui_file_explorer/file_explorer.js +115 -115
- package/framework/components/chui_file_explorer/styles.css +6 -6
- package/framework/components/chui_form/form.js +11 -11
- package/framework/components/chui_gantt/gantt.js +41 -41
- package/framework/components/chui_gantt/styles.css +5 -5
- package/framework/components/chui_graphs/graphs.js +82 -46
- package/framework/components/chui_graphs/styles.css +26 -5
- package/framework/components/chui_hero/hero.js +63 -20
- package/framework/components/chui_hero/styles.css +176 -7
- package/framework/components/chui_html_block/html_block.js +5 -5
- package/framework/components/chui_html_block/styles.css +1 -1
- package/framework/components/chui_hx/styles.css +2 -2
- package/framework/components/chui_icons/icons.js +7 -7
- package/framework/components/chui_icons/styles.css +2 -1
- package/framework/components/chui_inputs/chui_check_box/styles.css +12 -3
- package/framework/components/chui_inputs/chui_chips/chips.js +92 -31
- package/framework/components/chui_inputs/chui_chips/styles.css +28 -5
- package/framework/components/chui_inputs/chui_color_picker/color_picker.js +20 -15
- package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
- package/framework/components/chui_inputs/chui_combo_box/combo_box.js +58 -58
- package/framework/components/chui_inputs/chui_combo_box/styles.css +9 -9
- package/framework/components/chui_inputs/chui_date/date.js +93 -95
- package/framework/components/chui_inputs/chui_date/styles.css +8 -8
- package/framework/components/chui_inputs/chui_date_range/date_range.js +22 -22
- package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
- package/framework/components/chui_inputs/chui_datetime/datetime.js +12 -12
- package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
- package/framework/components/chui_inputs/chui_email/email.js +10 -10
- package/framework/components/chui_inputs/chui_email/styles.css +6 -6
- package/framework/components/chui_inputs/chui_file/file.js +8 -8
- package/framework/components/chui_inputs/chui_file/styles.css +12 -9
- package/framework/components/chui_inputs/chui_hotkey/hotkey.js +39 -39
- package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
- package/framework/components/chui_inputs/chui_masked/masked.js +44 -44
- package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
- package/framework/components/chui_inputs/chui_mention/mention.js +13 -13
- package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
- package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +147 -137
- package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +14 -8
- package/framework/components/chui_inputs/chui_number/number.js +42 -45
- package/framework/components/chui_inputs/chui_number/styles.css +6 -6
- package/framework/components/chui_inputs/chui_otp/otp.js +32 -32
- package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
- package/framework/components/chui_inputs/chui_password/password.js +30 -36
- package/framework/components/chui_inputs/chui_password/styles.css +7 -7
- package/framework/components/chui_inputs/chui_radio_button/styles.css +2 -2
- package/framework/components/chui_inputs/chui_rating/rating.js +28 -28
- package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
- package/framework/components/chui_inputs/chui_select_box/select_box.js +54 -54
- package/framework/components/chui_inputs/chui_select_box/styles.css +10 -10
- package/framework/components/chui_inputs/chui_slider/slider.js +14 -14
- package/framework/components/chui_inputs/chui_slider/styles.css +5 -4
- package/framework/components/chui_inputs/chui_text/styles.css +7 -7
- package/framework/components/chui_inputs/chui_text/text.js +13 -17
- package/framework/components/chui_inputs/chui_text_area/styles.css +8 -8
- package/framework/components/chui_inputs/chui_text_area/text_area.js +23 -23
- package/framework/components/chui_inputs/chui_time/styles.css +13 -17
- package/framework/components/chui_inputs/chui_time/time.js +35 -24
- package/framework/components/chui_inputs/chui_toggle/styles.css +10 -3
- package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
- package/framework/components/chui_json_editor/json_editor.js +87 -87
- package/framework/components/chui_json_editor/styles.css +5 -5
- package/framework/components/chui_json_viewer/json_viewer.js +80 -80
- package/framework/components/chui_json_viewer/styles.css +6 -6
- package/framework/components/chui_kanban/kanban.js +27 -27
- package/framework/components/chui_kanban/styles.css +8 -4
- package/framework/components/chui_kbd/styles.css +1 -1
- package/framework/components/chui_label/label.js +17 -17
- package/framework/components/chui_label/styles.css +1 -1
- package/framework/components/chui_link/link.js +9 -9
- package/framework/components/chui_link/styles.css +11 -4
- package/framework/components/chui_list/list.js +11 -11
- package/framework/components/chui_list/styles.css +2 -2
- package/framework/components/chui_markdown_editor/markdown_editor.js +66 -66
- package/framework/components/chui_markdown_editor/styles.css +5 -5
- package/framework/components/chui_media/audio.js +240 -246
- package/framework/components/chui_media/audio_styles.css +41 -23
- package/framework/components/chui_media/image.js +49 -46
- package/framework/components/chui_media/image_compare.js +35 -35
- package/framework/components/chui_media/image_compare_styles.css +5 -5
- package/framework/components/chui_media/image_styles.css +1 -1
- package/framework/components/chui_media/video.js +148 -148
- package/framework/components/chui_media/video_styles.css +27 -11
- package/framework/components/chui_menu_bar/menu_bar.js +54 -54
- package/framework/components/chui_menu_bar/styles.css +10 -10
- 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 +37 -13
- package/framework/components/chui_notification/notification.js +76 -54
- package/framework/components/chui_notification/notification_download.js +26 -81
- package/framework/components/chui_notification/notification_download_card.js +115 -0
- package/framework/components/chui_notification/notification_download_progress.css +2 -2
- package/framework/components/chui_notification/notification_download_progress.js +70 -108
- package/framework/components/chui_notification/notification_update.js +31 -31
- package/framework/components/chui_notification/status_plate.css +3 -3
- package/framework/components/chui_notification/styles.css +6 -1
- package/framework/components/chui_notification/styles_download.css +1 -1
- package/framework/components/chui_notification/styles_update.css +2 -2
- package/framework/components/chui_org_chart/org_chart.js +29 -29
- package/framework/components/chui_org_chart/styles.css +2 -2
- package/framework/components/chui_pagination/pagination.js +3 -3
- package/framework/components/chui_pagination/styles.css +1 -1
- package/framework/components/chui_paragraph/styles.css +2 -2
- package/framework/components/chui_popover/popover.js +29 -23
- package/framework/components/chui_popover/styles.css +1 -1
- package/framework/components/chui_popups/popups.js +124 -124
- package/framework/components/chui_popups/styles.css +5 -5
- package/framework/components/chui_print_button/print_button.js +15 -10
- package/framework/components/chui_progress_bar/progress_bar.js +34 -12
- package/framework/components/chui_progress_bar/styles.css +4 -4
- package/framework/components/chui_progress_ring/progress_ring.js +15 -15
- package/framework/components/chui_progress_ring/styles.css +1 -1
- package/framework/components/chui_qrcode/qrcode.js +12 -12
- package/framework/components/chui_query_builder/query_builder.js +46 -46
- package/framework/components/chui_query_builder/styles.css +4 -4
- package/framework/components/chui_radio_group/styles.css +1 -1
- package/framework/components/chui_result/result.js +15 -15
- package/framework/components/chui_result/styles.css +3 -3
- package/framework/components/chui_scheduler/scheduler.js +74 -74
- package/framework/components/chui_scheduler/styles.css +5 -5
- 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 +63 -6
- package/framework/components/chui_segmented_control/styles.css +32 -6
- package/framework/components/chui_settings/settings.js +45 -46
- package/framework/components/chui_settings/styles.css +4 -4
- package/framework/components/chui_shortcut_help/shortcut_help.js +32 -34
- package/framework/components/chui_sidebar_nav/sidebar_nav.js +98 -29
- package/framework/components/chui_sidebar_nav/styles.css +9 -3
- package/framework/components/chui_slideshow/slideshow.js +85 -85
- package/framework/components/chui_slideshow/styles.css +6 -6
- package/framework/components/chui_spinner/spinner.js +10 -10
- package/framework/components/chui_split_button/split_button.js +30 -12
- package/framework/components/chui_split_button/styles.css +21 -5
- package/framework/components/chui_splitter/splitter.js +11 -11
- package/framework/components/chui_splitter/styles.css +2 -2
- package/framework/components/chui_statistic/statistic.js +47 -47
- package/framework/components/chui_status_bar/styles.css +2 -2
- package/framework/components/chui_stepper/stepper.js +202 -31
- package/framework/components/chui_stepper/styles.css +79 -14
- package/framework/components/chui_sticky_bar/sticky_bar.js +44 -13
- package/framework/components/chui_sticky_bar/styles.css +10 -8
- package/framework/components/chui_tabs/chui_tabs.js +74 -26
- package/framework/components/chui_tabs/styles.css +40 -12
- package/framework/components/chui_text_editor/styles.css +7 -7
- package/framework/components/chui_text_editor/text_editor.js +56 -56
- package/framework/components/chui_text_editor/text_editor_panel.js +173 -174
- package/framework/components/chui_theme_toggle/theme_toggle.js +21 -5
- package/framework/components/chui_timeline/styles.css +3 -1
- package/framework/components/chui_toast_queue/styles.css +11 -11
- package/framework/components/chui_toast_queue/toast_queue.js +30 -27
- package/framework/components/chui_toolbar/styles.css +2 -2
- package/framework/components/chui_tooltip/styles.css +2 -2
- package/framework/components/chui_tooltip/tooltip.js +3 -3
- package/framework/components/chui_tour/styles.css +8 -8
- package/framework/components/chui_tour/tour.js +72 -72
- package/framework/components/chui_transfer/styles.css +6 -6
- package/framework/components/chui_transfer/transfer.js +93 -106
- package/framework/components/chui_tree_table/styles.css +4 -4
- package/framework/components/chui_tree_table/tree_table.js +45 -45
- package/framework/components/chui_tree_view/styles.css +10 -8
- package/framework/components/chui_tree_view/tree_view.js +185 -183
- 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 +17 -17
- package/framework/components/chui_webview/webview.js +9 -9
- 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 +78 -79
- package/framework/modules/chui_animations/animations.js +77 -15
- package/framework/modules/chui_animations/motion.js +120 -0
- package/framework/modules/chui_animations/styles.css +36 -3
- package/framework/modules/chui_functions.js +31 -27
- package/framework/modules/chui_highlight/styles.css +13 -10
- package/framework/modules/chui_i18n/chui_i18n.js +3 -3
- package/framework/modules/chui_i18n/locales/feedback.js +62 -0
- package/framework/modules/chui_i18n/locales/navigation.js +4 -0
- package/framework/modules/chui_json/chui_json.js +2 -2
- package/framework/modules/chui_logger/chui_logger.js +23 -8
- package/framework/modules/chui_page/page.js +10 -10
- package/framework/modules/chui_palette/palette.js +61 -0
- package/framework/modules/chui_qr/chui_qr.js +23 -23
- package/framework/modules/chui_scrollbar/chui_scrollbar.js +45 -45
- package/framework/modules/chui_scrollbar/styles.css +3 -3
- package/framework/modules/chui_services/chui_services.js +8 -8
- package/framework/modules/chui_services/desktop.js +77 -71
- package/framework/modules/chui_sortable/chui_sortable.js +17 -17
- package/framework/modules/chui_validate/chui_validate.js +3 -3
- package/framework/tray_bar/chui_menu_items.js +2 -2
- package/index.d.ts +266 -34
- package/index.js +20 -1168
- package/package.json +6 -4
- package/framework/components/telegram_bot/chui_telegram_bot.js +0 -191
|
@@ -56,34 +56,34 @@ class DiffViewer {
|
|
|
56
56
|
#title = document.createElement("diff_viewer_title");
|
|
57
57
|
#head = document.createElement("diff_viewer_head");
|
|
58
58
|
#stats = document.createElement("diff_viewer_stats");
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
59
|
+
#statRemoved = document.createElement("diff_viewer_stat");
|
|
60
|
+
#statAdded = document.createElement("diff_viewer_stat");
|
|
61
|
+
#statChanged = document.createElement("diff_viewer_stat");
|
|
62
62
|
#prev = document.createElement("button");
|
|
63
63
|
#next = document.createElement("button");
|
|
64
64
|
#grid = document.createElement("diff_viewer_grid");
|
|
65
|
-
#
|
|
65
|
+
#headRow = document.createElement("diff_viewer_head_row");
|
|
66
66
|
#body = document.createElement("diff_viewer_body");
|
|
67
67
|
#empty = document.createElement("diff_viewer_empty");
|
|
68
68
|
#status = document.createElement("diff_viewer_status");
|
|
69
69
|
#id = undefined;
|
|
70
70
|
#left = "";
|
|
71
71
|
#right = "";
|
|
72
|
-
#
|
|
73
|
-
#
|
|
72
|
+
#leftTitle = undefined;
|
|
73
|
+
#rightTitle = undefined;
|
|
74
74
|
#mode = DiffViewer.MODE.SIDE_BY_SIDE;
|
|
75
75
|
#context = 3;
|
|
76
|
-
#
|
|
76
|
+
#lineNumbers = true;
|
|
77
77
|
#height = "360px";
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
78
|
+
#titleText = undefined;
|
|
79
|
+
#labelText = undefined;
|
|
80
|
+
#emptyText = undefined;
|
|
81
81
|
#rows = [];
|
|
82
|
-
#
|
|
82
|
+
#statsData = { equal: 0, added: 0, removed: 0, changed: 0, groups: 0 };
|
|
83
83
|
#approximate = false;
|
|
84
84
|
#expanded = [];
|
|
85
|
-
#
|
|
86
|
-
#
|
|
85
|
+
#activeIndex = undefined;
|
|
86
|
+
#focusIndex = undefined;
|
|
87
87
|
|
|
88
88
|
constructor(
|
|
89
89
|
options = {
|
|
@@ -107,16 +107,16 @@ class DiffViewer {
|
|
|
107
107
|
this.#id = options.id === undefined ? `chui_diff_viewer_${DiffViewer.#counter}` : options.id;
|
|
108
108
|
this.#root.id = this.#id;
|
|
109
109
|
this.#root.setAttribute("role", "group");
|
|
110
|
-
this.#
|
|
111
|
-
if (options.leftTitle !== undefined) this.#
|
|
112
|
-
else this.#
|
|
113
|
-
if (options.rightTitle !== undefined) this.#
|
|
114
|
-
else this.#
|
|
115
|
-
if (options.emptyText !== undefined) this.#
|
|
116
|
-
else this.#
|
|
110
|
+
this.#labelText = options.label;
|
|
111
|
+
if (options.leftTitle !== undefined) this.#leftTitle = String(options.leftTitle);
|
|
112
|
+
else this.#leftTitle = I18n.t("diffViewer.before");
|
|
113
|
+
if (options.rightTitle !== undefined) this.#rightTitle = String(options.rightTitle);
|
|
114
|
+
else this.#rightTitle = I18n.t("diffViewer.after");
|
|
115
|
+
if (options.emptyText !== undefined) this.#emptyText = String(options.emptyText);
|
|
116
|
+
else this.#emptyText = I18n.t("diffViewer.noChanges");
|
|
117
117
|
this.#mode = options.mode === DiffViewer.MODE.UNIFIED ? DiffViewer.MODE.UNIFIED : DiffViewer.MODE.SIDE_BY_SIDE;
|
|
118
118
|
this.#context = options.context === undefined ? this.#context : options.context;
|
|
119
|
-
this.#
|
|
119
|
+
this.#lineNumbers = options.lineNumbers !== false;
|
|
120
120
|
this.#title.className = "diff_viewer_title";
|
|
121
121
|
this.#title.id = `${this.#id}_title`;
|
|
122
122
|
this.#head.className = "diff_viewer_head";
|
|
@@ -125,8 +125,8 @@ class DiffViewer {
|
|
|
125
125
|
this.#stats.setAttribute("aria-hidden", "true");
|
|
126
126
|
this.#grid.className = "diff_viewer_grid";
|
|
127
127
|
this.#grid.setAttribute("role", "table");
|
|
128
|
-
this.#
|
|
129
|
-
this.#
|
|
128
|
+
this.#headRow.className = "diff_viewer_head_row";
|
|
129
|
+
this.#headRow.setAttribute("role", "row");
|
|
130
130
|
this.#body.className = "diff_viewer_body";
|
|
131
131
|
this.#body.setAttribute("role", "rowgroup");
|
|
132
132
|
this.#empty.className = "diff_viewer_empty";
|
|
@@ -136,14 +136,14 @@ class DiffViewer {
|
|
|
136
136
|
this.#buildHead();
|
|
137
137
|
this.#root.appendChild(this.#title);
|
|
138
138
|
this.#root.appendChild(this.#head);
|
|
139
|
-
this.#grid.appendChild(this.#
|
|
139
|
+
this.#grid.appendChild(this.#headRow);
|
|
140
140
|
this.#grid.appendChild(this.#body);
|
|
141
141
|
this.#root.appendChild(this.#grid);
|
|
142
142
|
this.#root.appendChild(this.#empty);
|
|
143
143
|
this.#root.appendChild(this.#status);
|
|
144
144
|
if (options.title !== undefined) this.setTitle(options.title);
|
|
145
145
|
else this.#title.hidden = true;
|
|
146
|
-
this.setLabel(this.#
|
|
146
|
+
this.setLabel(this.#labelText === undefined ? I18n.t("diffViewer.title") : this.#labelText);
|
|
147
147
|
// Высота из опций: без неё остаётся своя по умолчанию (360px, тело прокручивается)
|
|
148
148
|
this.setHeight(options.height === undefined ? this.#height : options.height);
|
|
149
149
|
this.setTexts(options.left === undefined ? "" : options.left, options.right === undefined ? "" : options.right);
|
|
@@ -158,12 +158,12 @@ class DiffViewer {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
getTitle() {
|
|
161
|
-
return this.#
|
|
161
|
+
return this.#titleText;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
/** Доступное имя компонента, заданное в `label` */
|
|
165
165
|
getLabel() {
|
|
166
|
-
return this.#
|
|
166
|
+
return this.#labelText;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
getMode() {
|
|
@@ -179,11 +179,11 @@ class DiffViewer {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
getLeftTitle() {
|
|
182
|
-
return this.#
|
|
182
|
+
return this.#leftTitle;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
getRightTitle() {
|
|
186
|
-
return this.#
|
|
186
|
+
return this.#rightTitle;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
/** Строки модели: `{type, left, right}` (у вставки нет левой строки, у удаления — правой) */
|
|
@@ -193,7 +193,7 @@ class DiffViewer {
|
|
|
193
193
|
|
|
194
194
|
/** Счёт изменений: `{equal, added, removed, changed, groups}` */
|
|
195
195
|
getStats() {
|
|
196
|
-
return Object.assign({}, this.#
|
|
196
|
+
return Object.assign({}, this.#statsData);
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
/** Строки с учётом свёрнутых участков: у пропуска `{type: "gap", from, to}` (индексы модели) */
|
|
@@ -215,7 +215,7 @@ class DiffViewer {
|
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
isLineNumbers() {
|
|
218
|
-
return this.#
|
|
218
|
+
return this.#lineNumbers;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
getHeight() {
|
|
@@ -223,7 +223,7 @@ class DiffViewer {
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
getEmptyText() {
|
|
226
|
-
return this.#
|
|
226
|
+
return this.#emptyText;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
/** Сработал ли предел алгоритма: середина расхождения показана одним блоком */
|
|
@@ -242,7 +242,7 @@ class DiffViewer {
|
|
|
242
242
|
|
|
243
243
|
/** Подпись над сравнением; `undefined` её убирает (имя тогда даёт `label`) */
|
|
244
244
|
setTitle(text = undefined) {
|
|
245
|
-
this.#
|
|
245
|
+
this.#titleText = text;
|
|
246
246
|
if (text === undefined || text === "") {
|
|
247
247
|
this.#title.hidden = true;
|
|
248
248
|
this.#title.innerText = "";
|
|
@@ -257,19 +257,19 @@ class DiffViewer {
|
|
|
257
257
|
|
|
258
258
|
/** Имя сравнения, когда подписи в разметке нет */
|
|
259
259
|
setLabel(text = undefined) {
|
|
260
|
-
this.#
|
|
260
|
+
this.#labelText = text;
|
|
261
261
|
this.#syncLabel();
|
|
262
262
|
return this;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
setLeftTitle(text = String()) {
|
|
266
|
-
this.#
|
|
266
|
+
this.#leftTitle = String(text);
|
|
267
267
|
this.#render();
|
|
268
268
|
return this;
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
setRightTitle(text = String()) {
|
|
272
|
-
this.#
|
|
272
|
+
this.#rightTitle = String(text);
|
|
273
273
|
this.#render();
|
|
274
274
|
return this;
|
|
275
275
|
}
|
|
@@ -298,8 +298,8 @@ class DiffViewer {
|
|
|
298
298
|
this.#expanded = [];
|
|
299
299
|
this.#approximate = false;
|
|
300
300
|
this.#rows = this.#buildRows(DiffViewer.#split(this.#left), DiffViewer.#split(this.#right));
|
|
301
|
-
this.#
|
|
302
|
-
this.#
|
|
301
|
+
this.#statsData = this.#collectStats();
|
|
302
|
+
this.#activeIndex = undefined;
|
|
303
303
|
this.#render();
|
|
304
304
|
this.#announce();
|
|
305
305
|
return this;
|
|
@@ -322,13 +322,13 @@ class DiffViewer {
|
|
|
322
322
|
/** Раскрыть пропуск по индексам модели (как кнопка «Показать N строк») */
|
|
323
323
|
expandRange(from = Number(), to = Number()) {
|
|
324
324
|
this.#expanded.push({ from: Number(from), to: Number(to) });
|
|
325
|
-
this.#
|
|
325
|
+
this.#focusIndex = Number(from);
|
|
326
326
|
this.#render();
|
|
327
327
|
return this;
|
|
328
328
|
}
|
|
329
329
|
|
|
330
330
|
setLineNumbers(shown = Boolean()) {
|
|
331
|
-
this.#
|
|
331
|
+
this.#lineNumbers = shown !== false;
|
|
332
332
|
this.#render();
|
|
333
333
|
return this;
|
|
334
334
|
}
|
|
@@ -347,7 +347,7 @@ class DiffViewer {
|
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
setEmptyText(text = String()) {
|
|
350
|
-
this.#
|
|
350
|
+
this.#emptyText = text === undefined ? "" : String(text);
|
|
351
351
|
this.#render();
|
|
352
352
|
return this;
|
|
353
353
|
}
|
|
@@ -448,20 +448,20 @@ class DiffViewer {
|
|
|
448
448
|
suffix += 1;
|
|
449
449
|
const rows = [];
|
|
450
450
|
for (let i = 0; i < prefix; i += 1) rows.push(DiffViewer.#equalRow(left[i], i + 1, right[i], i + 1));
|
|
451
|
-
const
|
|
452
|
-
const
|
|
453
|
-
if (
|
|
451
|
+
const middleLeft = left.slice(prefix, left.length - suffix);
|
|
452
|
+
const middleRight = right.slice(prefix, right.length - suffix);
|
|
453
|
+
if (middleLeft.length > 0 || middleRight.length > 0) {
|
|
454
454
|
let operations;
|
|
455
|
-
if (
|
|
455
|
+
if (middleLeft.length * middleRight.length > DiffViewer.LCS_LIMIT) {
|
|
456
456
|
// Предел алгоритма: вместо честного (но не помещающегося) LCS показываем один блок
|
|
457
457
|
this.#approximate = true;
|
|
458
458
|
operations = [];
|
|
459
|
-
if (
|
|
460
|
-
if (
|
|
459
|
+
if (middleLeft.length > 0) operations.push({ type: DELETE, from: 0, to: middleLeft.length });
|
|
460
|
+
if (middleRight.length > 0) operations.push({ type: INSERT, from: 0, to: middleRight.length });
|
|
461
461
|
} else {
|
|
462
|
-
operations = DiffViewer.#operations(
|
|
462
|
+
operations = DiffViewer.#operations(middleLeft, middleRight);
|
|
463
463
|
}
|
|
464
|
-
for (const row of DiffViewer.#middleRows(operations,
|
|
464
|
+
for (const row of DiffViewer.#middleRows(operations, middleLeft, middleRight, prefix)) rows.push(row);
|
|
465
465
|
}
|
|
466
466
|
for (let k = 0; k < suffix; k += 1) {
|
|
467
467
|
const li = left.length - suffix + k;
|
|
@@ -471,11 +471,11 @@ class DiffViewer {
|
|
|
471
471
|
return rows;
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
-
static #equalRow(
|
|
474
|
+
static #equalRow(leftText = String(), leftNumber = Number(), rightText = String(), rightNumber = Number()) {
|
|
475
475
|
return {
|
|
476
476
|
type: EQUAL,
|
|
477
|
-
left: { number:
|
|
478
|
-
right: { number:
|
|
477
|
+
left: { number: leftNumber, text: leftText },
|
|
478
|
+
right: { number: rightNumber, text: rightText },
|
|
479
479
|
};
|
|
480
480
|
}
|
|
481
481
|
|
|
@@ -490,12 +490,12 @@ class DiffViewer {
|
|
|
490
490
|
for (let k = 0; k < pairs; k += 1) {
|
|
491
491
|
const li = operation.from + k;
|
|
492
492
|
const ri = next.from + k;
|
|
493
|
-
const
|
|
494
|
-
const
|
|
493
|
+
const hasLeft = li < operation.to;
|
|
494
|
+
const hasRight = ri < next.to;
|
|
495
495
|
rows.push({
|
|
496
|
-
type:
|
|
497
|
-
left:
|
|
498
|
-
right:
|
|
496
|
+
type: hasLeft && hasRight ? REPLACE : hasLeft ? DELETE : INSERT,
|
|
497
|
+
left: hasLeft ? { number: offset + li + 1, text: left[li] } : undefined,
|
|
498
|
+
right: hasRight ? { number: offset + ri + 1, text: right[ri] } : undefined,
|
|
499
499
|
});
|
|
500
500
|
}
|
|
501
501
|
index += 1;
|
|
@@ -555,7 +555,7 @@ class DiffViewer {
|
|
|
555
555
|
#visibleRows() {
|
|
556
556
|
const total = this.#rows.length;
|
|
557
557
|
const list = [];
|
|
558
|
-
if (this.#context === Infinity || this.#
|
|
558
|
+
if (this.#context === Infinity || this.#statsData.groups === 0) {
|
|
559
559
|
for (let index = 0; index < total; index += 1)
|
|
560
560
|
list.push({ type: this.#rows[index].type, row: this.#rows[index], index: index });
|
|
561
561
|
return list;
|
|
@@ -586,15 +586,15 @@ class DiffViewer {
|
|
|
586
586
|
}
|
|
587
587
|
|
|
588
588
|
#accessibleName() {
|
|
589
|
-
if (this.#
|
|
590
|
-
if (this.#
|
|
589
|
+
if (this.#titleText !== undefined && this.#titleText !== "") return this.#titleText;
|
|
590
|
+
if (this.#labelText !== undefined && this.#labelText !== "") return this.#labelText;
|
|
591
591
|
return I18n.t("diffViewer.title");
|
|
592
592
|
}
|
|
593
593
|
|
|
594
594
|
// Имя компонента: видимая подпись — через aria-labelledby, скрытая — через aria-label.
|
|
595
595
|
// Таблица внутри получает то же имя: у неё своя роль, и без имени она читалась бы безымянной
|
|
596
596
|
#syncLabel() {
|
|
597
|
-
if (this.#
|
|
597
|
+
if (this.#titleText !== undefined && this.#titleText !== "") {
|
|
598
598
|
this.#root.setAttribute("aria-labelledby", this.#title.id);
|
|
599
599
|
this.#root.removeAttribute("aria-label");
|
|
600
600
|
} else {
|
|
@@ -607,12 +607,12 @@ class DiffViewer {
|
|
|
607
607
|
|
|
608
608
|
#buildHead() {
|
|
609
609
|
this.#stats.innerHTML = "";
|
|
610
|
-
this.#
|
|
611
|
-
this.#
|
|
612
|
-
this.#
|
|
613
|
-
this.#stats.appendChild(this.#
|
|
614
|
-
this.#stats.appendChild(this.#
|
|
615
|
-
this.#stats.appendChild(this.#
|
|
610
|
+
this.#statRemoved.className = "diff_viewer_stat diff_viewer_stat_removed";
|
|
611
|
+
this.#statAdded.className = "diff_viewer_stat diff_viewer_stat_added";
|
|
612
|
+
this.#statChanged.className = "diff_viewer_stat diff_viewer_stat_changed";
|
|
613
|
+
this.#stats.appendChild(this.#statRemoved);
|
|
614
|
+
this.#stats.appendChild(this.#statAdded);
|
|
615
|
+
this.#stats.appendChild(this.#statChanged);
|
|
616
616
|
this.#prev.type = "button";
|
|
617
617
|
this.#prev.className = "diff_viewer_move diff_viewer_move_prev";
|
|
618
618
|
this.#prev.setAttribute("aria-label", I18n.t("diffViewer.previousChange"));
|
|
@@ -658,7 +658,7 @@ class DiffViewer {
|
|
|
658
658
|
const number = document.createElement("span");
|
|
659
659
|
number.className = "diff_viewer_number";
|
|
660
660
|
number.setAttribute("aria-hidden", "true");
|
|
661
|
-
number.innerText = this.#
|
|
661
|
+
number.innerText = this.#lineNumbers && line !== undefined ? String(line.number) : "";
|
|
662
662
|
const text = document.createElement("span");
|
|
663
663
|
text.className = "diff_viewer_text";
|
|
664
664
|
text.innerText = line === undefined ? "" : line.text;
|
|
@@ -677,7 +677,7 @@ class DiffViewer {
|
|
|
677
677
|
const label = this.#rowLabel(row);
|
|
678
678
|
if (label !== undefined) node.setAttribute("aria-label", label);
|
|
679
679
|
if (row.type !== EQUAL) node.classList.add(`diff_viewer_row_${row.type}`);
|
|
680
|
-
node.classList.toggle("diff_viewer_row_no_numbers", this.#
|
|
680
|
+
node.classList.toggle("diff_viewer_row_no_numbers", this.#lineNumbers === false);
|
|
681
681
|
for (const cell of this.#cells(row)) node.appendChild(cell);
|
|
682
682
|
return node;
|
|
683
683
|
}
|
|
@@ -722,10 +722,10 @@ class DiffViewer {
|
|
|
722
722
|
}
|
|
723
723
|
|
|
724
724
|
#applyStats() {
|
|
725
|
-
const stats = this.#
|
|
726
|
-
this.#
|
|
727
|
-
this.#
|
|
728
|
-
this.#
|
|
725
|
+
const stats = this.#statsData;
|
|
726
|
+
this.#statRemoved.innerText = `−${stats.removed}`;
|
|
727
|
+
this.#statAdded.innerText = `+${stats.added}`;
|
|
728
|
+
this.#statChanged.innerText = `~${stats.changed}`;
|
|
729
729
|
const empty = stats.groups === 0;
|
|
730
730
|
this.#prev.disabled = empty;
|
|
731
731
|
this.#next.disabled = empty;
|
|
@@ -733,7 +733,7 @@ class DiffViewer {
|
|
|
733
733
|
}
|
|
734
734
|
|
|
735
735
|
#announce() {
|
|
736
|
-
const stats = this.#
|
|
736
|
+
const stats = this.#statsData;
|
|
737
737
|
if (stats.groups === 0) {
|
|
738
738
|
this.#status.innerText = I18n.t("diffViewer.noChanges");
|
|
739
739
|
return this;
|
|
@@ -751,19 +751,19 @@ class DiffViewer {
|
|
|
751
751
|
// Строки пересобираются, а фокус живёт на строке: запоминаем её до перерисовки
|
|
752
752
|
const active = document.activeElement;
|
|
753
753
|
const focused = active === null || !this.#grid.contains(active) ? null : active.closest(".diff_viewer_row");
|
|
754
|
-
if (focused !== null && focused.dataset.index !== undefined) this.#
|
|
755
|
-
this.#
|
|
754
|
+
if (focused !== null && focused.dataset.index !== undefined) this.#focusIndex = Number(focused.dataset.index);
|
|
755
|
+
this.#headRow.innerHTML = "";
|
|
756
756
|
this.#body.innerHTML = "";
|
|
757
757
|
const titles =
|
|
758
758
|
this.#mode === DiffViewer.MODE.UNIFIED
|
|
759
759
|
? [I18n.t("diffViewer.changes")]
|
|
760
|
-
: [this.#
|
|
760
|
+
: [this.#leftTitle, this.#rightTitle];
|
|
761
761
|
for (const title of titles) {
|
|
762
762
|
const cell = document.createElement("div");
|
|
763
763
|
cell.className = "diff_viewer_head_cell";
|
|
764
764
|
cell.setAttribute("role", "columnheader");
|
|
765
765
|
cell.innerText = title;
|
|
766
|
-
this.#
|
|
766
|
+
this.#headRow.appendChild(cell);
|
|
767
767
|
}
|
|
768
768
|
this.#grid.setAttribute("aria-colcount", String(titles.length));
|
|
769
769
|
this.#grid.classList.toggle("diff_viewer_grid_unified", this.#mode === DiffViewer.MODE.UNIFIED);
|
|
@@ -772,8 +772,8 @@ class DiffViewer {
|
|
|
772
772
|
this.#body.appendChild(entry.type === GAP ? this.#gapNode(entry) : this.#rowNode(entry));
|
|
773
773
|
this.#grid.setAttribute("aria-rowcount", String(list.length + 1));
|
|
774
774
|
this.#grid.hidden = this.#rows.length === 0;
|
|
775
|
-
this.#empty.hidden = this.#
|
|
776
|
-
this.#empty.innerText = this.#
|
|
775
|
+
this.#empty.hidden = this.#statsData.groups !== 0;
|
|
776
|
+
this.#empty.innerText = this.#emptyText;
|
|
777
777
|
this.#applyStats();
|
|
778
778
|
this.#applyStop();
|
|
779
779
|
return this;
|
|
@@ -784,14 +784,14 @@ class DiffViewer {
|
|
|
784
784
|
const list = [...this.#body.querySelectorAll(".diff_viewer_row")];
|
|
785
785
|
if (list.length === 0) return;
|
|
786
786
|
const stop =
|
|
787
|
-
list.find((row) => Number(row.dataset.index) === this.#
|
|
788
|
-
list.find((row) => Number(row.dataset.index) === this.#
|
|
787
|
+
list.find((row) => Number(row.dataset.index) === this.#activeIndex) ??
|
|
788
|
+
list.find((row) => Number(row.dataset.index) === this.#focusIndex) ??
|
|
789
789
|
list[0];
|
|
790
|
-
this.#
|
|
790
|
+
this.#activeIndex = Number(stop.dataset.index);
|
|
791
791
|
for (const row of list) row.setAttribute("tabindex", row === stop ? "0" : "-1");
|
|
792
792
|
// Фокус возвращаем, только если он был в теле: иначе перерисовка его бы украла
|
|
793
|
-
if (this.#
|
|
794
|
-
this.#
|
|
793
|
+
if (this.#focusIndex !== undefined && Number(stop.dataset.index) === this.#focusIndex) {
|
|
794
|
+
this.#focusIndex = undefined;
|
|
795
795
|
stop.focus();
|
|
796
796
|
}
|
|
797
797
|
return this;
|
|
@@ -799,7 +799,7 @@ class DiffViewer {
|
|
|
799
799
|
|
|
800
800
|
#focusRow(row = undefined) {
|
|
801
801
|
if (row === undefined || row === null) return this;
|
|
802
|
-
this.#
|
|
802
|
+
this.#activeIndex = Number(row.dataset.index);
|
|
803
803
|
for (const other of this.#body.querySelectorAll(".diff_viewer_row")) {
|
|
804
804
|
other.setAttribute("tabindex", other === row ? "0" : "-1");
|
|
805
805
|
}
|
|
@@ -839,7 +839,7 @@ class DiffViewer {
|
|
|
839
839
|
#goToChange(direction = Number()) {
|
|
840
840
|
const groups = this.#changeGroups();
|
|
841
841
|
if (groups.length === 0) return this;
|
|
842
|
-
const current = this.#
|
|
842
|
+
const current = this.#activeIndex;
|
|
843
843
|
const forward = direction > 0;
|
|
844
844
|
let target;
|
|
845
845
|
if (current === undefined) target = forward ? groups[0] : groups[groups.length - 1];
|
|
@@ -859,7 +859,7 @@ class DiffViewer {
|
|
|
859
859
|
#onFocusIn = (event) => {
|
|
860
860
|
const row = event.target instanceof Element ? event.target.closest(".diff_viewer_row") : null;
|
|
861
861
|
if (row === null || row.dataset.index === undefined) return;
|
|
862
|
-
this.#
|
|
862
|
+
this.#activeIndex = Number(row.dataset.index);
|
|
863
863
|
};
|
|
864
864
|
|
|
865
865
|
#onKeyDown = (event) => {
|
|
@@ -7,10 +7,10 @@ chui_diff_viewer {
|
|
|
7
7
|
box-sizing: border-box;
|
|
8
8
|
width: -webkit-fill-available;
|
|
9
9
|
max-width: 100%;
|
|
10
|
-
margin: var(--
|
|
10
|
+
margin: var(--block_margin);
|
|
11
11
|
overflow: hidden;
|
|
12
12
|
border: 1px solid var(--border_color);
|
|
13
|
-
border-radius: var(--
|
|
13
|
+
border-radius: var(--radius_sm);
|
|
14
14
|
background: var(--element_background);
|
|
15
15
|
color: var(--text_color);
|
|
16
16
|
font-family: "chui_mono", monospace;
|
|
@@ -24,7 +24,7 @@ chui_diff_viewer.diff_viewer_fixed .diff_viewer_body {
|
|
|
24
24
|
.diff_viewer_title {
|
|
25
25
|
display: block;
|
|
26
26
|
width: max-content;
|
|
27
|
-
margin: var(--
|
|
27
|
+
margin: var(--block_margin);
|
|
28
28
|
color: var(--text_color);
|
|
29
29
|
font-family: system-ui, sans-serif;
|
|
30
30
|
font-size: var(--font_labels_size);
|
|
@@ -68,17 +68,17 @@ chui_diff_viewer.diff_viewer_fixed .diff_viewer_body {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
.diff_viewer_stat_removed {
|
|
71
|
-
background: var(--
|
|
71
|
+
background: var(--badge_error_background);
|
|
72
72
|
color: var(--badge_error_text);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
.diff_viewer_stat_added {
|
|
76
|
-
background: var(--
|
|
76
|
+
background: var(--badge_success_background);
|
|
77
77
|
color: var(--badge_success_text);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
.diff_viewer_stat_changed {
|
|
81
|
-
background: var(--
|
|
81
|
+
background: var(--badge_warning_background);
|
|
82
82
|
color: var(--badge_warning_text);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -246,15 +246,15 @@ chui_diff_viewer.diff_viewer_fixed .diff_viewer_body {
|
|
|
246
246
|
/* Тона строк — те же, что у счётчиков: добавлено, удалено, заменено, без изменений.
|
|
247
247
|
Класс строки собирается из типа модели (insert/delete/replace), поэтому имена совпадают с ним */
|
|
248
248
|
.diff_viewer_row_insert {
|
|
249
|
-
background: var(--
|
|
249
|
+
background: var(--badge_success_background);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
.diff_viewer_row_delete {
|
|
253
|
-
background: var(--
|
|
253
|
+
background: var(--badge_error_background);
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
.diff_viewer_row_replace {
|
|
257
|
-
background: var(--
|
|
257
|
+
background: var(--badge_warning_background);
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
.diff_viewer_row_insert .diff_viewer_marker {
|
|
@@ -26,7 +26,7 @@ class Divider {
|
|
|
26
26
|
#root = document.createElement("chui_divider");
|
|
27
27
|
#line = document.createElement("divider_line");
|
|
28
28
|
// Вторая линия существует ровно тогда, когда есть подпись
|
|
29
|
-
#
|
|
29
|
+
#lineAfter = undefined;
|
|
30
30
|
#text = undefined;
|
|
31
31
|
#id = undefined;
|
|
32
32
|
|
|
@@ -80,17 +80,17 @@ class Divider {
|
|
|
80
80
|
this.#text.remove();
|
|
81
81
|
this.#text = undefined;
|
|
82
82
|
}
|
|
83
|
-
if (this.#
|
|
84
|
-
this.#
|
|
85
|
-
this.#
|
|
83
|
+
if (this.#lineAfter !== undefined) {
|
|
84
|
+
this.#lineAfter.remove();
|
|
85
|
+
this.#lineAfter = undefined;
|
|
86
86
|
}
|
|
87
87
|
return this;
|
|
88
88
|
}
|
|
89
89
|
if (this.#text === undefined) {
|
|
90
90
|
this.#text = document.createElement("divider_text");
|
|
91
|
-
this.#
|
|
91
|
+
this.#lineAfter = document.createElement("divider_line");
|
|
92
92
|
this.#root.appendChild(this.#text);
|
|
93
|
-
this.#root.appendChild(this.#
|
|
93
|
+
this.#root.appendChild(this.#lineAfter);
|
|
94
94
|
}
|
|
95
95
|
this.#text.innerText = text;
|
|
96
96
|
return this;
|
|
@@ -6,7 +6,7 @@ chui_divider {
|
|
|
6
6
|
--divider_length: -webkit-fill-available;
|
|
7
7
|
color: var(--text_color_disabled);
|
|
8
8
|
font-size: var(--font_default_size);
|
|
9
|
-
margin: var(--
|
|
9
|
+
margin: var(--block_margin);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
chui_divider[data-orientation="horizontal"] {
|
|
@@ -18,7 +18,7 @@ chui_divider[data-orientation="vertical"] {
|
|
|
18
18
|
align-self: stretch;
|
|
19
19
|
width: 1px;
|
|
20
20
|
height: var(--divider_length);
|
|
21
|
-
margin: 0 var(--
|
|
21
|
+
margin: 0 var(--block_margin);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
divider_line {
|