@siemens/element-ng 47.3.0 → 47.5.0
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/badge/si-badge.component.d.ts +1 -1
- package/breadcrumb/breadcrumb-item.model.d.ts +36 -0
- package/breadcrumb/index.d.ts +7 -0
- package/breadcrumb/package.json +3 -0
- package/breadcrumb/si-breadcrumb-item-template.directive.d.ts +10 -0
- package/breadcrumb/si-breadcrumb.component.d.ts +46 -0
- package/breadcrumb/si-breadcrumb.module.d.ts +7 -0
- package/card/index.d.ts +6 -0
- package/card/package.json +3 -0
- package/card/si-card.component.d.ts +79 -0
- package/card/si-card.module.d.ts +7 -0
- package/circle-status/index.d.ts +6 -0
- package/circle-status/package.json +3 -0
- package/circle-status/si-circle-status.component.d.ts +66 -0
- package/circle-status/si-circle-status.module.d.ts +7 -0
- package/column-selection-dialog/column-selection-editor/si-column-selection-editor.component.d.ts +23 -0
- package/column-selection-dialog/index.d.ts +6 -0
- package/column-selection-dialog/package.json +3 -0
- package/column-selection-dialog/si-column-selection-dialog.component.d.ts +114 -0
- package/column-selection-dialog/si-column-selection-dialog.service.d.ts +20 -0
- package/column-selection-dialog/si-column-selection-dialog.types.d.ts +68 -0
- package/common/models/status-type.model.d.ts +4 -2
- package/datatable/index.d.ts +42 -0
- package/datatable/package.json +3 -0
- package/datatable/si-datatable-interaction.directive.d.ts +34 -0
- package/datatable/si-datatable.module.d.ts +7 -0
- package/date-range-filter/index.d.ts +8 -0
- package/date-range-filter/package.json +3 -0
- package/date-range-filter/si-date-range-calculation.service.d.ts +33 -0
- package/date-range-filter/si-date-range-filter.component.d.ts +248 -0
- package/date-range-filter/si-date-range-filter.module.d.ts +7 -0
- package/date-range-filter/si-date-range-filter.types.d.ts +40 -0
- package/date-range-filter/si-relative-date.component.d.ts +31 -0
- package/datepicker/components/si-calendar-body.component.d.ts +137 -0
- package/datepicker/components/si-calendar-date-cell.directive.d.ts +16 -0
- package/datepicker/components/si-calendar-direction-button.component.d.ts +18 -0
- package/datepicker/components/si-compare-adapter.d.ts +37 -0
- package/datepicker/components/si-day-selection.component.d.ts +76 -0
- package/datepicker/components/si-initial-focus.component.d.ts +74 -0
- package/datepicker/components/si-month-selection.component.d.ts +62 -0
- package/datepicker/components/si-year-selection.component.d.ts +65 -0
- package/datepicker/date-time-helper.d.ts +302 -0
- package/datepicker/index.d.ts +15 -0
- package/datepicker/package.json +3 -0
- package/datepicker/si-calendar-button.component.d.ts +49 -0
- package/datepicker/si-date-input.directive.d.ts +114 -0
- package/datepicker/si-date-range.component.d.ts +150 -0
- package/datepicker/si-datepicker-overlay.component.d.ts +82 -0
- package/datepicker/si-datepicker-overlay.directive.d.ts +104 -0
- package/datepicker/si-datepicker.component.d.ts +228 -0
- package/datepicker/si-datepicker.directive.d.ts +62 -0
- package/datepicker/si-datepicker.model.d.ts +129 -0
- package/datepicker/si-datepicker.module.d.ts +12 -0
- package/datepicker/si-timepicker.component.d.ts +214 -0
- package/electron-titlebar/electron.helpers.d.ts +5 -0
- package/electron-titlebar/index.d.ts +7 -0
- package/electron-titlebar/package.json +3 -0
- package/electron-titlebar/si-electron-titlebar.component.d.ts +72 -0
- package/electron-titlebar/si-electron-titlebar.module.d.ts +7 -0
- package/fesm2022/siemens-element-ng-badge.mjs.map +1 -1
- package/fesm2022/siemens-element-ng-breadcrumb.mjs +302 -0
- package/fesm2022/siemens-element-ng-breadcrumb.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-card.mjs +122 -0
- package/fesm2022/siemens-element-ng-card.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-circle-status.mjs +146 -0
- package/fesm2022/siemens-element-ng-circle-status.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-column-selection-dialog.mjs +369 -0
- package/fesm2022/siemens-element-ng-column-selection-dialog.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-common.mjs.map +1 -1
- package/fesm2022/siemens-element-ng-datatable.mjs +173 -0
- package/fesm2022/siemens-element-ng-datatable.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-date-range-filter.mjs +649 -0
- package/fesm2022/siemens-element-ng-date-range-filter.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-datepicker.mjs +4231 -0
- package/fesm2022/siemens-element-ng-datepicker.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-electron-titlebar.mjs +142 -0
- package/fesm2022/siemens-element-ng-electron-titlebar.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-file-uploader.mjs +751 -0
- package/fesm2022/siemens-element-ng-file-uploader.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-filter-bar.mjs +153 -0
- package/fesm2022/siemens-element-ng-filter-bar.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-filtered-search.mjs +1139 -0
- package/fesm2022/siemens-element-ng-filtered-search.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-formly.mjs +935 -0
- package/fesm2022/siemens-element-ng-formly.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-icon.mjs +52 -14
- package/fesm2022/siemens-element-ng-icon.mjs.map +1 -1
- package/fesm2022/siemens-element-ng-info-page.mjs +63 -0
- package/fesm2022/siemens-element-ng-info-page.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-inline-notification.mjs +4 -6
- package/fesm2022/siemens-element-ng-inline-notification.mjs.map +1 -1
- package/fesm2022/siemens-element-ng-ip-input.mjs +451 -0
- package/fesm2022/siemens-element-ng-ip-input.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-list-details.mjs +390 -0
- package/fesm2022/siemens-element-ng-list-details.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-loading-spinner.mjs +15 -12
- package/fesm2022/siemens-element-ng-loading-spinner.mjs.map +1 -1
- package/fesm2022/siemens-element-ng-localization.mjs +306 -0
- package/fesm2022/siemens-element-ng-localization.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-modal.mjs +4 -1
- package/fesm2022/siemens-element-ng-modal.mjs.map +1 -1
- package/fesm2022/siemens-element-ng-password-strength.mjs +22 -16
- package/fesm2022/siemens-element-ng-password-strength.mjs.map +1 -1
- package/fesm2022/siemens-element-ng-phone-number.mjs +426 -0
- package/fesm2022/siemens-element-ng-phone-number.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-photo-upload.mjs +480 -0
- package/fesm2022/siemens-element-ng-photo-upload.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-result-details-list.mjs +74 -0
- package/fesm2022/siemens-element-ng-result-details-list.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-search-bar.mjs +193 -0
- package/fesm2022/siemens-element-ng-search-bar.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-shadow-root.mjs +70 -0
- package/fesm2022/siemens-element-ng-shadow-root.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-side-panel.mjs +554 -0
- package/fesm2022/siemens-element-ng-side-panel.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-slider.mjs +313 -0
- package/fesm2022/siemens-element-ng-slider.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-sort-bar.mjs +89 -0
- package/fesm2022/siemens-element-ng-sort-bar.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-split.mjs +575 -0
- package/fesm2022/siemens-element-ng-split.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-status-bar.mjs +348 -0
- package/fesm2022/siemens-element-ng-status-bar.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-status-toggle.mjs +196 -0
- package/fesm2022/siemens-element-ng-status-toggle.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-system-banner.mjs +47 -0
- package/fesm2022/siemens-element-ng-system-banner.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-tabs-next.mjs +491 -0
- package/fesm2022/siemens-element-ng-tabs-next.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-tabs.mjs +395 -0
- package/fesm2022/siemens-element-ng-tabs.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-translate.mjs.map +1 -1
- package/fesm2022/siemens-element-ng-tree-view.mjs +2936 -0
- package/fesm2022/siemens-element-ng-tree-view.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-unauthorized-page.mjs +76 -0
- package/fesm2022/siemens-element-ng-unauthorized-page.mjs.map +1 -0
- package/fesm2022/siemens-element-ng-wizard.mjs +2 -2
- package/fesm2022/siemens-element-ng-wizard.mjs.map +1 -1
- package/file-uploader/index.d.ts +8 -0
- package/file-uploader/package.json +3 -0
- package/file-uploader/si-file-dropzone.component.d.ts +106 -0
- package/file-uploader/si-file-uploader.component.d.ts +296 -0
- package/file-uploader/si-file-uploader.model.d.ts +12 -0
- package/file-uploader/si-file-uploader.module.d.ts +8 -0
- package/filter-bar/filter.d.ts +26 -0
- package/filter-bar/index.d.ts +8 -0
- package/filter-bar/package.json +3 -0
- package/filter-bar/si-filter-bar.component.d.ts +65 -0
- package/filter-bar/si-filter-bar.module.d.ts +7 -0
- package/filter-bar/si-filter-pill.component.d.ts +20 -0
- package/filtered-search/index.d.ts +7 -0
- package/filtered-search/package.json +3 -0
- package/filtered-search/si-filtered-search-helper.d.ts +22 -0
- package/filtered-search/si-filtered-search-value.component.d.ts +53 -0
- package/filtered-search/si-filtered-search.component.d.ts +329 -0
- package/filtered-search/si-filtered-search.model.d.ts +139 -0
- package/filtered-search/si-filtered-search.module.d.ts +7 -0
- package/filtered-search/values/date-value/si-filtered-search-date-value.component.d.ts +57 -0
- package/filtered-search/values/si-filtered-search-value.base.d.ts +27 -0
- package/filtered-search/values/typeahead/si-filtered-search-typeahead.component.d.ts +45 -0
- package/formly/fields/button/si-formly-button.component.d.ts +7 -0
- package/formly/fields/date-range/si-formly-date-range.component.d.ts +6 -0
- package/formly/fields/datetime/si-formly-datetime.component.d.ts +13 -0
- package/formly/fields/email/si-formly-email.component.d.ts +6 -0
- package/formly/fields/ip-input/si-formly-ip-input.component.d.ts +6 -0
- package/formly/fields/number/si-formly-number.component.d.ts +6 -0
- package/formly/fields/password/si-formly-password.component.d.ts +6 -0
- package/formly/fields/select/si-formly-select.component.d.ts +6 -0
- package/formly/fields/text/si-formly-text-display.component.d.ts +7 -0
- package/formly/fields/textarea/si-formly-textarea.component.d.ts +18 -0
- package/formly/fields/time/si-formly-time.component.d.ts +13 -0
- package/formly/index.d.ts +6 -0
- package/formly/package.json +3 -0
- package/formly/si-formly-translate.extension.d.ts +11 -0
- package/formly/si-formly.component.d.ts +62 -0
- package/formly/si-formly.module.d.ts +35 -0
- package/formly/structural/si-formly-accordion/si-formly-accordion.component.d.ts +13 -0
- package/formly/structural/si-formly-array/si-formly-array.component.d.ts +6 -0
- package/formly/structural/si-formly-object/si-formly-object.component.d.ts +6 -0
- package/formly/structural/si-formly-object-grid/si-formly-object-grid.component.d.ts +22 -0
- package/formly/structural/si-formly-object-grid/si-formly-object-grid.model.d.ts +21 -0
- package/formly/structural/si-formly-object-plain/si-formly-object-plain.component.d.ts +6 -0
- package/formly/structural/si-formly-tabset/si-formly-object-tabset.component.d.ts +7 -0
- package/formly/utils.d.ts +6 -0
- package/formly/wrapper/si-formly-fieldset.component.d.ts +8 -0
- package/formly/wrapper/si-formly-form-field-provider.directive.d.ts +19 -0
- package/formly/wrapper/si-formly-horizontal-wrapper.component.d.ts +6 -0
- package/formly/wrapper/si-formly-icon-wrapper.component.d.ts +6 -0
- package/formly/wrapper/si-formly-wrapper.component.d.ts +8 -0
- package/icon/element-icons.d.ts +15 -0
- package/icon/si-status-icon.component.d.ts +6 -1
- package/info-page/index.d.ts +5 -0
- package/info-page/package.json +3 -0
- package/info-page/si-info-page.component.d.ts +38 -0
- package/inline-notification/si-inline-notification.component.d.ts +0 -2
- package/ip-input/address-utils.d.ts +28 -0
- package/ip-input/address-validators.d.ts +21 -0
- package/ip-input/index.d.ts +7 -0
- package/ip-input/package.json +3 -0
- package/ip-input/si-ip-input.directive.d.ts +53 -0
- package/ip-input/si-ip4-input.directive.d.ts +9 -0
- package/ip-input/si-ip6-input.directive.d.ts +10 -0
- package/list-details/index.d.ts +12 -0
- package/list-details/package.json +3 -0
- package/list-details/si-details-pane/si-details-pane.component.d.ts +8 -0
- package/list-details/si-details-pane-body/si-details-pane-body.component.d.ts +6 -0
- package/list-details/si-details-pane-footer/si-details-pane-footer.component.d.ts +6 -0
- package/list-details/si-details-pane-header/si-details-pane-header.component.d.ts +38 -0
- package/list-details/si-list-details.component.d.ts +100 -0
- package/list-details/si-list-pane/si-list-pane.component.d.ts +10 -0
- package/list-details/si-list-pane-body/si-list-pane-body.component.d.ts +6 -0
- package/list-details/si-list-pane-header/si-list-pane-header.component.d.ts +6 -0
- package/loading-spinner/si-loading-spinner.directive.d.ts +3 -2
- package/localization/index.d.ts +8 -0
- package/localization/package.json +3 -0
- package/localization/si-directionality.d.ts +41 -0
- package/localization/si-locale-id.d.ts +22 -0
- package/localization/si-locale-store.d.ts +16 -0
- package/localization/si-locale.service.d.ts +73 -0
- package/package.json +161 -9
- package/password-strength/si-password-strength.directive.d.ts +11 -0
- package/phone-number/index.d.ts +7 -0
- package/phone-number/package.json +3 -0
- package/phone-number/si-phone-number-input-select.directive.d.ts +10 -0
- package/phone-number/si-phone-number-input.component.d.ts +137 -0
- package/phone-number/si-phone-number-input.models.d.ts +48 -0
- package/phone-number/si-phone-number-input.module.d.ts +7 -0
- package/photo-upload/index.d.ts +6 -0
- package/photo-upload/package.json +3 -0
- package/photo-upload/si-image-cropper-style.component.d.ts +5 -0
- package/photo-upload/si-photo-upload.component.d.ts +298 -0
- package/result-details-list/index.d.ts +7 -0
- package/result-details-list/package.json +3 -0
- package/result-details-list/si-result-details-list.component.d.ts +14 -0
- package/result-details-list/si-result-details-list.datamodel.d.ts +48 -0
- package/result-details-list/si-result-details-list.module.d.ts +7 -0
- package/search-bar/index.d.ts +6 -0
- package/search-bar/package.json +3 -0
- package/search-bar/si-search-bar.component.d.ts +87 -0
- package/search-bar/si-search-bar.module.d.ts +7 -0
- package/shadow-root/index.d.ts +5 -0
- package/shadow-root/package.json +3 -0
- package/shadow-root/si-shadow-root.directive.d.ts +39 -0
- package/side-panel/index.d.ts +9 -0
- package/side-panel/package.json +3 -0
- package/side-panel/si-side-panel-content.component.d.ts +105 -0
- package/side-panel/si-side-panel.component.d.ts +108 -0
- package/side-panel/si-side-panel.module.d.ts +8 -0
- package/side-panel/si-side-panel.service.d.ts +45 -0
- package/side-panel/side-panel.model.d.ts +16 -0
- package/slider/index.d.ts +6 -0
- package/slider/package.json +3 -0
- package/slider/si-slider.component.d.ts +129 -0
- package/slider/si-slider.module.d.ts +7 -0
- package/sort-bar/index.d.ts +6 -0
- package/sort-bar/package.json +3 -0
- package/sort-bar/si-sort-bar.component.d.ts +42 -0
- package/sort-bar/si-sort-bar.module.d.ts +7 -0
- package/split/index.d.ts +8 -0
- package/split/package.json +3 -0
- package/split/si-split-part.component.d.ts +154 -0
- package/split/si-split.component.d.ts +48 -0
- package/split/si-split.interfaces.d.ts +17 -0
- package/split/si-split.module.d.ts +8 -0
- package/status-bar/index.d.ts +7 -0
- package/status-bar/package.json +3 -0
- package/status-bar/si-status-bar-item/index.d.ts +6 -0
- package/status-bar/si-status-bar-item/si-status-bar-item.component.d.ts +22 -0
- package/status-bar/si-status-bar-item/si-status-bar-item.model.d.ts +33 -0
- package/status-bar/si-status-bar.component.d.ts +116 -0
- package/status-bar/si-status-bar.module.d.ts +7 -0
- package/status-toggle/index.d.ts +6 -0
- package/status-toggle/package.json +3 -0
- package/status-toggle/si-status-toggle.component.d.ts +54 -0
- package/status-toggle/status-toggle.model.d.ts +26 -0
- package/system-banner/index.d.ts +5 -0
- package/system-banner/package.json +3 -0
- package/system-banner/system-banner.component.d.ts +23 -0
- package/tabs/index.d.ts +7 -0
- package/tabs/package.json +3 -0
- package/tabs/si-tab/index.d.ts +5 -0
- package/tabs/si-tab/si-tab.component.d.ts +58 -0
- package/tabs/si-tabs.module.d.ts +8 -0
- package/tabs/si-tabset/index.d.ts +5 -0
- package/tabs/si-tabset/si-tabset.component.d.ts +100 -0
- package/tabs-next/index.d.ts +7 -0
- package/tabs-next/package.json +3 -0
- package/tabs-next/si-tab-next-base.directive.d.ts +66 -0
- package/tabs-next/si-tab-next-link.component.d.ts +18 -0
- package/tabs-next/si-tab-next.component.d.ts +16 -0
- package/tabs-next/si-tabs-tokens.d.ts +7 -0
- package/tabs-next/si-tabset-next.component.d.ts +72 -0
- package/template-i18n.json +111 -0
- package/translate/si-translatable-keys.interface.d.ts +111 -0
- package/tree-view/drag-drop.util.d.ts +32 -0
- package/tree-view/index.d.ts +12 -0
- package/tree-view/package.json +3 -0
- package/tree-view/si-tree-view-converter.service.d.ts +41 -0
- package/tree-view/si-tree-view-item/si-tree-view-item.component.d.ts +105 -0
- package/tree-view/si-tree-view-item/si-tree-view-item.directive.d.ts +24 -0
- package/tree-view/si-tree-view-item-context.d.ts +11 -0
- package/tree-view/si-tree-view-item-height.service.d.ts +49 -0
- package/tree-view/si-tree-view-item-template.directive.d.ts +18 -0
- package/tree-view/si-tree-view-virtualization.service.d.ts +150 -0
- package/tree-view/si-tree-view.component.d.ts +466 -0
- package/tree-view/si-tree-view.model.d.ts +146 -0
- package/tree-view/si-tree-view.module.d.ts +10 -0
- package/tree-view/si-tree-view.service.d.ts +55 -0
- package/tree-view/si-tree-view.utils.d.ts +46 -0
- package/unauthorized-page/index.d.ts +6 -0
- package/unauthorized-page/package.json +3 -0
- package/unauthorized-page/si-unauthorized-page.component.d.ts +35 -0
- package/unauthorized-page/si-unauthorized-page.module.d.ts +7 -0
|
@@ -0,0 +1,2936 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, inject, TemplateRef, Directive, InjectionToken, Injectable, ElementRef, ChangeDetectorRef, signal, computed, HostListener, HostBinding, ViewChild, Component, EventEmitter, ViewContainerRef, IterableDiffers, Injector, booleanAttribute, output, ContentChildren, ContentChild, ViewChildren, NgModule } from '@angular/core';
|
|
3
|
+
import { CdkContextMenuTrigger, CdkMenuTrigger } from '@angular/cdk/menu';
|
|
4
|
+
import { NgClass, NgTemplateOutlet } from '@angular/common';
|
|
5
|
+
import { correctKeyRTL, buildTrackByIdentity } from '@siemens/element-ng/common';
|
|
6
|
+
import { SiLoadingSpinnerComponent } from '@siemens/element-ng/loading-spinner';
|
|
7
|
+
import { SiMenuFactoryComponent } from '@siemens/element-ng/menu';
|
|
8
|
+
import * as i1 from '@siemens/element-translate-ng/translate';
|
|
9
|
+
import { SiTranslateModule } from '@siemens/element-translate-ng/translate';
|
|
10
|
+
import { Subject, asyncScheduler, defer, fromEvent, merge } from 'rxjs';
|
|
11
|
+
import { takeUntil, take, withLatestFrom, map } from 'rxjs/operators';
|
|
12
|
+
import { FocusKeyManager } from '@angular/cdk/a11y';
|
|
13
|
+
import * as i2 from '@angular/cdk/scrolling';
|
|
14
|
+
import { CdkScrollableModule } from '@angular/cdk/scrolling';
|
|
15
|
+
import { ResizeObserverService } from '@siemens/element-ng/resize-observer';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Copyright Siemens 2016 - 2025.
|
|
19
|
+
* SPDX-License-Identifier: MIT
|
|
20
|
+
*/
|
|
21
|
+
class SiTreeViewItemTemplateDirective {
|
|
22
|
+
/** @defaultValue undefined */
|
|
23
|
+
name = input(undefined, { alias: 'siTreeViewItemTemplate' });
|
|
24
|
+
/** @internal */
|
|
25
|
+
template = inject((TemplateRef));
|
|
26
|
+
static ngTemplateContextGuard(dir, ctx) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewItemTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
30
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.6", type: SiTreeViewItemTemplateDirective, isStandalone: true, selector: "[siTreeViewItemTemplate]", inputs: { name: { classPropertyName: "name", publicName: "siTreeViewItemTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
31
|
+
}
|
|
32
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewItemTemplateDirective, decorators: [{
|
|
33
|
+
type: Directive,
|
|
34
|
+
args: [{
|
|
35
|
+
selector: '[siTreeViewItemTemplate]'
|
|
36
|
+
}]
|
|
37
|
+
}] });
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Copyright Siemens 2016 - 2025.
|
|
41
|
+
* SPDX-License-Identifier: MIT
|
|
42
|
+
*/
|
|
43
|
+
const TREE_ITEM_CONTEXT = new InjectionToken('TREE_ITEM_CONTEXT');
|
|
44
|
+
|
|
45
|
+
class FolderStateEventArgs {
|
|
46
|
+
treeItem;
|
|
47
|
+
oldState;
|
|
48
|
+
newState;
|
|
49
|
+
constructor(treeItem, oldState, newState) {
|
|
50
|
+
this.treeItem = treeItem;
|
|
51
|
+
this.oldState = oldState;
|
|
52
|
+
this.newState = newState;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
class CheckboxClickEventArgs {
|
|
56
|
+
target;
|
|
57
|
+
oldState;
|
|
58
|
+
newState;
|
|
59
|
+
constructor(target, oldState, newState) {
|
|
60
|
+
this.target = target;
|
|
61
|
+
this.oldState = oldState;
|
|
62
|
+
this.newState = newState;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
class ClickEventArgs {
|
|
66
|
+
target;
|
|
67
|
+
mouseEvent;
|
|
68
|
+
constructor(target, mouseEvent) {
|
|
69
|
+
this.target = target;
|
|
70
|
+
this.mouseEvent = mouseEvent;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
class LoadChildrenEventArgs {
|
|
74
|
+
treeItem;
|
|
75
|
+
callback;
|
|
76
|
+
constructor(treeItem, callback) {
|
|
77
|
+
this.treeItem = treeItem;
|
|
78
|
+
this.callback = callback;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
class ItemsVirtualizedArgs {
|
|
82
|
+
treeItems;
|
|
83
|
+
virtualized;
|
|
84
|
+
constructor(treeItems, virtualized) {
|
|
85
|
+
this.treeItems = treeItems;
|
|
86
|
+
this.virtualized = virtualized;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const DEFAULT_TREE_ICON_SET = {
|
|
90
|
+
headerHome: 'element-home',
|
|
91
|
+
headerArrow: 'element-left-2 flip-rtl',
|
|
92
|
+
itemMenu: 'element-options-vertical',
|
|
93
|
+
itemCollapsed: 'element-down-2',
|
|
94
|
+
itemCollapsedFlat: 'element-right-2 flip-rtl',
|
|
95
|
+
itemCollapsedLeft: 'element-right-2 flip-rtl',
|
|
96
|
+
itemExpanded: 'element-up-2',
|
|
97
|
+
itemExpandedFlat: 'element-down-3',
|
|
98
|
+
itemExpandedLeft: 'element-down-2'
|
|
99
|
+
};
|
|
100
|
+
const DEFAULT_CHILDREN_INDENTATION = 14;
|
|
101
|
+
|
|
102
|
+
const ROOT_LEVEL = -1;
|
|
103
|
+
const childrenLoaded = (item) => (item.children?.length ?? 0) > 0;
|
|
104
|
+
const hasChildren = (item) => item.state !== 'leaf';
|
|
105
|
+
const removeUndefinedState = (state) => state ?? 'collapsed';
|
|
106
|
+
/**
|
|
107
|
+
* Collapses the tree item except for leaf items.
|
|
108
|
+
*/
|
|
109
|
+
const collapse = (item) => {
|
|
110
|
+
if (item?.state !== 'leaf') {
|
|
111
|
+
item.state = 'collapsed';
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Expands the tree item except for leaf items.
|
|
116
|
+
*/
|
|
117
|
+
const expand = (item) => {
|
|
118
|
+
if (item?.state !== 'leaf') {
|
|
119
|
+
item.state = 'expanded';
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const expandRecursive = (item) => {
|
|
123
|
+
if (item.parent) {
|
|
124
|
+
expand(item.parent);
|
|
125
|
+
expandRecursive(item.parent);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const boxClicked = (treeItem, inheritChecked) => {
|
|
129
|
+
if (treeItem.showCheckbox) {
|
|
130
|
+
treeItem.checked = treeItem.checked === 'checked' ? 'unchecked' : 'checked';
|
|
131
|
+
if (inheritChecked) {
|
|
132
|
+
checkAllChildren(treeItem, treeItem.checked);
|
|
133
|
+
updateCheckStateOfParents(treeItem);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (treeItem.showOptionbox && treeItem.checked === 'unchecked') {
|
|
137
|
+
treeItem.parent?.children?.forEach(item => (item.checked = 'unchecked'));
|
|
138
|
+
treeItem.checked = 'checked';
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Changes the folder state to a new state based on the old state.
|
|
143
|
+
* If a client calls this method, the same is responsible to load the children in case the new state is 'expanding'!!!
|
|
144
|
+
*
|
|
145
|
+
* @param deleteChildrenOnCollapse - If set to true, the children are deleted upon collapsing the item.
|
|
146
|
+
*/
|
|
147
|
+
const doFolderStateChange = (item, deleteChildrenOnCollapse, newState) => {
|
|
148
|
+
if (item?.state === 'collapsed' && (!newState || newState === 'expanded')) {
|
|
149
|
+
item.state = childrenLoaded(item) ? 'expanded' : 'expanding';
|
|
150
|
+
}
|
|
151
|
+
else if (item?.state === 'expanding' && (!newState || newState === 'collapsed')) {
|
|
152
|
+
item.state = 'collapsed';
|
|
153
|
+
}
|
|
154
|
+
else if (item?.state === 'expanded' && (!newState || newState === 'collapsed')) {
|
|
155
|
+
if (deleteChildrenOnCollapse) {
|
|
156
|
+
item.children = [];
|
|
157
|
+
}
|
|
158
|
+
item.state = 'collapsed';
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const enableCheckboxRecursive = (item, enable) => {
|
|
162
|
+
item.showCheckbox = enable;
|
|
163
|
+
if (childrenLoaded(item)) {
|
|
164
|
+
item.children?.forEach(child => enableCheckboxRecursive(child, enable));
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const enableOptionboxRecursive = (item, enable) => {
|
|
168
|
+
item.showOptionbox = enable;
|
|
169
|
+
if (childrenLoaded(item)) {
|
|
170
|
+
item.children?.forEach(child => enableOptionboxRecursive(child, enable));
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const parentCountRecursive = (item, stackLevel) => {
|
|
174
|
+
if (item?.parent && item.parent.level !== ROOT_LEVEL) {
|
|
175
|
+
return parentCountRecursive(item.parent, stackLevel + 1);
|
|
176
|
+
}
|
|
177
|
+
return stackLevel;
|
|
178
|
+
};
|
|
179
|
+
const selectItemsBetween = (roots, start, end) => {
|
|
180
|
+
if (start === end) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const foundItems = [];
|
|
184
|
+
const inBetweenState = { startIsFirst: false, inBetween: false, done: false };
|
|
185
|
+
for (const root of roots) {
|
|
186
|
+
getItemsBetweenRecursive(foundItems, root, start, end, inBetweenState);
|
|
187
|
+
if (inBetweenState.done) {
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
foundItems.forEach(item => {
|
|
192
|
+
if (item.selectable) {
|
|
193
|
+
item.selected = true;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
return foundItems;
|
|
197
|
+
};
|
|
198
|
+
const selectRecursive = (item, select) => {
|
|
199
|
+
if (item.selectable) {
|
|
200
|
+
item.selected = select;
|
|
201
|
+
}
|
|
202
|
+
if (childrenLoaded(item)) {
|
|
203
|
+
item.children?.forEach(child => selectRecursive(child, select));
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const setBoxStateRecursive = (item, state) => {
|
|
207
|
+
item.checked = state;
|
|
208
|
+
if (childrenLoaded(item)) {
|
|
209
|
+
item.children?.forEach(child => setBoxStateRecursive(child, state));
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Sets the item to be active or not; all other items of the tree are reset.
|
|
214
|
+
*/
|
|
215
|
+
const setActive = (item, active) => {
|
|
216
|
+
const getRoot = (treeItem) => treeItem.parent ? getRoot(treeItem.parent) : treeItem;
|
|
217
|
+
resetActive(getRoot(item));
|
|
218
|
+
item.active = active;
|
|
219
|
+
};
|
|
220
|
+
const resetActive = (item) => {
|
|
221
|
+
item.active = false;
|
|
222
|
+
if (childrenLoaded(item)) {
|
|
223
|
+
item.children?.forEach(childItem => resetActive(childItem));
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Sets the treeItem as selectable or not
|
|
228
|
+
*/
|
|
229
|
+
const setSelectable = (item, selectable) => {
|
|
230
|
+
item.selectable = selectable;
|
|
231
|
+
if (item.selected && !item.selectable) {
|
|
232
|
+
item.selected = selectable;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
const deleteItem = (item) => {
|
|
236
|
+
if (item.parent) {
|
|
237
|
+
const idx = item.parent.children?.indexOf(item) ?? -1;
|
|
238
|
+
if (idx < 0) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
item.parent.children?.splice(idx, 1);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
const addChildItem = (parent, child, position, callback) => {
|
|
245
|
+
addChildItems(parent, [child], position, callback);
|
|
246
|
+
};
|
|
247
|
+
const addChildItems = (parent, children, position, callback) => {
|
|
248
|
+
const itemCount = parent.children?.length ?? 0;
|
|
249
|
+
position ??= itemCount;
|
|
250
|
+
// Negative position insert items counting from the last item
|
|
251
|
+
if (position < 0) {
|
|
252
|
+
position = itemCount + (position % itemCount);
|
|
253
|
+
}
|
|
254
|
+
initializeTreeItemsRecursive(children, parent, callback);
|
|
255
|
+
if (!parent.children) {
|
|
256
|
+
parent.children = [];
|
|
257
|
+
parent.children.push(...children);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (position >= parent.children.length) {
|
|
261
|
+
parent.children.push(...children);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
parent.children.splice(position, 0, ...children);
|
|
265
|
+
};
|
|
266
|
+
const initializeTreeItemsRecursive = (items, parent, callback) => {
|
|
267
|
+
const level = (parent.level ?? -1) + 1;
|
|
268
|
+
for (const item of items) {
|
|
269
|
+
item.parent = parent;
|
|
270
|
+
item.level = level;
|
|
271
|
+
setTreeItemDefaults(item, callback);
|
|
272
|
+
if (item.children?.length) {
|
|
273
|
+
initializeTreeItemsRecursive(item.children, item, callback);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
const setTreeItemDefaults = (item, callback) => {
|
|
278
|
+
item.children ??= [];
|
|
279
|
+
item.state ??= 'collapsed';
|
|
280
|
+
item.active ??= false;
|
|
281
|
+
item.checked ??= 'unchecked';
|
|
282
|
+
item.selected ??= false;
|
|
283
|
+
item.selectable ??= true;
|
|
284
|
+
if (callback) {
|
|
285
|
+
callback(item);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
const checkAllChildren = (treeItem, check) => {
|
|
289
|
+
if (childrenLoaded(treeItem)) {
|
|
290
|
+
treeItem.children?.forEach(item => {
|
|
291
|
+
item.checked = check;
|
|
292
|
+
checkAllChildren(item, check);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
const getItemsBetweenRecursive = (found, current, start, end, inBetweenState) => {
|
|
297
|
+
if (inBetweenState.done) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (current === start && !inBetweenState.inBetween) {
|
|
301
|
+
// This is the first found tree item within the selection, the start tree item (the item which is clicked first) is ordered
|
|
302
|
+
// before the end tree item (the item which is clicked second).
|
|
303
|
+
// The recursive function is from now on handling tree node which are in between the two selections.
|
|
304
|
+
// Note, we don't need to select it, as it is already selected with previous click
|
|
305
|
+
inBetweenState.startIsFirst = true;
|
|
306
|
+
inBetweenState.inBetween = true;
|
|
307
|
+
}
|
|
308
|
+
else if (current === end && !inBetweenState.inBetween) {
|
|
309
|
+
// This is the first found tree item within the selection, the end tree item (the item which is clicked second) is ordered
|
|
310
|
+
// before the start tree item (the item which is clicked first).
|
|
311
|
+
// The recursive function is from now on handling tree node which are in between the two selections.
|
|
312
|
+
inBetweenState.startIsFirst = false;
|
|
313
|
+
inBetweenState.inBetween = true;
|
|
314
|
+
found.push(current);
|
|
315
|
+
}
|
|
316
|
+
else if (current === end && inBetweenState.inBetween) {
|
|
317
|
+
found.push(current);
|
|
318
|
+
inBetweenState.inBetween = false;
|
|
319
|
+
inBetweenState.done = true;
|
|
320
|
+
return; // the end of the search
|
|
321
|
+
}
|
|
322
|
+
else if (current === start && inBetweenState.inBetween) {
|
|
323
|
+
inBetweenState.inBetween = false;
|
|
324
|
+
inBetweenState.done = true;
|
|
325
|
+
return; // the end of the search
|
|
326
|
+
}
|
|
327
|
+
else if (inBetweenState.inBetween) {
|
|
328
|
+
found.push(current);
|
|
329
|
+
}
|
|
330
|
+
if (current.state === 'expanded') {
|
|
331
|
+
current.children?.forEach(item => getItemsBetweenRecursive(found, item, start, end, inBetweenState));
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
const updateCheckStateOfParents = (treeItem) => {
|
|
335
|
+
if (treeItem.parent) {
|
|
336
|
+
let allChecked = true;
|
|
337
|
+
let allUnchecked = true;
|
|
338
|
+
for (const item of treeItem.parent?.children ?? []) {
|
|
339
|
+
if (item.checked === 'indeterminate') {
|
|
340
|
+
treeItem.parent.checked = 'indeterminate';
|
|
341
|
+
updateCheckStateOfParents(treeItem.parent);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (item.checked === 'checked') {
|
|
345
|
+
allUnchecked = false;
|
|
346
|
+
}
|
|
347
|
+
if (item.checked === 'unchecked') {
|
|
348
|
+
allChecked = false;
|
|
349
|
+
}
|
|
350
|
+
if (!allChecked && !allUnchecked) {
|
|
351
|
+
treeItem.parent.checked = 'indeterminate';
|
|
352
|
+
updateCheckStateOfParents(treeItem.parent);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (allChecked) {
|
|
357
|
+
treeItem.parent.checked = 'checked';
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
treeItem.parent.checked = 'unchecked';
|
|
361
|
+
}
|
|
362
|
+
updateCheckStateOfParents(treeItem.parent);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Copyright Siemens 2016 - 2025.
|
|
368
|
+
* SPDX-License-Identifier: MIT
|
|
369
|
+
*/
|
|
370
|
+
/**
|
|
371
|
+
* Supports communication between the TreeViewComponent and the TreeViewItemComponent and the services.
|
|
372
|
+
* Stores tree specific settings.
|
|
373
|
+
* One instance per TreeViewComponent exists.
|
|
374
|
+
*/
|
|
375
|
+
class SiTreeViewService {
|
|
376
|
+
/** Emits when a tree item is clicked. */
|
|
377
|
+
clickEvent = new Subject();
|
|
378
|
+
/** Emits when a folder item is clicked. */
|
|
379
|
+
folderClickEvent = new Subject();
|
|
380
|
+
/** Emits when checkbox is clicked. */
|
|
381
|
+
checkboxClickEvent = new Subject();
|
|
382
|
+
/** Emits when on tree item expansion to load child items. */
|
|
383
|
+
loadChildrenEvent = new Subject();
|
|
384
|
+
/** Emits when the consumer want a node to be scrolled into view. */
|
|
385
|
+
scrollIntoViewEvent = new Subject();
|
|
386
|
+
/** Emits when the parent shall become focused. */
|
|
387
|
+
focusParentEvent = new Subject();
|
|
388
|
+
/** Emits when the child shall become focused. */
|
|
389
|
+
focusFirstChildEvent = new Subject();
|
|
390
|
+
/**
|
|
391
|
+
* Shows or hides context menu button.
|
|
392
|
+
*
|
|
393
|
+
* @defaultValue true
|
|
394
|
+
*/
|
|
395
|
+
enableContextMenuButton = true;
|
|
396
|
+
/**
|
|
397
|
+
* Child padding in pixel (px).
|
|
398
|
+
*
|
|
399
|
+
* @defaultValue 14
|
|
400
|
+
*/
|
|
401
|
+
childrenIndentation = 14;
|
|
402
|
+
/**
|
|
403
|
+
* Visualize tree as grouped list, the child padding will have no effect.
|
|
404
|
+
*
|
|
405
|
+
* @defaultValue false
|
|
406
|
+
*/
|
|
407
|
+
groupedList = false;
|
|
408
|
+
/** @internal */
|
|
409
|
+
triggerMarkForCheck = new Subject();
|
|
410
|
+
/** @internal */
|
|
411
|
+
scroll$;
|
|
412
|
+
/** Indicate whether item is a group item. */
|
|
413
|
+
isGroupedItem(item) {
|
|
414
|
+
return (!item.parent || item.parent.level === ROOT_LEVEL) && this.groupedList;
|
|
415
|
+
}
|
|
416
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
417
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewService });
|
|
418
|
+
}
|
|
419
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewService, decorators: [{
|
|
420
|
+
type: Injectable
|
|
421
|
+
}] });
|
|
422
|
+
|
|
423
|
+
class SiTreeViewItemComponent {
|
|
424
|
+
element = inject(ElementRef);
|
|
425
|
+
siTreeViewService = inject(SiTreeViewService);
|
|
426
|
+
cdRef = inject(ChangeDetectorRef);
|
|
427
|
+
treeItemContext = inject(TREE_ITEM_CONTEXT);
|
|
428
|
+
treeViewComponent = this.treeItemContext.parent;
|
|
429
|
+
/** @internal */
|
|
430
|
+
treeItem = this.treeItemContext.record.item;
|
|
431
|
+
scrollIntoView = this.treeViewComponent.scrollChildIntoView;
|
|
432
|
+
childrenLoaded = this.treeViewComponent.childrenLoaded;
|
|
433
|
+
templates = this.treeViewComponent.templates;
|
|
434
|
+
_contextMenuItems = this.treeViewComponent.contextMenuItems;
|
|
435
|
+
contextMenuItems = signal([]);
|
|
436
|
+
isContextMenuButtonVisible = computed(() => {
|
|
437
|
+
return (this.enableContextMenuButton() &&
|
|
438
|
+
!!this._contextMenuItems() &&
|
|
439
|
+
!!this.contextMenuItems()?.length);
|
|
440
|
+
});
|
|
441
|
+
stickyEndItems = this.treeViewComponent.horizontalScrolling;
|
|
442
|
+
displayFolderState = this.treeViewComponent.hasAnyChildren;
|
|
443
|
+
icons = this.treeViewComponent.computedIcons;
|
|
444
|
+
savedElement;
|
|
445
|
+
subscriptions = [];
|
|
446
|
+
indentLevel = this.treeItem.level ?? 0;
|
|
447
|
+
nextSiblingElement;
|
|
448
|
+
menuTrigger;
|
|
449
|
+
get ariaLevel() {
|
|
450
|
+
return (this.treeItem.level ?? 0) + 1;
|
|
451
|
+
}
|
|
452
|
+
get ariaSetsize() {
|
|
453
|
+
return this.treeItem.parent?.children?.length ?? 1;
|
|
454
|
+
}
|
|
455
|
+
ariaPosinset;
|
|
456
|
+
get ariaSelected() {
|
|
457
|
+
return this.enableSelection() && this.treeItem.selectable ? !!this.treeItem.selected : null;
|
|
458
|
+
}
|
|
459
|
+
get ariaChecked() {
|
|
460
|
+
return this.showCheckOrOptionBox && this.treeItem.selectable
|
|
461
|
+
? this.treeItem.checked === 'checked'
|
|
462
|
+
: null;
|
|
463
|
+
}
|
|
464
|
+
get ariaExpanded() {
|
|
465
|
+
if (this.treeItem.state === 'leaf') {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
return this.treeItem.state === 'expanded';
|
|
469
|
+
}
|
|
470
|
+
ngOnInit() {
|
|
471
|
+
this.subscriptions.push(this.scrollIntoView.subscribe(event => this.onScrollIntoViewByConsumer(event)));
|
|
472
|
+
this.subscriptions.push(this.childrenLoaded.subscribe(event => this.childrenLoadingDone(event)));
|
|
473
|
+
this.subscriptions.push(this.siTreeViewService.triggerMarkForCheck.subscribe(() => this.cdRef.markForCheck()));
|
|
474
|
+
this.updateContextMenuItem();
|
|
475
|
+
}
|
|
476
|
+
ngDoCheck() {
|
|
477
|
+
if (this.treeItem.parent?.children && this.ariaPosinset) {
|
|
478
|
+
if (this.treeItem.parent.children[this.ariaPosinset] !== this.treeItem) {
|
|
479
|
+
this.ariaPosinset = this.treeItem.parent.children.indexOf(this.treeItem) + 1;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
else if (this.treeItem.parent?.children) {
|
|
483
|
+
this.ariaPosinset = this.treeItem.parent.children.indexOf(this.treeItem) + 1;
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
this.ariaPosinset = 1;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
ngAfterViewInit() {
|
|
490
|
+
if (this.savedElement) {
|
|
491
|
+
this.siTreeViewService.scrollIntoViewEvent.next(this.savedElement);
|
|
492
|
+
this.savedElement = undefined;
|
|
493
|
+
}
|
|
494
|
+
this.nextSiblingElement = this.element.nativeElement?.nextElementSibling;
|
|
495
|
+
}
|
|
496
|
+
ngOnDestroy() {
|
|
497
|
+
this.subscriptions
|
|
498
|
+
.filter(subscription => !!subscription)
|
|
499
|
+
.forEach(subscription => subscription.unsubscribe());
|
|
500
|
+
}
|
|
501
|
+
enableSelection = this.treeViewComponent.enableSelection;
|
|
502
|
+
enableContextMenuButton = this.treeViewComponent.enableContextMenuButton;
|
|
503
|
+
enableDataField1 = this.treeViewComponent.enableDataField1;
|
|
504
|
+
enableDataField2 = this.treeViewComponent.enableDataField2;
|
|
505
|
+
deleteChildrenOnCollapse = this.treeViewComponent.deleteChildrenOnCollapse;
|
|
506
|
+
get paddingStart() {
|
|
507
|
+
return this.siTreeViewService.groupedList
|
|
508
|
+
? '0'
|
|
509
|
+
: this.indentLevel * this.siTreeViewService.childrenIndentation + 'px';
|
|
510
|
+
}
|
|
511
|
+
get biggerPaddingStart() {
|
|
512
|
+
const basePadding = this.showFolderStateStart ? 24 : 0;
|
|
513
|
+
return ((this.siTreeViewService.groupedList
|
|
514
|
+
? basePadding
|
|
515
|
+
: this.indentLevel * this.siTreeViewService.childrenIndentation + basePadding) + 'px');
|
|
516
|
+
}
|
|
517
|
+
get isGroupedItem() {
|
|
518
|
+
return this.siTreeViewService.isGroupedItem(this.treeItem);
|
|
519
|
+
}
|
|
520
|
+
get showFolderStateStart() {
|
|
521
|
+
return (this.displayFolderState &&
|
|
522
|
+
this.treeViewComponent.folderStateStart() &&
|
|
523
|
+
!this.treeViewComponent.flatTree() &&
|
|
524
|
+
(!!this.isGroupedItem || !this.siTreeViewService.groupedList));
|
|
525
|
+
}
|
|
526
|
+
get showFolderStateEnd() {
|
|
527
|
+
return this.displayFolderState && !this.showFolderStateStart;
|
|
528
|
+
}
|
|
529
|
+
get isExpanding() {
|
|
530
|
+
return this.treeItem.state === 'expanding';
|
|
531
|
+
}
|
|
532
|
+
showStateIndicator = this.treeViewComponent.enableStateIndicator;
|
|
533
|
+
showIcon = computed(() => {
|
|
534
|
+
return this.treeViewComponent.enableIcon() && !!this.treeItem.icon;
|
|
535
|
+
});
|
|
536
|
+
get showCheckOrOptionBox() {
|
|
537
|
+
return !!this.treeItem.showCheckbox || !!this.treeItem.showOptionbox;
|
|
538
|
+
}
|
|
539
|
+
updateContextMenuItem() {
|
|
540
|
+
const contextMenuItems = this._contextMenuItems();
|
|
541
|
+
if (contextMenuItems) {
|
|
542
|
+
if (Array.isArray(contextMenuItems)) {
|
|
543
|
+
this.contextMenuItems.set(contextMenuItems);
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
const menuItems = contextMenuItems(this.treeItem);
|
|
547
|
+
if (Array.isArray(menuItems)) {
|
|
548
|
+
this.contextMenuItems.set(menuItems);
|
|
549
|
+
}
|
|
550
|
+
else if (menuItems) {
|
|
551
|
+
this.subscriptions.push(menuItems.subscribe(items => {
|
|
552
|
+
this.contextMenuItems.set(items);
|
|
553
|
+
}));
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
getItemFolderStateClass() {
|
|
559
|
+
if (this.treeItem.state === 'collapsed') {
|
|
560
|
+
if (this.treeViewComponent.flatTree()) {
|
|
561
|
+
// flat tree mode
|
|
562
|
+
return this.icons().itemCollapsedFlat;
|
|
563
|
+
}
|
|
564
|
+
else if (this.treeViewComponent.folderStateStart()) {
|
|
565
|
+
// normal tree mode; folder state icon shown on the left (in LTR) side
|
|
566
|
+
return this.icons().itemCollapsedLeft; // si-tree-view-item-collapsed
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
// normal tree mode; folder state icon shown on the right (in LTR) side
|
|
570
|
+
return this.icons().itemCollapsed; // si-tree-view-item-collapsed
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
else if (this.treeItem.state === 'expanding') {
|
|
574
|
+
return 'si-tree-view-item-expanding'; // because empty is treated as disabled
|
|
575
|
+
}
|
|
576
|
+
else if (this.treeItem.state === 'expanded') {
|
|
577
|
+
if (this.treeViewComponent.flatTree()) {
|
|
578
|
+
// flat tree mode
|
|
579
|
+
return this.icons().itemExpandedFlat;
|
|
580
|
+
}
|
|
581
|
+
else if (this.treeViewComponent.folderStateStart()) {
|
|
582
|
+
// normal tree mode; folder state icon shown on the left (in LTR) side
|
|
583
|
+
return this.icons().itemExpandedLeft; // si-tree-view-item-expanded
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
// normal tree mode; folder state icon shown on the right (in LTR) side
|
|
587
|
+
return this.icons().itemExpanded; // si-tree-view-item-expanded
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return '';
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Show icon if the item is selected.
|
|
594
|
+
* Per default the `filled` icon is used, this can be configured using {@link disableFilledIcons}.
|
|
595
|
+
**/
|
|
596
|
+
getIconClass() {
|
|
597
|
+
let iconClass = this.treeItem.icon;
|
|
598
|
+
if (this.treeItem.selected && this.treeItem.selectable && this.enableSelection()) {
|
|
599
|
+
iconClass =
|
|
600
|
+
iconClass +
|
|
601
|
+
(!this.treeViewComponent.disableFilledIcons() ? ' ' + iconClass + '-filled' : '');
|
|
602
|
+
}
|
|
603
|
+
return iconClass ?? '';
|
|
604
|
+
}
|
|
605
|
+
getStateIndicatorColor() {
|
|
606
|
+
return this.treeItem ? (this.treeItem.stateIndicatorColor ?? '') : '';
|
|
607
|
+
}
|
|
608
|
+
onItemFolderClicked(newState) {
|
|
609
|
+
this.nextSiblingElement = this.element.nativeElement?.nextElementSibling;
|
|
610
|
+
const oldState = removeUndefinedState(this.treeItem.state);
|
|
611
|
+
doFolderStateChange(this.treeItem, this.deleteChildrenOnCollapse(), newState);
|
|
612
|
+
this.siTreeViewService.folderClickEvent.next(new FolderStateEventArgs(this.treeItem, oldState, removeUndefinedState(this.treeItem.state)));
|
|
613
|
+
if (this.treeItem.state === 'expanding') {
|
|
614
|
+
this.siTreeViewService.loadChildrenEvent.next(this.treeItem);
|
|
615
|
+
}
|
|
616
|
+
if (this.treeItem.state === 'expanded') {
|
|
617
|
+
this.scrollChildNodeIntoViewPort();
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
childrenLoadingDone(item) {
|
|
621
|
+
if (item === this.treeItem) {
|
|
622
|
+
asyncScheduler.schedule(() => this.scrollChildNodeIntoViewPort(), 0);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
scrollChildNodeIntoViewPort() {
|
|
626
|
+
const task = () => {
|
|
627
|
+
const container = this.element.nativeElement.closest('.si-tree-view');
|
|
628
|
+
const first = this.element.nativeElement;
|
|
629
|
+
this.nextSiblingElement =
|
|
630
|
+
this.nextSiblingElement?.previousElementSibling ?? this.nextSiblingElement;
|
|
631
|
+
const last = container?.contains(this.nextSiblingElement)
|
|
632
|
+
? this.nextSiblingElement
|
|
633
|
+
: this.element.nativeElement.parentElement?.lastElementChild;
|
|
634
|
+
const fits = container?.offsetHeight -
|
|
635
|
+
(last?.offsetTop + last?.getBoundingClientRect().height - first?.offsetTop) >=
|
|
636
|
+
0;
|
|
637
|
+
const targetElement = fits ? last : first;
|
|
638
|
+
if (targetElement) {
|
|
639
|
+
const observer = new window.IntersectionObserver(([entry]) => {
|
|
640
|
+
requestAnimationFrame(() => {
|
|
641
|
+
const scrollElement = targetElement.firstChild ?? targetElement;
|
|
642
|
+
if (fits) {
|
|
643
|
+
scrollElement.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
644
|
+
}
|
|
645
|
+
else {
|
|
646
|
+
// scrollIntoView messes up with page scroll when body also has a scroll for { block : 'start' }
|
|
647
|
+
const totalScrollTop = container?.scrollTop +
|
|
648
|
+
first?.getBoundingClientRect().top -
|
|
649
|
+
container?.getBoundingClientRect().top;
|
|
650
|
+
container?.scrollTo({ top: totalScrollTop, behavior: 'smooth' });
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
observer.disconnect();
|
|
654
|
+
}, {
|
|
655
|
+
root: null,
|
|
656
|
+
threshold: 1
|
|
657
|
+
});
|
|
658
|
+
observer.observe(targetElement);
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
asyncScheduler.schedule(task, 0);
|
|
662
|
+
}
|
|
663
|
+
onItemClicked(event) {
|
|
664
|
+
const previousActive = this.treeItem.active;
|
|
665
|
+
this.siTreeViewService.clickEvent.next(new ClickEventArgs(this.treeItem, event));
|
|
666
|
+
if (!this.enableSelection() &&
|
|
667
|
+
(this.treeViewComponent.enableCheckbox() || this.treeViewComponent.enableOptionbox())) {
|
|
668
|
+
this.onBoxClicked();
|
|
669
|
+
}
|
|
670
|
+
// Toggle expand when item is collapsed, collapse only if the node is active
|
|
671
|
+
const toggle = (this.treeItem.state === 'expanded' && previousActive) || this.treeItem.state === 'collapsed';
|
|
672
|
+
if (this.expandOnClick() && toggle) {
|
|
673
|
+
this.onItemFolderClicked();
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
onMouseDownTreeItem(event) {
|
|
677
|
+
if (event.shiftKey) {
|
|
678
|
+
// let selection: Selection = window.getSelection();
|
|
679
|
+
// selection.removeAllRanges();
|
|
680
|
+
// we do not want the tree item text selected: thus we prevent the default behavior in this situation
|
|
681
|
+
event.preventDefault();
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
onToggleContextMenuOpen() {
|
|
685
|
+
setActive(this.treeItem, true);
|
|
686
|
+
this.siTreeViewService.scroll$
|
|
687
|
+
.pipe(takeUntil(this.menuTrigger.closed), take(1))
|
|
688
|
+
.subscribe(() => this.menuTrigger?.close());
|
|
689
|
+
}
|
|
690
|
+
onToggleContextMenuClose() {
|
|
691
|
+
setTimeout(() => this.element.nativeElement.focus());
|
|
692
|
+
}
|
|
693
|
+
getInputType() {
|
|
694
|
+
// This method will be called only when either of the showCheckbox or showOptionBox is true, thus
|
|
695
|
+
// following condition can be shortened
|
|
696
|
+
return this.treeItem.showCheckbox ? 'checkbox' : 'radio';
|
|
697
|
+
}
|
|
698
|
+
onBoxClicked() {
|
|
699
|
+
if (!this.treeItem.selectable) {
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
const oldState = this.treeItem.checked ?? 'unchecked';
|
|
703
|
+
boxClicked(this.treeItem, this.treeViewComponent.inheritChecked());
|
|
704
|
+
this.siTreeViewService.checkboxClickEvent.next(new CheckboxClickEventArgs(this.treeItem, oldState, this.treeItem.checked ?? 'unchecked'));
|
|
705
|
+
}
|
|
706
|
+
renderMatchingTemplate(treeItem) {
|
|
707
|
+
// we check in the HTML template if templates exist.
|
|
708
|
+
const templateDirective = this.templates.find(td => td.name() === treeItem.templateName);
|
|
709
|
+
return templateDirective ? templateDirective.template : this.templates.toArray()[0].template;
|
|
710
|
+
}
|
|
711
|
+
onContextMenu(event) {
|
|
712
|
+
this.handleContextMenuEvent(event);
|
|
713
|
+
return false;
|
|
714
|
+
}
|
|
715
|
+
onKeydown(event) {
|
|
716
|
+
const rtlCorrectedKey = correctKeyRTL(event.key);
|
|
717
|
+
if (rtlCorrectedKey === 'Enter') {
|
|
718
|
+
event.preventDefault();
|
|
719
|
+
this.onItemClicked(event);
|
|
720
|
+
}
|
|
721
|
+
else if (rtlCorrectedKey === 'ContextMenu' || (rtlCorrectedKey === 'F10' && event.shiftKey)) {
|
|
722
|
+
this.handleContextMenuEvent(event);
|
|
723
|
+
}
|
|
724
|
+
else if (rtlCorrectedKey === 'ArrowLeft') {
|
|
725
|
+
if ((!this.treeViewComponent.flatTree() &&
|
|
726
|
+
this.showFolderStateStart &&
|
|
727
|
+
(this.treeItem.state !== 'leaf' || this.isGroupedItem)) ||
|
|
728
|
+
this.showFolderStateEnd) {
|
|
729
|
+
event.preventDefault();
|
|
730
|
+
if (this.treeItem.state !== 'collapsed' && this.treeItem.state !== 'leaf') {
|
|
731
|
+
this.onItemFolderClicked('collapsed');
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
this.siTreeViewService.focusParentEvent.next(this.treeItem);
|
|
736
|
+
}
|
|
737
|
+
else if (rtlCorrectedKey === 'ArrowRight') {
|
|
738
|
+
if ((this.showFolderStateStart && (this.treeItem.state !== 'leaf' || this.isGroupedItem)) ||
|
|
739
|
+
this.showFolderStateEnd) {
|
|
740
|
+
event.preventDefault();
|
|
741
|
+
if (this.treeItem.state !== 'expanded') {
|
|
742
|
+
this.onItemFolderClicked('expanded');
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
this.siTreeViewService.focusFirstChildEvent.next(this.treeItem);
|
|
747
|
+
}
|
|
748
|
+
else if (this.showCheckOrOptionBox &&
|
|
749
|
+
(rtlCorrectedKey === 'Space' || rtlCorrectedKey === ' ')) {
|
|
750
|
+
event.preventDefault();
|
|
751
|
+
this.onBoxClicked();
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
handleContextMenuEvent(event) {
|
|
755
|
+
if (this.isContextMenuButtonVisible() &&
|
|
756
|
+
this.contextMenuItems()?.some(item => (!item.type && !item.disabled && !item.isHeading && item.title !== '-') ||
|
|
757
|
+
(item.type !== 'divider' &&
|
|
758
|
+
item.type !== 'header' &&
|
|
759
|
+
(item.type !== 'radio-group' ||
|
|
760
|
+
item.children.some(radioItem => radioItem.type === 'radio' && !radioItem.disabled)) &&
|
|
761
|
+
item.type !== 'radio-group' &&
|
|
762
|
+
!item.disabled))) {
|
|
763
|
+
event.preventDefault();
|
|
764
|
+
event.stopPropagation();
|
|
765
|
+
// Without the setTimeout in Firefox native menu will open as well.
|
|
766
|
+
// Event suppression does not work.
|
|
767
|
+
// Re-check in the future if FF fixes it.
|
|
768
|
+
setTimeout(() => {
|
|
769
|
+
this.menuTrigger?.open();
|
|
770
|
+
this.menuTrigger?.getMenu().focusFirstItem('keyboard');
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
event.preventDefault();
|
|
775
|
+
event.stopPropagation();
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Focusses the tree item.
|
|
780
|
+
*/
|
|
781
|
+
focus() {
|
|
782
|
+
this.element.nativeElement.focus();
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Get tree item label.
|
|
786
|
+
*/
|
|
787
|
+
getLabel() {
|
|
788
|
+
return this.treeItem?.label ?? '';
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Called by the consumer when they want a node to be scrolled into view.
|
|
792
|
+
*/
|
|
793
|
+
onScrollIntoViewByConsumer(item) {
|
|
794
|
+
if (item === this.treeItem) {
|
|
795
|
+
this.savedElement = this.element;
|
|
796
|
+
this.siTreeViewService.scrollIntoViewEvent.next(this.element);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
expandOnClick() {
|
|
800
|
+
return (this.treeViewComponent.expandOnClick() &&
|
|
801
|
+
this.treeItem.state !== 'leaf' &&
|
|
802
|
+
!!this.treeItem.selectable &&
|
|
803
|
+
!this.treeViewComponent.flatTree());
|
|
804
|
+
}
|
|
805
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
806
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: SiTreeViewItemComponent, isStandalone: true, selector: "si-tree-view-item", host: { attributes: { "role": "treeitem" }, listeners: { "contextmenu": "onContextMenu($event)", "keydown": "onKeydown($event)" }, properties: { "attr.tabindex": "treeItemContext.record.currentIndex === treeViewComponent.activeIndex ? 0 : -1", "class.focus-none": "true", "class.si-tree-ellipsis": "treeViewComponent.horizontalScrolling()", "class.si-tree-view-top-level-item": "!treeViewComponent.compactMode() && (treeViewComponent.flatTree() || (treeItem.level ?? 0) < 1)", "attr.aria-haspopup": "isContextMenuButtonVisible()", "attr.aria-level": "this.ariaLevel", "attr.aria-setsize": "this.ariaSetsize", "attr.aria-posinset": "this.ariaPosinset", "attr.aria-selected": "this.ariaSelected", "attr.aria-checked": "this.ariaChecked", "attr.aria-expanded": "this.ariaExpanded" } }, viewQueries: [{ propertyName: "menuTrigger", first: true, predicate: CdkMenuTrigger, descendants: true }], ngImport: i0, template: "@if (!isGroupedItem) {\n <div\n #contextMenuTrigger=\"cdkContextMenuTriggerFor\"\n class=\"si-tree-view-li si-tree-view-li-item focus-direct-sub-inside\"\n [class.si-tree-view-item-context-menu-visible]=\"\n !!(contextMenuTrigger.isOpen() || menuTrigger?.isOpen())\n \"\n [class.si-tree-view-item-active]=\"treeItem.active\"\n [class.si-tree-view-item-selected]=\"enableSelection() && treeItem.selected\"\n [class.si-tree-view-item-not-selectable]=\"!treeItem.selectable\"\n [style.padding-inline-start]=\"biggerPaddingStart\"\n [cdkContextMenuTriggerFor]=\"contextMenu\"\n [cdkContextMenuDisabled]=\"!isContextMenuButtonVisible() || !treeItem.selectable\"\n (cdkContextMenuOpened)=\"onToggleContextMenuOpen()\"\n (cdkContextMenuClosed)=\"onToggleContextMenuClose()\"\n >\n <div class=\"si-tree-view-item\" (mousedown)=\"onMouseDownTreeItem($event)\">\n @if (showFolderStateStart && treeItem.state !== 'leaf') {\n <a\n class=\"si-tree-stretch-center si-tree-view-item-toggle\"\n tabindex=\"-1\"\n [style.margin-inline-start]=\"'-' + biggerPaddingStart\"\n [style.padding-inline-start]=\"paddingStart\"\n (click)=\"onItemFolderClicked()\"\n >\n @if (isExpanding) {\n <si-loading-spinner [@.disabled]=\"true\" />\n }\n @if (!isExpanding) {\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-dropdown-caret\"\n [ngClass]=\"getItemFolderStateClass()\"\n ></i>\n }\n </a>\n }\n @if (showCheckOrOptionBox) {\n <a class=\"form-check input-box\" tabindex=\"-1\">\n <input\n class=\"form-check-input\"\n tabindex=\"-1\"\n [type]=\"getInputType()\"\n [indeterminate]=\"this.treeItem.checked === 'indeterminate' ? true : null\"\n [checked]=\"this.treeItem.checked === 'checked'\"\n [disabled]=\"!treeItem.selectable\"\n [attr.aria-label]=\"treeItem.label | translate\"\n (click)=\"onBoxClicked()\"\n />\n </a>\n }\n <div\n class=\"si-tree-view-item-main d-flex flex-grow-1 align-self-stretch grab-area\"\n (click)=\"onItemClicked($event)\"\n >\n @if (showIcon()) {\n <div class=\"si-tree-stretch-center\">\n <span class=\"si-tree-view-item-icon\" [ngClass]=\"getIconClass()\"></span>\n </div>\n }\n <div\n class=\"si-tree-view-item-object-data d-flex flex-column justify-content-center overflow-hidden\"\n >\n @if (!templates.length) {\n <h5 class=\"text-truncate\">{{ treeItem.label | translate }}</h5>\n }\n @if (templates.length) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n renderMatchingTemplate(treeItem);\n context: { $implicit: treeItem }\n \"\n />\n </div>\n }\n @if (enableDataField1() && treeItem.dataField1) {\n <p class=\"si-tree-view-item-object-data-field-1 text-truncate\">{{\n treeItem.dataField1 | translate\n }}</p>\n }\n @if (enableDataField2() && treeItem.dataField2) {\n <p class=\"si-tree-view-item-object-data-field-2 text-truncate\">{{\n treeItem.dataField2 | translate\n }}</p>\n }\n </div>\n @if (treeItem.badge) {\n <span\n class=\"badge flex-shrink-0\"\n [ngClass]=\"'bg-' + (treeItem.badgeColor || 'default')\"\n >{{ treeItem.badge }}</span\n >\n }\n </div>\n <div\n class=\"si-tree-view-item-end-icons d-flex ms-2 align-items-center\"\n [class.si-tree-view-item-end-icons-sticky]=\"stickyEndItems()\"\n >\n @if (showStateIndicator() && getStateIndicatorColor()) {\n <div\n class=\"si-tree-view-state-indicator\"\n [style.background-color]=\"getStateIndicatorColor()\"\n [class.si-tree-view-state-indicator-endmost]=\"\n !enableContextMenuButton() && !showFolderStateEnd\n \"\n ></div>\n }\n @if (isContextMenuButtonVisible()) {\n <div class=\"si-tree-stretch-center si-tree-context-menu-btn\">\n <div\n #menuTrigger=\"cdkMenuTriggerFor\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [cdkMenuTriggerFor]=\"contextMenu\"\n (cdkMenuOpened)=\"onToggleContextMenuOpen()\"\n (cdkMenuClosed)=\"onToggleContextMenuClose()\"\n >\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-icon si-tree-view-menu-btn\"\n [ngClass]=\"icons().itemMenu\"\n ></i>\n </div>\n </div>\n }\n @if (showFolderStateEnd && treeItem.state !== 'leaf') {\n <a\n class=\"si-tree-stretch-center si-tree-view-item-toggle si-tree-view-item-toggle-end\"\n tabindex=\"-1\"\n [class.disabled]=\"!getItemFolderStateClass()\"\n (click)=\"onItemFolderClicked()\"\n >\n @if (isExpanding) {\n <si-loading-spinner class=\"si-tree-view-item-icon\" />\n }\n @if (!isExpanding) {\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-icon\"\n [ngClass]=\"getItemFolderStateClass()\"\n ></i>\n }\n </a>\n }\n @if (showFolderStateEnd && treeItem.state === 'leaf') {\n <div class=\"si-tree-stretch-center si-tree-view-item-toggle si-tree-view-item-toggle-end\">\n <i aria-hidden=\"true\" class=\"si-tree-view-item-icon si-tree-view-item-icon-spacer\"></i>\n </div>\n }\n </div>\n </div>\n </div>\n}\n\n@if (isGroupedItem) {\n <div class=\"si-tree-view-li focus-direct-sub-inside\">\n <div class=\"si-tree-view-item-group\">\n @if (showFolderStateStart) {\n <a\n class=\"si-tree-stretch-center si-tree-view-item-toggle\"\n tabindex=\"-1\"\n (click)=\"onItemFolderClicked()\"\n >\n @if (isExpanding) {\n <si-loading-spinner />\n }\n @if (!isExpanding) {\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-icon\"\n [ngClass]=\"getItemFolderStateClass()\"\n ></i>\n }\n </a>\n }\n @if (showCheckOrOptionBox) {\n <a class=\"form-check input-box\" tabindex=\"-1\">\n <input\n class=\"form-check-input\"\n tabindex=\"-1\"\n [type]=\"getInputType()\"\n [indeterminate]=\"this.treeItem.checked === 'indeterminate' ? true : null\"\n [checked]=\"this.treeItem.checked === 'checked'\"\n [attr.aria-label]=\"treeItem.label | translate\"\n (click)=\"onBoxClicked()\"\n />\n </a>\n }\n <p class=\"mb-0\">{{ treeItem.label | translate }}</p>\n @if (showFolderStateEnd) {\n <a\n class=\"si-tree-stretch-center\"\n tabindex=\"-1\"\n [class.disabled]=\"!getItemFolderStateClass()\"\n (click)=\"onItemFolderClicked()\"\n >\n @if (isExpanding) {\n <si-loading-spinner />\n }\n @if (!isExpanding) {\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-icon\"\n [ngClass]=\"getItemFolderStateClass()\"\n ></i>\n }\n </a>\n }\n </div>\n </div>\n}\n\n<ng-template #contextMenu>\n <si-menu-factory class=\"me-5\" [items]=\"contextMenuItems()!\" [actionParam]=\"treeItem\" />\n</ng-template>\n", styles: [":host{--si-tree-view-background: var(--element-base-1);--si-tree-view-border-color: var(--element-ui-4);--si-tree-view-icon-size: 24px;--si-tree-view-padding-base-horizontal: 8px;--si-tree-view-padding-base-vertical: 8px;--si-tree-view-item-hover-color: var(--element-base-1-hover);--si-tree-view-item-select-color: var(--element-base-1-selected);--si-tree-view-item-line-height: 1.143;--si-tree-view-item-min-height: 40px;--si-tree-view-item-object-data-field-1-color: var(--element-text-secondary);--si-tree-view-item-object-data-h5-font-size: .875rem;--si-tree-view-item-object-data-h5-font-weight: normal}:host-context(.tree-sm){--si-tree-view-item-min-height: 32px;--si-tree-view-padding-base-vertical: 0px}:host-context(.tree-xs){--si-tree-view-item-min-height: 24px;--si-tree-view-padding-base-vertical: 0px}:host{display:block}:host.cdk-drag-placeholder{block-size:0;margin-inline:8px;margin-block:0!important;opacity:1;min-block-size:0;position:relative;z-index:999}:host.cdk-drag-placeholder:after{position:absolute;inline-size:100%;block-size:2px;content:\"\";background-color:var(--element-focus-default)!important}:host.cdk-drag-placeholder>*{display:none}:host.cdk-drag:not(.cdk-drag-placeholder){transform:none!important}:host.cdk-drop-list-dragging *:hover,:host.cdk-drop-list-dragging .si-tree-view-item-end-icons,:host.cdk-drop-list-dragging .si-tree-view-item-context-menu-visible,:host .cdk-drop-list-dragging *:hover,:host .cdk-drop-list-dragging .si-tree-view-item-end-icons,:host .cdk-drop-list-dragging .si-tree-view-item-context-menu-visible{background-color:transparent!important}:host.cdk-drag-preview .si-tree-view-li.si-tree-view-li-item{padding-inline-start:8px!important;padding-inline-end:12px!important}:host.cdk-drag-preview .si-tree-view-li.si-tree-view-li-item .si-tree-view-item-toggle{padding-inline-start:12px!important}:host.cdk-drag-preview .si-tree-view-li.si-tree-view-li-item .badge{margin-inline-end:0}:host.cdk-drag-preview .si-tree-view-item-end-icons,:host.cdk-drag-preview .si-tree-view-li.si-tree-view-li-item{background-color:var(--element-base-3)!important}.si-tree-view-li.si-tree-view-li-item{position:relative}.si-tree-view-li.si-tree-view-li-item:hover,.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-context-menu-visible,.si-tree-view-li.si-tree-view-li-item:hover .si-tree-view-item-end-icons,.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-context-menu-visible .si-tree-view-item-end-icons{background-color:var(--si-tree-view-item-hover-color)}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-selected,.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-selected .si-tree-view-item-end-icons{background-color:var(--si-tree-view-item-select-color)}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-selected>.si-tree-view-item>.si-tree-view-item-main>.si-tree-view-item-object-data>h5{font-weight:700}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable:hover,.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item-end-icons{background-color:unset}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item:hover{cursor:default;background-color:unset}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item-dropdown-caret{cursor:pointer}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-context-menu-btn>div[role=button]{cursor:pointer}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item-toggle-end{cursor:pointer}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item-toggle-end .si-tree-view-item-icon{color:var(--element-text-primary)}.si-tree-view-li.si-tree-view-li-item .si-tree-view-item-end-icons{background-color:var(--si-tree-view-background)}.si-tree-view-item-group,.si-tree-view-item{display:flex;align-items:center}.si-tree-stretch-center{align-self:stretch;display:flex;align-items:center;justify-content:center;margin:0;text-decoration:none}.si-tree-view-item-toggle.disabled .si-tree-view-item-icon{inline-size:24px}.si-tree-stretch-center+.si-tree-view-item-toggle-end .si-tree-view-item-icon{margin-inline-start:-4px}.si-tree-view-item-icon{padding-inline-end:8px}.si-tree-view-item-icon.si-tree-view-item-icon-spacer{box-sizing:content-box;inline-size:var(--si-tree-view-icon-size)}.si-tree-view-item-object-data,.si-tree-view-item-icon{margin-block:0;margin-inline:calc(var(--si-tree-view-padding-base-horizontal) / 4)}.si-tree-view-item{justify-content:space-between;min-block-size:var(--si-tree-view-item-min-height);padding-inline:var(--si-tree-view-padding-base-horizontal) calc(var(--si-tree-view-padding-base-horizontal) / 4)}.si-tree-view-item:hover{cursor:pointer}:host-context(.si-tree-view-flat) .si-tree-view-item{padding-inline-start:calc(var(--si-tree-view-padding-base-horizontal) / 2)}.si-tree-view-state-indicator{margin-block:0;margin-inline:calc(var(--si-tree-view-padding-base-horizontal) * .75);min-inline-size:6px;block-size:6px;border-radius:50%}.si-tree-view-state-indicator.si-tree-view-state-indicator-endmost{margin-inline-end:calc(var(--si-tree-view-padding-base-horizontal) * 1.75)}.si-tree-view-item-group{padding-block:calc(2 * var(--si-tree-view-padding-base-vertical));padding-inline:calc(var(--si-tree-view-padding-base-horizontal) / 2);cursor:default}.si-tree-view-item-group .si-tree-view-item-dropdown-caret:hover,.si-tree-view-item-group .si-tree-view-item-icon:hover{cursor:pointer}.si-tree-view-item-dropdown-caret,.si-tree-view-item-dropdown-caret:hover,.si-tree-view-item-icon,.si-tree-view-item-icon:hover{color:var(--element-text-primary);text-decoration:none;font-size:var(--si-tree-view-icon-size)}.si-tree-view-item-main{overflow-x:hidden}.si-tree-view-item-main>.badge{margin-block:auto}.si-tree-view-item-object-data>.si-tree-view-item-object-data-field-1{color:var(--si-tree-view-item-object-data-field-1-color)}:host.si-tree-ellipsis .si-tree-view-item-object-data{overflow-x:hidden}.si-tree-view-item-object-data>*{white-space:nowrap;margin-block:0;line-height:var(--si-tree-view-item-line-height)}:host.si-tree-ellipsis .si-tree-view-item-object-data>*{overflow:hidden;text-overflow:ellipsis}.si-tree-view-item-object-data>h5{font-size:var(--si-tree-view-item-object-data-h5-font-size);font-weight:var(--si-tree-view-item-object-data-h5-font-weight)}.si-tree-view-menu-btn{pointer-events:none}.si-tree-view-item-end-icons{block-size:calc(var(--si-tree-view-item-min-height) - 2 * (var(--element-button-focus-width) + var(--element-button-focus-overlay-width)))}.si-tree-view-item-end-icons.si-tree-view-item-end-icons-sticky{position:sticky;inset-inline-end:0}.input-box{margin-inline:2px 12px}.form-check-input{display:block}si-loading-spinner{--loading-spinner-size: var(--si-tree-view-icon-size)}\n"], dependencies: [{ kind: "directive", type: CdkContextMenuTrigger, selector: "[cdkContextMenuTriggerFor]", inputs: ["cdkContextMenuTriggerFor", "cdkContextMenuPosition", "cdkContextMenuTriggerData", "cdkContextMenuDisabled"], outputs: ["cdkContextMenuOpened", "cdkContextMenuClosed"], exportAs: ["cdkContextMenuTriggerFor"] }, { kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SiLoadingSpinnerComponent, selector: "si-loading-spinner", inputs: ["isBlockingSpinner", "isSpinnerOverlay", "ariaLabel"] }, { kind: "component", type: SiMenuFactoryComponent, selector: "si-menu-factory", inputs: ["items", "actionParam"] }, { kind: "ngmodule", type: SiTranslateModule }, { kind: "pipe", type: i1.SiTranslatePipe, name: "translate" }] });
|
|
807
|
+
}
|
|
808
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewItemComponent, decorators: [{
|
|
809
|
+
type: Component,
|
|
810
|
+
args: [{ selector: 'si-tree-view-item', imports: [
|
|
811
|
+
CdkContextMenuTrigger,
|
|
812
|
+
CdkMenuTrigger,
|
|
813
|
+
NgClass,
|
|
814
|
+
NgTemplateOutlet,
|
|
815
|
+
SiLoadingSpinnerComponent,
|
|
816
|
+
SiMenuFactoryComponent,
|
|
817
|
+
SiTranslateModule
|
|
818
|
+
], host: {
|
|
819
|
+
role: 'treeitem',
|
|
820
|
+
'[attr.tabindex]': 'treeItemContext.record.currentIndex === treeViewComponent.activeIndex ? 0 : -1',
|
|
821
|
+
'[class.focus-none]': 'true',
|
|
822
|
+
'[class.si-tree-ellipsis]': 'treeViewComponent.horizontalScrolling()',
|
|
823
|
+
'[class.si-tree-view-top-level-item]': '!treeViewComponent.compactMode() && (treeViewComponent.flatTree() || (treeItem.level ?? 0) < 1)',
|
|
824
|
+
'[attr.aria-haspopup]': 'isContextMenuButtonVisible()'
|
|
825
|
+
}, template: "@if (!isGroupedItem) {\n <div\n #contextMenuTrigger=\"cdkContextMenuTriggerFor\"\n class=\"si-tree-view-li si-tree-view-li-item focus-direct-sub-inside\"\n [class.si-tree-view-item-context-menu-visible]=\"\n !!(contextMenuTrigger.isOpen() || menuTrigger?.isOpen())\n \"\n [class.si-tree-view-item-active]=\"treeItem.active\"\n [class.si-tree-view-item-selected]=\"enableSelection() && treeItem.selected\"\n [class.si-tree-view-item-not-selectable]=\"!treeItem.selectable\"\n [style.padding-inline-start]=\"biggerPaddingStart\"\n [cdkContextMenuTriggerFor]=\"contextMenu\"\n [cdkContextMenuDisabled]=\"!isContextMenuButtonVisible() || !treeItem.selectable\"\n (cdkContextMenuOpened)=\"onToggleContextMenuOpen()\"\n (cdkContextMenuClosed)=\"onToggleContextMenuClose()\"\n >\n <div class=\"si-tree-view-item\" (mousedown)=\"onMouseDownTreeItem($event)\">\n @if (showFolderStateStart && treeItem.state !== 'leaf') {\n <a\n class=\"si-tree-stretch-center si-tree-view-item-toggle\"\n tabindex=\"-1\"\n [style.margin-inline-start]=\"'-' + biggerPaddingStart\"\n [style.padding-inline-start]=\"paddingStart\"\n (click)=\"onItemFolderClicked()\"\n >\n @if (isExpanding) {\n <si-loading-spinner [@.disabled]=\"true\" />\n }\n @if (!isExpanding) {\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-dropdown-caret\"\n [ngClass]=\"getItemFolderStateClass()\"\n ></i>\n }\n </a>\n }\n @if (showCheckOrOptionBox) {\n <a class=\"form-check input-box\" tabindex=\"-1\">\n <input\n class=\"form-check-input\"\n tabindex=\"-1\"\n [type]=\"getInputType()\"\n [indeterminate]=\"this.treeItem.checked === 'indeterminate' ? true : null\"\n [checked]=\"this.treeItem.checked === 'checked'\"\n [disabled]=\"!treeItem.selectable\"\n [attr.aria-label]=\"treeItem.label | translate\"\n (click)=\"onBoxClicked()\"\n />\n </a>\n }\n <div\n class=\"si-tree-view-item-main d-flex flex-grow-1 align-self-stretch grab-area\"\n (click)=\"onItemClicked($event)\"\n >\n @if (showIcon()) {\n <div class=\"si-tree-stretch-center\">\n <span class=\"si-tree-view-item-icon\" [ngClass]=\"getIconClass()\"></span>\n </div>\n }\n <div\n class=\"si-tree-view-item-object-data d-flex flex-column justify-content-center overflow-hidden\"\n >\n @if (!templates.length) {\n <h5 class=\"text-truncate\">{{ treeItem.label | translate }}</h5>\n }\n @if (templates.length) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n renderMatchingTemplate(treeItem);\n context: { $implicit: treeItem }\n \"\n />\n </div>\n }\n @if (enableDataField1() && treeItem.dataField1) {\n <p class=\"si-tree-view-item-object-data-field-1 text-truncate\">{{\n treeItem.dataField1 | translate\n }}</p>\n }\n @if (enableDataField2() && treeItem.dataField2) {\n <p class=\"si-tree-view-item-object-data-field-2 text-truncate\">{{\n treeItem.dataField2 | translate\n }}</p>\n }\n </div>\n @if (treeItem.badge) {\n <span\n class=\"badge flex-shrink-0\"\n [ngClass]=\"'bg-' + (treeItem.badgeColor || 'default')\"\n >{{ treeItem.badge }}</span\n >\n }\n </div>\n <div\n class=\"si-tree-view-item-end-icons d-flex ms-2 align-items-center\"\n [class.si-tree-view-item-end-icons-sticky]=\"stickyEndItems()\"\n >\n @if (showStateIndicator() && getStateIndicatorColor()) {\n <div\n class=\"si-tree-view-state-indicator\"\n [style.background-color]=\"getStateIndicatorColor()\"\n [class.si-tree-view-state-indicator-endmost]=\"\n !enableContextMenuButton() && !showFolderStateEnd\n \"\n ></div>\n }\n @if (isContextMenuButtonVisible()) {\n <div class=\"si-tree-stretch-center si-tree-context-menu-btn\">\n <div\n #menuTrigger=\"cdkMenuTriggerFor\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [cdkMenuTriggerFor]=\"contextMenu\"\n (cdkMenuOpened)=\"onToggleContextMenuOpen()\"\n (cdkMenuClosed)=\"onToggleContextMenuClose()\"\n >\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-icon si-tree-view-menu-btn\"\n [ngClass]=\"icons().itemMenu\"\n ></i>\n </div>\n </div>\n }\n @if (showFolderStateEnd && treeItem.state !== 'leaf') {\n <a\n class=\"si-tree-stretch-center si-tree-view-item-toggle si-tree-view-item-toggle-end\"\n tabindex=\"-1\"\n [class.disabled]=\"!getItemFolderStateClass()\"\n (click)=\"onItemFolderClicked()\"\n >\n @if (isExpanding) {\n <si-loading-spinner class=\"si-tree-view-item-icon\" />\n }\n @if (!isExpanding) {\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-icon\"\n [ngClass]=\"getItemFolderStateClass()\"\n ></i>\n }\n </a>\n }\n @if (showFolderStateEnd && treeItem.state === 'leaf') {\n <div class=\"si-tree-stretch-center si-tree-view-item-toggle si-tree-view-item-toggle-end\">\n <i aria-hidden=\"true\" class=\"si-tree-view-item-icon si-tree-view-item-icon-spacer\"></i>\n </div>\n }\n </div>\n </div>\n </div>\n}\n\n@if (isGroupedItem) {\n <div class=\"si-tree-view-li focus-direct-sub-inside\">\n <div class=\"si-tree-view-item-group\">\n @if (showFolderStateStart) {\n <a\n class=\"si-tree-stretch-center si-tree-view-item-toggle\"\n tabindex=\"-1\"\n (click)=\"onItemFolderClicked()\"\n >\n @if (isExpanding) {\n <si-loading-spinner />\n }\n @if (!isExpanding) {\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-icon\"\n [ngClass]=\"getItemFolderStateClass()\"\n ></i>\n }\n </a>\n }\n @if (showCheckOrOptionBox) {\n <a class=\"form-check input-box\" tabindex=\"-1\">\n <input\n class=\"form-check-input\"\n tabindex=\"-1\"\n [type]=\"getInputType()\"\n [indeterminate]=\"this.treeItem.checked === 'indeterminate' ? true : null\"\n [checked]=\"this.treeItem.checked === 'checked'\"\n [attr.aria-label]=\"treeItem.label | translate\"\n (click)=\"onBoxClicked()\"\n />\n </a>\n }\n <p class=\"mb-0\">{{ treeItem.label | translate }}</p>\n @if (showFolderStateEnd) {\n <a\n class=\"si-tree-stretch-center\"\n tabindex=\"-1\"\n [class.disabled]=\"!getItemFolderStateClass()\"\n (click)=\"onItemFolderClicked()\"\n >\n @if (isExpanding) {\n <si-loading-spinner />\n }\n @if (!isExpanding) {\n <i\n aria-hidden=\"true\"\n class=\"si-tree-view-item-icon\"\n [ngClass]=\"getItemFolderStateClass()\"\n ></i>\n }\n </a>\n }\n </div>\n </div>\n}\n\n<ng-template #contextMenu>\n <si-menu-factory class=\"me-5\" [items]=\"contextMenuItems()!\" [actionParam]=\"treeItem\" />\n</ng-template>\n", styles: [":host{--si-tree-view-background: var(--element-base-1);--si-tree-view-border-color: var(--element-ui-4);--si-tree-view-icon-size: 24px;--si-tree-view-padding-base-horizontal: 8px;--si-tree-view-padding-base-vertical: 8px;--si-tree-view-item-hover-color: var(--element-base-1-hover);--si-tree-view-item-select-color: var(--element-base-1-selected);--si-tree-view-item-line-height: 1.143;--si-tree-view-item-min-height: 40px;--si-tree-view-item-object-data-field-1-color: var(--element-text-secondary);--si-tree-view-item-object-data-h5-font-size: .875rem;--si-tree-view-item-object-data-h5-font-weight: normal}:host-context(.tree-sm){--si-tree-view-item-min-height: 32px;--si-tree-view-padding-base-vertical: 0px}:host-context(.tree-xs){--si-tree-view-item-min-height: 24px;--si-tree-view-padding-base-vertical: 0px}:host{display:block}:host.cdk-drag-placeholder{block-size:0;margin-inline:8px;margin-block:0!important;opacity:1;min-block-size:0;position:relative;z-index:999}:host.cdk-drag-placeholder:after{position:absolute;inline-size:100%;block-size:2px;content:\"\";background-color:var(--element-focus-default)!important}:host.cdk-drag-placeholder>*{display:none}:host.cdk-drag:not(.cdk-drag-placeholder){transform:none!important}:host.cdk-drop-list-dragging *:hover,:host.cdk-drop-list-dragging .si-tree-view-item-end-icons,:host.cdk-drop-list-dragging .si-tree-view-item-context-menu-visible,:host .cdk-drop-list-dragging *:hover,:host .cdk-drop-list-dragging .si-tree-view-item-end-icons,:host .cdk-drop-list-dragging .si-tree-view-item-context-menu-visible{background-color:transparent!important}:host.cdk-drag-preview .si-tree-view-li.si-tree-view-li-item{padding-inline-start:8px!important;padding-inline-end:12px!important}:host.cdk-drag-preview .si-tree-view-li.si-tree-view-li-item .si-tree-view-item-toggle{padding-inline-start:12px!important}:host.cdk-drag-preview .si-tree-view-li.si-tree-view-li-item .badge{margin-inline-end:0}:host.cdk-drag-preview .si-tree-view-item-end-icons,:host.cdk-drag-preview .si-tree-view-li.si-tree-view-li-item{background-color:var(--element-base-3)!important}.si-tree-view-li.si-tree-view-li-item{position:relative}.si-tree-view-li.si-tree-view-li-item:hover,.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-context-menu-visible,.si-tree-view-li.si-tree-view-li-item:hover .si-tree-view-item-end-icons,.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-context-menu-visible .si-tree-view-item-end-icons{background-color:var(--si-tree-view-item-hover-color)}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-selected,.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-selected .si-tree-view-item-end-icons{background-color:var(--si-tree-view-item-select-color)}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-selected>.si-tree-view-item>.si-tree-view-item-main>.si-tree-view-item-object-data>h5{font-weight:700}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable:hover,.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item-end-icons{background-color:unset}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item:hover{cursor:default;background-color:unset}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item-dropdown-caret{cursor:pointer}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-context-menu-btn>div[role=button]{cursor:pointer}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item-toggle-end{cursor:pointer}.si-tree-view-li.si-tree-view-li-item.si-tree-view-item-not-selectable .si-tree-view-item-toggle-end .si-tree-view-item-icon{color:var(--element-text-primary)}.si-tree-view-li.si-tree-view-li-item .si-tree-view-item-end-icons{background-color:var(--si-tree-view-background)}.si-tree-view-item-group,.si-tree-view-item{display:flex;align-items:center}.si-tree-stretch-center{align-self:stretch;display:flex;align-items:center;justify-content:center;margin:0;text-decoration:none}.si-tree-view-item-toggle.disabled .si-tree-view-item-icon{inline-size:24px}.si-tree-stretch-center+.si-tree-view-item-toggle-end .si-tree-view-item-icon{margin-inline-start:-4px}.si-tree-view-item-icon{padding-inline-end:8px}.si-tree-view-item-icon.si-tree-view-item-icon-spacer{box-sizing:content-box;inline-size:var(--si-tree-view-icon-size)}.si-tree-view-item-object-data,.si-tree-view-item-icon{margin-block:0;margin-inline:calc(var(--si-tree-view-padding-base-horizontal) / 4)}.si-tree-view-item{justify-content:space-between;min-block-size:var(--si-tree-view-item-min-height);padding-inline:var(--si-tree-view-padding-base-horizontal) calc(var(--si-tree-view-padding-base-horizontal) / 4)}.si-tree-view-item:hover{cursor:pointer}:host-context(.si-tree-view-flat) .si-tree-view-item{padding-inline-start:calc(var(--si-tree-view-padding-base-horizontal) / 2)}.si-tree-view-state-indicator{margin-block:0;margin-inline:calc(var(--si-tree-view-padding-base-horizontal) * .75);min-inline-size:6px;block-size:6px;border-radius:50%}.si-tree-view-state-indicator.si-tree-view-state-indicator-endmost{margin-inline-end:calc(var(--si-tree-view-padding-base-horizontal) * 1.75)}.si-tree-view-item-group{padding-block:calc(2 * var(--si-tree-view-padding-base-vertical));padding-inline:calc(var(--si-tree-view-padding-base-horizontal) / 2);cursor:default}.si-tree-view-item-group .si-tree-view-item-dropdown-caret:hover,.si-tree-view-item-group .si-tree-view-item-icon:hover{cursor:pointer}.si-tree-view-item-dropdown-caret,.si-tree-view-item-dropdown-caret:hover,.si-tree-view-item-icon,.si-tree-view-item-icon:hover{color:var(--element-text-primary);text-decoration:none;font-size:var(--si-tree-view-icon-size)}.si-tree-view-item-main{overflow-x:hidden}.si-tree-view-item-main>.badge{margin-block:auto}.si-tree-view-item-object-data>.si-tree-view-item-object-data-field-1{color:var(--si-tree-view-item-object-data-field-1-color)}:host.si-tree-ellipsis .si-tree-view-item-object-data{overflow-x:hidden}.si-tree-view-item-object-data>*{white-space:nowrap;margin-block:0;line-height:var(--si-tree-view-item-line-height)}:host.si-tree-ellipsis .si-tree-view-item-object-data>*{overflow:hidden;text-overflow:ellipsis}.si-tree-view-item-object-data>h5{font-size:var(--si-tree-view-item-object-data-h5-font-size);font-weight:var(--si-tree-view-item-object-data-h5-font-weight)}.si-tree-view-menu-btn{pointer-events:none}.si-tree-view-item-end-icons{block-size:calc(var(--si-tree-view-item-min-height) - 2 * (var(--element-button-focus-width) + var(--element-button-focus-overlay-width)))}.si-tree-view-item-end-icons.si-tree-view-item-end-icons-sticky{position:sticky;inset-inline-end:0}.input-box{margin-inline:2px 12px}.form-check-input{display:block}si-loading-spinner{--loading-spinner-size: var(--si-tree-view-icon-size)}\n"] }]
|
|
826
|
+
}], propDecorators: { menuTrigger: [{
|
|
827
|
+
type: ViewChild,
|
|
828
|
+
args: [CdkMenuTrigger]
|
|
829
|
+
}], ariaLevel: [{
|
|
830
|
+
type: HostBinding,
|
|
831
|
+
args: ['attr.aria-level']
|
|
832
|
+
}], ariaSetsize: [{
|
|
833
|
+
type: HostBinding,
|
|
834
|
+
args: ['attr.aria-setsize']
|
|
835
|
+
}], ariaPosinset: [{
|
|
836
|
+
type: HostBinding,
|
|
837
|
+
args: ['attr.aria-posinset']
|
|
838
|
+
}], ariaSelected: [{
|
|
839
|
+
type: HostBinding,
|
|
840
|
+
args: ['attr.aria-selected']
|
|
841
|
+
}], ariaChecked: [{
|
|
842
|
+
type: HostBinding,
|
|
843
|
+
args: ['attr.aria-checked']
|
|
844
|
+
}], ariaExpanded: [{
|
|
845
|
+
type: HostBinding,
|
|
846
|
+
args: ['attr.aria-expanded']
|
|
847
|
+
}], onContextMenu: [{
|
|
848
|
+
type: HostListener,
|
|
849
|
+
args: ['contextmenu', ['$event']]
|
|
850
|
+
}], onKeydown: [{
|
|
851
|
+
type: HostListener,
|
|
852
|
+
args: ['keydown', ['$event']]
|
|
853
|
+
}] } });
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* Copyright Siemens 2016 - 2025.
|
|
857
|
+
* SPDX-License-Identifier: MIT
|
|
858
|
+
*/
|
|
859
|
+
/**
|
|
860
|
+
* Provides the functionality to flatten the hierarchical tree structure into a flat one dimensional array; called flattenedTrees.
|
|
861
|
+
* The TreeViewComponent uses this flattened trees (the array) to bind the contained tree/list items to the GUI into a list.
|
|
862
|
+
* In addition the service provides the number of 'normal' list items and the number of group items.
|
|
863
|
+
* Important:
|
|
864
|
+
* The coupling to the TreeViewComponent is high, thus the service is provided only by the TreeViewComponent.
|
|
865
|
+
*/
|
|
866
|
+
class SiTreeViewConverterService {
|
|
867
|
+
/**
|
|
868
|
+
* The flattened tree array; filled upon calling the method 'fillFlattenedTree'
|
|
869
|
+
*
|
|
870
|
+
* @defaultValue []
|
|
871
|
+
*/
|
|
872
|
+
flattenedTrees = [];
|
|
873
|
+
/**
|
|
874
|
+
* The number of group items of the flattened tree.
|
|
875
|
+
*
|
|
876
|
+
* @defaultValue 0
|
|
877
|
+
*/
|
|
878
|
+
groupItemsCount = 0;
|
|
879
|
+
/**
|
|
880
|
+
* The total items count of the flattened tree.
|
|
881
|
+
*
|
|
882
|
+
* @defaultValue 0
|
|
883
|
+
*/
|
|
884
|
+
itemsTotal = 0;
|
|
885
|
+
siTreeViewService = inject(SiTreeViewService);
|
|
886
|
+
/**
|
|
887
|
+
* Flattens the tree handed over as parameter.
|
|
888
|
+
* Takes the mode of the tree into consideration:
|
|
889
|
+
* In case of a flat tree: only the first level of the items parameter is copied into the flattenedTrees array.
|
|
890
|
+
* In case of a grouped tree: only the first two levels are copied into the flattenedTrees array
|
|
891
|
+
* In the other cases all tree nodes are copied into the flattenedTrees array.
|
|
892
|
+
*/
|
|
893
|
+
fillFlattenedTree(items, isFlatTree) {
|
|
894
|
+
if (isFlatTree === false) {
|
|
895
|
+
this.flattenedTrees = [];
|
|
896
|
+
if (this.siTreeViewService.groupedList) {
|
|
897
|
+
this.fillFlattenedTreeRecursive(items, 2, 0);
|
|
898
|
+
}
|
|
899
|
+
else {
|
|
900
|
+
this.fillFlattenedTreeRecursive(items);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
else {
|
|
904
|
+
this.flattenedTrees = items;
|
|
905
|
+
this.groupItemsCount = 0;
|
|
906
|
+
}
|
|
907
|
+
this.itemsTotal = items.length;
|
|
908
|
+
}
|
|
909
|
+
fillFlattenedTreeRecursive(items, noOfLevels, stackLevel) {
|
|
910
|
+
if (noOfLevels !== undefined && stackLevel !== undefined && noOfLevels <= stackLevel) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
stackLevel = stackLevel ?? 0;
|
|
914
|
+
for (const current of items) {
|
|
915
|
+
this.flattenedTrees.push(current);
|
|
916
|
+
if (this.siTreeViewService.isGroupedItem(current)) {
|
|
917
|
+
this.groupItemsCount++;
|
|
918
|
+
}
|
|
919
|
+
if (current.state === 'expanded') {
|
|
920
|
+
this.fillFlattenedTreeRecursive(current.children ?? [], noOfLevels, stackLevel + 1);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewConverterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
925
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewConverterService });
|
|
926
|
+
}
|
|
927
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewConverterService, decorators: [{
|
|
928
|
+
type: Injectable
|
|
929
|
+
}] });
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Copyright Siemens 2016 - 2025.
|
|
933
|
+
* SPDX-License-Identifier: MIT
|
|
934
|
+
*/
|
|
935
|
+
/**
|
|
936
|
+
* This service provides helper functionality for the tree view to read the height of the tree/list items and
|
|
937
|
+
* the group list items out of the DOM.
|
|
938
|
+
*
|
|
939
|
+
* Important: The coupling to the TreeViewComponent is very high as the service contains knowledge on the HTML structure!!!
|
|
940
|
+
* Thus the service is provided only by the TreeViewComponent.
|
|
941
|
+
*
|
|
942
|
+
* Constraint: The height of the items (DOM elements) must be all the same; The height of the grouped items (DOM elements)
|
|
943
|
+
* must be all the same;
|
|
944
|
+
*/
|
|
945
|
+
class SiTreeViewItemHeightService {
|
|
946
|
+
/**
|
|
947
|
+
* The height of a tree list item.
|
|
948
|
+
* Can be undefined if the tree list has not been layout rendered yet.
|
|
949
|
+
*/
|
|
950
|
+
itemHeight;
|
|
951
|
+
/**
|
|
952
|
+
* The height of a grouped list item.
|
|
953
|
+
* Can be undefined if the tree list has not been layout rendered yet or if it does not contain group items.
|
|
954
|
+
*/
|
|
955
|
+
groupItemHeight;
|
|
956
|
+
/**
|
|
957
|
+
* Emitter for itemHeight changes.
|
|
958
|
+
*/
|
|
959
|
+
itemHeightChange = new EventEmitter();
|
|
960
|
+
siTreeViewService = inject(SiTreeViewService);
|
|
961
|
+
/**
|
|
962
|
+
* Updates the height of a list item, if an appropriate item is in the DOM.
|
|
963
|
+
*
|
|
964
|
+
* @returns The new height of the list item; or undefined if no list item is in the DOM yet.
|
|
965
|
+
*/
|
|
966
|
+
updateItemHeight(elementList, flattenedTrees, itemsBase, virtualizedItems) {
|
|
967
|
+
let newHeight;
|
|
968
|
+
let itemsTop = itemsBase + virtualizedItems;
|
|
969
|
+
if (itemsTop > flattenedTrees.length) {
|
|
970
|
+
itemsTop = flattenedTrees.length;
|
|
971
|
+
}
|
|
972
|
+
for (let i = itemsBase; i < itemsTop; i++) {
|
|
973
|
+
if (this.siTreeViewService.isGroupedItem(flattenedTrees[i]) === false) {
|
|
974
|
+
newHeight = this.getItemHeightOfListElement(elementList, i - itemsBase);
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
if (newHeight !== undefined && this.itemHeight !== newHeight) {
|
|
979
|
+
this.itemHeight = newHeight;
|
|
980
|
+
this.itemHeightChange.emit(newHeight);
|
|
981
|
+
}
|
|
982
|
+
return newHeight;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Updates the height of a group item, if an appropriate item is in the DOM.
|
|
986
|
+
*
|
|
987
|
+
* @returns The new height of the group item; or undefined if no group item is in the DOM yet.
|
|
988
|
+
*/
|
|
989
|
+
updateGroupedItemHeight(elementList, flattenedTrees, itemsBase, virtualizedItems) {
|
|
990
|
+
let newHeight;
|
|
991
|
+
let itemsTop = itemsBase + virtualizedItems;
|
|
992
|
+
if (itemsTop > flattenedTrees.length) {
|
|
993
|
+
itemsTop = flattenedTrees.length;
|
|
994
|
+
}
|
|
995
|
+
for (let i = itemsBase; i < itemsTop; i++) {
|
|
996
|
+
if (this.siTreeViewService.isGroupedItem(flattenedTrees[i])) {
|
|
997
|
+
newHeight = this.getItemHeightOfListElement(elementList, i - itemsBase);
|
|
998
|
+
break;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
if (newHeight !== undefined) {
|
|
1002
|
+
this.groupItemHeight = newHeight;
|
|
1003
|
+
}
|
|
1004
|
+
return newHeight;
|
|
1005
|
+
}
|
|
1006
|
+
getItemHeightOfListElement(elementList, index) {
|
|
1007
|
+
const items = elementList.querySelectorAll('si-tree-view-item');
|
|
1008
|
+
if (index < items.length) {
|
|
1009
|
+
return items.item(index).getBoundingClientRect().height;
|
|
1010
|
+
}
|
|
1011
|
+
return undefined;
|
|
1012
|
+
}
|
|
1013
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewItemHeightService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1014
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewItemHeightService });
|
|
1015
|
+
}
|
|
1016
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewItemHeightService, decorators: [{
|
|
1017
|
+
type: Injectable
|
|
1018
|
+
}] });
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Copyright Siemens 2016 - 2025.
|
|
1022
|
+
* SPDX-License-Identifier: MIT
|
|
1023
|
+
*/
|
|
1024
|
+
class SiTreeViewItemDirective {
|
|
1025
|
+
templateRef = inject(TemplateRef);
|
|
1026
|
+
viewContainerRef = inject(ViewContainerRef);
|
|
1027
|
+
parent = inject(SiTreeViewComponent);
|
|
1028
|
+
differs = inject(IterableDiffers);
|
|
1029
|
+
cdRef = inject(ChangeDetectorRef);
|
|
1030
|
+
differ = null;
|
|
1031
|
+
subscription;
|
|
1032
|
+
itemsVirtualizedDirty = true;
|
|
1033
|
+
ngAfterViewInit() {
|
|
1034
|
+
if (this.itemsVirtualizedDirty) {
|
|
1035
|
+
this.itemsVirtualizedDirty = false;
|
|
1036
|
+
const value = this.parent.itemsVirtualized;
|
|
1037
|
+
if (!this.differ && value) {
|
|
1038
|
+
this.differ = this.differs.find(value).create((_index, item) => item);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
this.evaluateDiffer();
|
|
1042
|
+
this.subscription = this.parent.evaluateForTreeItemsDiffer.subscribe(_ => this.evaluateDiffer());
|
|
1043
|
+
}
|
|
1044
|
+
ngOnDestroy() {
|
|
1045
|
+
this.subscription.unsubscribe();
|
|
1046
|
+
}
|
|
1047
|
+
evaluateDiffer() {
|
|
1048
|
+
if (this.differ) {
|
|
1049
|
+
const changes = this.differ.diff(this.parent.itemsVirtualized);
|
|
1050
|
+
if (changes)
|
|
1051
|
+
this.applyChanges(changes);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
applyChanges(changes) {
|
|
1055
|
+
const viewContainer = this.viewContainerRef;
|
|
1056
|
+
changes.forEachOperation((record, adjustedPreviousIndex, currentIndex) => {
|
|
1057
|
+
if (record.previousIndex == null) {
|
|
1058
|
+
viewContainer.createEmbeddedView(this.templateRef, {
|
|
1059
|
+
treeItem: record.item,
|
|
1060
|
+
index: record.currentIndex,
|
|
1061
|
+
parent: this.parent
|
|
1062
|
+
}, {
|
|
1063
|
+
injector: Injector.create({
|
|
1064
|
+
providers: [
|
|
1065
|
+
{
|
|
1066
|
+
provide: TREE_ITEM_CONTEXT,
|
|
1067
|
+
useValue: {
|
|
1068
|
+
record,
|
|
1069
|
+
parent: this.parent
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
]
|
|
1073
|
+
}),
|
|
1074
|
+
index: currentIndex ?? undefined
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
else if (currentIndex == null) {
|
|
1078
|
+
viewContainer.remove(adjustedPreviousIndex ?? undefined);
|
|
1079
|
+
}
|
|
1080
|
+
else if (adjustedPreviousIndex !== null) {
|
|
1081
|
+
const view = viewContainer.get(adjustedPreviousIndex);
|
|
1082
|
+
viewContainer.move(view, currentIndex);
|
|
1083
|
+
view.context = {
|
|
1084
|
+
treeItem: record.item,
|
|
1085
|
+
index: record.currentIndex,
|
|
1086
|
+
parent: this.parent
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
this.cdRef.detectChanges();
|
|
1090
|
+
});
|
|
1091
|
+
for (let i = 0, ilen = viewContainer.length; i < ilen; i++) {
|
|
1092
|
+
const viewRef = viewContainer.get(i);
|
|
1093
|
+
const context = viewRef.context;
|
|
1094
|
+
context.index = i;
|
|
1095
|
+
}
|
|
1096
|
+
changes.forEachIdentityChange((record) => {
|
|
1097
|
+
if (record.currentIndex) {
|
|
1098
|
+
const viewRef = viewContainer.get(record.currentIndex);
|
|
1099
|
+
viewRef.context = {
|
|
1100
|
+
treeItem: record.item,
|
|
1101
|
+
index: record.currentIndex,
|
|
1102
|
+
parent: this.parent
|
|
1103
|
+
};
|
|
1104
|
+
this.cdRef.detectChanges();
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
static ngTemplateContextGuard(_dir, ctx) {
|
|
1109
|
+
return true;
|
|
1110
|
+
}
|
|
1111
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1112
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.6", type: SiTreeViewItemDirective, isStandalone: true, selector: "[siTreeViewItem]", ngImport: i0 });
|
|
1113
|
+
}
|
|
1114
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewItemDirective, decorators: [{
|
|
1115
|
+
type: Directive,
|
|
1116
|
+
args: [{
|
|
1117
|
+
selector: '[siTreeViewItem]'
|
|
1118
|
+
}]
|
|
1119
|
+
}] });
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Copyright Siemens 2016 - 2025.
|
|
1123
|
+
* SPDX-License-Identifier: MIT
|
|
1124
|
+
*/
|
|
1125
|
+
/**
|
|
1126
|
+
* Provides helper functionality to virtualize a list of items.
|
|
1127
|
+
* The number of virtualized items is the product of the pageSize and the pagesVirtualized (no of pages virtualized);
|
|
1128
|
+
* The paging algorithm works as follows:
|
|
1129
|
+
* If scrolling down, between two and three pages are kept above the 'visible' area;
|
|
1130
|
+
* The trigger is therefore if more than three pages are above the visible area, one page is removed from the top and added at the bottom.
|
|
1131
|
+
* If scrolling up, between one and two pages are kept above the 'visible' area;
|
|
1132
|
+
* The trigger is therefore if less than one page is above the visible area, one page is added on top and removed from the bottom.
|
|
1133
|
+
* All remaining items which are not virtualized, need to be simulated with two div-elements whose height can be set with the calculated
|
|
1134
|
+
* properties heightBefore and heightAfter.
|
|
1135
|
+
* See the test client for further information on the usage.
|
|
1136
|
+
* Constraint:
|
|
1137
|
+
* The virtualization calculation works correct only when all list items are of the same height!
|
|
1138
|
+
* If the 'group' mode is enabled, the corresponding group-items can have a different height, but for all group-items it must be the same.
|
|
1139
|
+
*/
|
|
1140
|
+
class SiTreeViewVirtualizationService {
|
|
1141
|
+
/**
|
|
1142
|
+
* The number of list items of a virtualized page.
|
|
1143
|
+
* Choose a value, which is roughly half of the number of items you expect to be displayed on the visible screen.
|
|
1144
|
+
*
|
|
1145
|
+
* @defaultValue 10
|
|
1146
|
+
*/
|
|
1147
|
+
pageSize = 10;
|
|
1148
|
+
/**
|
|
1149
|
+
* The number of pages to be virtualized.
|
|
1150
|
+
*
|
|
1151
|
+
* @defaultValue 6
|
|
1152
|
+
*/
|
|
1153
|
+
pagesVirtualized = 6;
|
|
1154
|
+
/**
|
|
1155
|
+
* Emits when the virtualized items have changed (added/removed).
|
|
1156
|
+
*/
|
|
1157
|
+
itemsVirtualizedChanged = new Subject();
|
|
1158
|
+
/**
|
|
1159
|
+
* The total height of the 'simulated' list items which are ordered before the virtualized list items.
|
|
1160
|
+
*/
|
|
1161
|
+
_heightBefore = 0;
|
|
1162
|
+
/**
|
|
1163
|
+
* The total height of the 'simulated' list items which are ordered after the virtualized list items.
|
|
1164
|
+
*/
|
|
1165
|
+
_heightAfter = 0;
|
|
1166
|
+
_pageBase = 0;
|
|
1167
|
+
scrollTopPrev = 0;
|
|
1168
|
+
_itemsVirtualized = [];
|
|
1169
|
+
groupItemsCountBefore = 0;
|
|
1170
|
+
listItemsCountBefore = 0;
|
|
1171
|
+
groupItemsCountAfter = 0;
|
|
1172
|
+
listItemsCountAfter = 0;
|
|
1173
|
+
groupItemsCountVirtualized = 0;
|
|
1174
|
+
listItemsCountVirtualized = 0;
|
|
1175
|
+
listItemsPerVirtPage = [];
|
|
1176
|
+
groupItemsPerVirtPage = [];
|
|
1177
|
+
siTreeViewService = inject(SiTreeViewService);
|
|
1178
|
+
siTreeViewItemHeightService = inject(SiTreeViewItemHeightService);
|
|
1179
|
+
/**
|
|
1180
|
+
* Returns the virtualized items.
|
|
1181
|
+
*/
|
|
1182
|
+
get itemsVirtualized() {
|
|
1183
|
+
return this._itemsVirtualized;
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* The total height of the 'simulated' list items which are ordered before the virtualized list items.
|
|
1187
|
+
*/
|
|
1188
|
+
get heightBefore() {
|
|
1189
|
+
return this._heightBefore;
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* The total height of the 'simulated' list items which are ordered after the virtualized list items.
|
|
1193
|
+
*/
|
|
1194
|
+
get heightAfter() {
|
|
1195
|
+
return this._heightAfter;
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* The index of the first (base) page being virtualized.
|
|
1199
|
+
*/
|
|
1200
|
+
get pageBase() {
|
|
1201
|
+
return this._pageBase;
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* The list item index of the base page.
|
|
1205
|
+
*/
|
|
1206
|
+
get itemBaseIdx() {
|
|
1207
|
+
return this._pageBase * this.pageSize;
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* Returns the number of virtualized items.
|
|
1211
|
+
*/
|
|
1212
|
+
get itemsVirtualizedCount() {
|
|
1213
|
+
return this.itemsVirtualized.length;
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Call this method upon scroll handler notifications!
|
|
1217
|
+
*
|
|
1218
|
+
* @param scrollTop - the scrollTop value retrieved form the event target
|
|
1219
|
+
* @param itemsAll - all items of the list
|
|
1220
|
+
*/
|
|
1221
|
+
handleScroll(scrollTop, itemsAll) {
|
|
1222
|
+
if (this.siTreeViewService.groupedList) {
|
|
1223
|
+
this.handleScrollGrouped(scrollTop, itemsAll);
|
|
1224
|
+
}
|
|
1225
|
+
else {
|
|
1226
|
+
this.handleScrollSimple(scrollTop, itemsAll);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Resets the virtualization to 'show' the items of the first page onwards.
|
|
1231
|
+
*/
|
|
1232
|
+
resetVirtualizedItemList(itemsAll) {
|
|
1233
|
+
this._pageBase = 0;
|
|
1234
|
+
this.updateVirtualizedItemListIntern(itemsAll);
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Updates the virtualized items. Call this method for use cases such as:
|
|
1238
|
+
* - The list items array contains added or removed items which could be in the 'visible' area
|
|
1239
|
+
* - The item height has changed.
|
|
1240
|
+
*/
|
|
1241
|
+
updateVirtualizedItemList(itemsAll) {
|
|
1242
|
+
this.updateVirtualizedItemListIntern(itemsAll);
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Checks if the specified item is currently virtualized.
|
|
1246
|
+
* If not, the virtualization is recalculated in order that the item is part of the virtualized items.
|
|
1247
|
+
*/
|
|
1248
|
+
virtualizeItem(item, itemsAll) {
|
|
1249
|
+
if (this.checkIfItemDisplayed(item) === false) {
|
|
1250
|
+
this.setBasePageForItemToDisplay(item, itemsAll);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* Calculates the first visible tree item based on current scroll position.
|
|
1255
|
+
*/
|
|
1256
|
+
calculateFirstVisibleTreeItem() {
|
|
1257
|
+
let item;
|
|
1258
|
+
let totalItemHeight = 0;
|
|
1259
|
+
// Approx Y-position of the middle of the first visible (top) tree item
|
|
1260
|
+
const topItemPos = this.scrollTopPrev +
|
|
1261
|
+
(this.siTreeViewItemHeightService.itemHeight ?? 0) / 2 -
|
|
1262
|
+
this.heightBefore;
|
|
1263
|
+
for (let idx = 0; idx < this._itemsVirtualized.length && totalItemHeight < topItemPos; idx++) {
|
|
1264
|
+
item = this._itemsVirtualized[idx];
|
|
1265
|
+
totalItemHeight += this.isGroupItem(item)
|
|
1266
|
+
? (this.siTreeViewItemHeightService.groupItemHeight ?? 0)
|
|
1267
|
+
: (this.siTreeViewItemHeightService.itemHeight ?? 0);
|
|
1268
|
+
}
|
|
1269
|
+
return item;
|
|
1270
|
+
}
|
|
1271
|
+
get listItemsCountTotal() {
|
|
1272
|
+
return this.listItemsCountBefore + this.listItemsCountVirtualized + this.listItemsCountAfter;
|
|
1273
|
+
}
|
|
1274
|
+
get groupItemsCountTotal() {
|
|
1275
|
+
return this.groupItemsCountBefore + this.groupItemsCountVirtualized + this.groupItemsCountAfter;
|
|
1276
|
+
}
|
|
1277
|
+
get itemsCountTotal() {
|
|
1278
|
+
return this.listItemsCountTotal + this.groupItemsCountTotal;
|
|
1279
|
+
}
|
|
1280
|
+
get itemsCountVirtualizedMax() {
|
|
1281
|
+
return this.pageSize * this.pagesVirtualized;
|
|
1282
|
+
}
|
|
1283
|
+
updateVirtualizedItemListIntern(itemsAll, scrolledPages) {
|
|
1284
|
+
// Note!!!:
|
|
1285
|
+
// The order of functionality within this method must be maintained as state of this object is changed!!!
|
|
1286
|
+
const itemsVirtualizedOld = this._itemsVirtualized.slice();
|
|
1287
|
+
this._itemsVirtualized = itemsAll.slice(this.pageBase * this.pageSize, this.itemsCountVirtualizedMax + this.pageBase * this.pageSize);
|
|
1288
|
+
this.updateItemsTypeCount(itemsAll, scrolledPages);
|
|
1289
|
+
if (this.siTreeViewService.groupedList) {
|
|
1290
|
+
this.calculateBeforeAndAfterForGroupList();
|
|
1291
|
+
}
|
|
1292
|
+
else {
|
|
1293
|
+
this.calculateBeforeAndAfter();
|
|
1294
|
+
}
|
|
1295
|
+
this.maintainVirtualizationNotifies(itemsVirtualizedOld);
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Notifies a consumer about changes of virtualized tree/list items in case of a pageBase change.
|
|
1299
|
+
* One notification is sent for every tree/list item
|
|
1300
|
+
* that went out of the virtualized items list or came into the virtualized items.
|
|
1301
|
+
*/
|
|
1302
|
+
maintainVirtualizationNotifies(itemsVirtualizedOld) {
|
|
1303
|
+
const itemsAdded = [];
|
|
1304
|
+
const itemsRemoved = [];
|
|
1305
|
+
for (const item of itemsVirtualizedOld) {
|
|
1306
|
+
if (!this._itemsVirtualized.includes(item)) {
|
|
1307
|
+
itemsRemoved.push(item);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
for (const item of this._itemsVirtualized) {
|
|
1311
|
+
if (!itemsVirtualizedOld.includes(item)) {
|
|
1312
|
+
itemsAdded.push(item);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
if (itemsRemoved.length > 0) {
|
|
1316
|
+
this.itemsVirtualizedChanged.next(new ItemsVirtualizedArgs(itemsRemoved, false));
|
|
1317
|
+
}
|
|
1318
|
+
if (itemsAdded.length > 0) {
|
|
1319
|
+
this.itemsVirtualizedChanged.next(new ItemsVirtualizedArgs(itemsAdded, true));
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
calculateBasePage(idx) {
|
|
1323
|
+
this._pageBase = Math.floor(idx / this.pageSize - this.pagesVirtualized / 2);
|
|
1324
|
+
if (this.pageBase < 0) {
|
|
1325
|
+
this._pageBase = 0;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
/**
|
|
1329
|
+
* Calculates the height [px] for the divs before and after the tree list in case of 'grouped' mode!
|
|
1330
|
+
*/
|
|
1331
|
+
calculateBeforeAndAfterForGroupList() {
|
|
1332
|
+
const groupItemHeight = this.siTreeViewItemHeightService.groupItemHeight ?? 0;
|
|
1333
|
+
const listItemHeight = this.siTreeViewItemHeightService.itemHeight ?? 0;
|
|
1334
|
+
const scrollHeight = this.listItemsCountTotal * listItemHeight + this.groupItemsCountTotal * groupItemHeight;
|
|
1335
|
+
this._heightBefore =
|
|
1336
|
+
this.listItemsCountBefore * listItemHeight + this.groupItemsCountBefore * groupItemHeight;
|
|
1337
|
+
this._heightAfter =
|
|
1338
|
+
scrollHeight -
|
|
1339
|
+
this.heightBefore -
|
|
1340
|
+
(this.listItemsCountVirtualized * listItemHeight +
|
|
1341
|
+
this.groupItemsCountVirtualized * groupItemHeight);
|
|
1342
|
+
}
|
|
1343
|
+
/**
|
|
1344
|
+
* Calculates the height [px] for the divs before and after the tree list in case of 'non-grouped' mode!
|
|
1345
|
+
*/
|
|
1346
|
+
calculateBeforeAndAfter() {
|
|
1347
|
+
if (this.siTreeViewItemHeightService.itemHeight === undefined ||
|
|
1348
|
+
this.siTreeViewItemHeightService.itemHeight === 0) {
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
const scrollHeight = this.itemsCountTotal * this.siTreeViewItemHeightService.itemHeight;
|
|
1352
|
+
this._heightBefore =
|
|
1353
|
+
this.pageBase * this.pageSize * this.siTreeViewItemHeightService.itemHeight;
|
|
1354
|
+
this._heightAfter =
|
|
1355
|
+
scrollHeight -
|
|
1356
|
+
this.heightBefore -
|
|
1357
|
+
this.itemsVirtualizedCount * this.siTreeViewItemHeightService.itemHeight;
|
|
1358
|
+
}
|
|
1359
|
+
checkIfItemDisplayed(currentItem) {
|
|
1360
|
+
for (const item of this._itemsVirtualized) {
|
|
1361
|
+
if (item === currentItem) {
|
|
1362
|
+
return true;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
return false;
|
|
1366
|
+
}
|
|
1367
|
+
setBasePageForItemToDisplay(item, itemsAll) {
|
|
1368
|
+
for (let i = 0; i < itemsAll.length; i++) {
|
|
1369
|
+
if (itemsAll[i] === item) {
|
|
1370
|
+
this.calculateBasePage(i);
|
|
1371
|
+
this.updateVirtualizedItemListIntern(itemsAll);
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Updates the number of grouped items and list items for the whole list for the different areas:
|
|
1378
|
+
* - The not virtualized items on top of the list (represented by the 'beforeHeight')
|
|
1379
|
+
* - The virtualized items
|
|
1380
|
+
* - The not virtualized items on the bottom of the list (represented by the 'afterHeight')
|
|
1381
|
+
*/
|
|
1382
|
+
updateItemsTypeCount(itemsAll, scrolledPages) {
|
|
1383
|
+
if (this.siTreeViewService.groupedList) {
|
|
1384
|
+
this.updateItemsTypeCountForGroupList(itemsAll, scrolledPages);
|
|
1385
|
+
}
|
|
1386
|
+
else {
|
|
1387
|
+
this.groupItemsCountBefore = 0;
|
|
1388
|
+
this.groupItemsCountVirtualized = 0;
|
|
1389
|
+
this.groupItemsCountAfter = 0;
|
|
1390
|
+
this.listItemsCountBefore = this.itemBaseIdx;
|
|
1391
|
+
this.listItemsCountVirtualized = this.itemsVirtualizedCount;
|
|
1392
|
+
this.listItemsCountAfter =
|
|
1393
|
+
itemsAll.length - this.listItemsCountBefore - this.listItemsCountVirtualized;
|
|
1394
|
+
}
|
|
1395
|
+
this.updateItemsTypeCountPerVirtPage();
|
|
1396
|
+
if (this.itemsCountTotal !== itemsAll.length) {
|
|
1397
|
+
console.error('TreeListVirtualizationService: updateVirtualizedItemList().updateListItemsTypeCount() calculation error!');
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Updates the number of grouped items and list items per virtualized page.
|
|
1402
|
+
*/
|
|
1403
|
+
updateItemsTypeCountPerVirtPage() {
|
|
1404
|
+
this.listItemsPerVirtPage = [];
|
|
1405
|
+
this.groupItemsPerVirtPage = [];
|
|
1406
|
+
for (let basePgIdx = 0; basePgIdx < this.pagesVirtualized; basePgIdx++) {
|
|
1407
|
+
const baseIdx = basePgIdx * this.pageSize;
|
|
1408
|
+
let groupItemsCount = 0;
|
|
1409
|
+
let listItemsCount = 0;
|
|
1410
|
+
for (let idx = baseIdx; idx < baseIdx + this.pageSize; idx++) {
|
|
1411
|
+
if (idx < this.itemsVirtualized.length) {
|
|
1412
|
+
const item = this.itemsVirtualized[idx];
|
|
1413
|
+
if (this.isGroupItem(item)) {
|
|
1414
|
+
groupItemsCount++;
|
|
1415
|
+
}
|
|
1416
|
+
else {
|
|
1417
|
+
listItemsCount++;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
else {
|
|
1421
|
+
break;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
this.listItemsPerVirtPage.push(listItemsCount);
|
|
1425
|
+
this.groupItemsPerVirtPage.push(groupItemsCount);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
calculateVirtPageHeight(index) {
|
|
1429
|
+
if (index >= this.groupItemsPerVirtPage.length) {
|
|
1430
|
+
return 0;
|
|
1431
|
+
}
|
|
1432
|
+
if (this.siTreeViewService.groupedList) {
|
|
1433
|
+
if (this.siTreeViewItemHeightService.itemHeight !== undefined) {
|
|
1434
|
+
return (this.listItemsPerVirtPage[index] * this.siTreeViewItemHeightService.itemHeight +
|
|
1435
|
+
this.groupItemsPerVirtPage[index] *
|
|
1436
|
+
(this.siTreeViewItemHeightService.groupItemHeight ?? 0));
|
|
1437
|
+
}
|
|
1438
|
+
else {
|
|
1439
|
+
return (this.groupItemsPerVirtPage[index] *
|
|
1440
|
+
(this.siTreeViewItemHeightService.groupItemHeight ?? 0));
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
else {
|
|
1444
|
+
return this.listItemsPerVirtPage[index] * (this.siTreeViewItemHeightService.itemHeight ?? 0);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
updateItemsTypeCountForGroupList(itemsAll, scrolledPages) {
|
|
1448
|
+
if (scrolledPages !== undefined && scrolledPages !== 0) {
|
|
1449
|
+
this.updateItemsTypeCountForGroupListScrolling(itemsAll, scrolledPages);
|
|
1450
|
+
}
|
|
1451
|
+
else {
|
|
1452
|
+
this.updateListItemsTypeCountForGroupListFull(itemsAll);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
updateItemsTypeCountForGroupListScrolling(itemsAll, scrolledPages) {
|
|
1456
|
+
// this method optimizes the update of the type counters in regards of performance in case of scrolling
|
|
1457
|
+
// the method considers the difference of the pageBase for the calculation of the counters.
|
|
1458
|
+
scrolledPages = scrolledPages ?? 0;
|
|
1459
|
+
const oldBaseIndex = (this.pageBase - scrolledPages) * this.pageSize;
|
|
1460
|
+
const newBaseIndex = this.pageBase * this.pageSize;
|
|
1461
|
+
this.groupItemsCountAfter = this.groupItemsCountAfter + this.groupItemsCountVirtualized;
|
|
1462
|
+
this.listItemsCountAfter = this.listItemsCountAfter + this.listItemsCountVirtualized;
|
|
1463
|
+
this.groupItemsCountVirtualized = 0;
|
|
1464
|
+
this.listItemsCountVirtualized = 0;
|
|
1465
|
+
if (scrolledPages > 0) {
|
|
1466
|
+
for (let idx = oldBaseIndex; idx < newBaseIndex; idx++) {
|
|
1467
|
+
if (this.isGroupItem(itemsAll[idx])) {
|
|
1468
|
+
this.groupItemsCountBefore++;
|
|
1469
|
+
this.groupItemsCountAfter--;
|
|
1470
|
+
}
|
|
1471
|
+
else {
|
|
1472
|
+
this.listItemsCountBefore++;
|
|
1473
|
+
this.listItemsCountAfter--;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
else {
|
|
1478
|
+
for (let idx = newBaseIndex; idx < oldBaseIndex; idx++) {
|
|
1479
|
+
if (this.isGroupItem(itemsAll[idx])) {
|
|
1480
|
+
this.groupItemsCountBefore--;
|
|
1481
|
+
this.groupItemsCountAfter++;
|
|
1482
|
+
}
|
|
1483
|
+
else {
|
|
1484
|
+
this.listItemsCountBefore--;
|
|
1485
|
+
this.listItemsCountAfter++;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
const upper = newBaseIndex + this.itemsVirtualizedCount;
|
|
1490
|
+
for (let vi = newBaseIndex; vi < upper; vi++) {
|
|
1491
|
+
if (this.isGroupItem(itemsAll[vi])) {
|
|
1492
|
+
this.groupItemsCountVirtualized++;
|
|
1493
|
+
}
|
|
1494
|
+
else {
|
|
1495
|
+
this.listItemsCountVirtualized++;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
this.groupItemsCountAfter = this.groupItemsCountAfter - this.groupItemsCountVirtualized;
|
|
1499
|
+
this.listItemsCountAfter = this.listItemsCountAfter - this.listItemsCountVirtualized;
|
|
1500
|
+
}
|
|
1501
|
+
updateListItemsTypeCountForGroupListFull(itemsAll) {
|
|
1502
|
+
// does fully update the counters for the whole list.
|
|
1503
|
+
this.groupItemsCountBefore = 0;
|
|
1504
|
+
this.groupItemsCountVirtualized = 0;
|
|
1505
|
+
this.groupItemsCountAfter = 0;
|
|
1506
|
+
const virtTop = this.itemBaseIdx + this.itemsVirtualizedCount;
|
|
1507
|
+
for (let i = 0; i < itemsAll.length; i++) {
|
|
1508
|
+
if (this.isGroupItem(itemsAll[i])) {
|
|
1509
|
+
if (i < this.itemBaseIdx) {
|
|
1510
|
+
this.groupItemsCountBefore++;
|
|
1511
|
+
}
|
|
1512
|
+
else if (i < virtTop) {
|
|
1513
|
+
this.groupItemsCountVirtualized++;
|
|
1514
|
+
}
|
|
1515
|
+
else {
|
|
1516
|
+
this.groupItemsCountAfter++;
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
this.listItemsCountBefore = this.itemBaseIdx - this.groupItemsCountBefore;
|
|
1521
|
+
this.listItemsCountVirtualized = this.itemsVirtualizedCount - this.groupItemsCountVirtualized;
|
|
1522
|
+
this.listItemsCountAfter =
|
|
1523
|
+
itemsAll.length -
|
|
1524
|
+
this.listItemsCountBefore -
|
|
1525
|
+
this.listItemsCountVirtualized -
|
|
1526
|
+
this.groupItemsCountBefore -
|
|
1527
|
+
this.groupItemsCountVirtualized -
|
|
1528
|
+
this.groupItemsCountAfter;
|
|
1529
|
+
}
|
|
1530
|
+
isGroupItem(item) {
|
|
1531
|
+
return !item.parent && this.siTreeViewService.groupedList;
|
|
1532
|
+
}
|
|
1533
|
+
handleScrollSimple(scrollTop, itemsAll) {
|
|
1534
|
+
// Notes:
|
|
1535
|
+
// This method is used in case all tree list items are of the same height.
|
|
1536
|
+
// This allows for an optimized and proper calculation of the pageBase.
|
|
1537
|
+
// pageBase stores the index of the first page which is virtualized.
|
|
1538
|
+
// totalDeltaScrollVirt corresponds to the total virtualized items height above the visible are!
|
|
1539
|
+
const totalDeltaScrollVirt = scrollTop - this.heightBefore;
|
|
1540
|
+
let updateVirtList = false;
|
|
1541
|
+
const pageHeight = this.pageSize * (this.siTreeViewItemHeightService.itemHeight ?? 0);
|
|
1542
|
+
const pageBaseOld = this.pageBase;
|
|
1543
|
+
const pageChangeDownTrigger = 3;
|
|
1544
|
+
if (this.scrollTopPrev < scrollTop) {
|
|
1545
|
+
// Scroll down:
|
|
1546
|
+
// We do keep always between two and three pages virtualized above the view, when scrolling down.
|
|
1547
|
+
// => We remove pages from the top only when more than three pages are 'above' the visible view
|
|
1548
|
+
// => It is mandatory, that the trigger points are calculated exactly in order to get a nice scrolling behavior for all situations
|
|
1549
|
+
if (totalDeltaScrollVirt > pageChangeDownTrigger * pageHeight) {
|
|
1550
|
+
const pagesOutsideView = totalDeltaScrollVirt / pageHeight;
|
|
1551
|
+
// Two pages shall remain 'above' the view;
|
|
1552
|
+
// It is important that this number is higher than the trigger when scrolling up (which is one page, see the next else statement)
|
|
1553
|
+
// Thus we have a hysteresis of one page in order to avoid scrollbar jitters!!
|
|
1554
|
+
this._pageBase = this.pageBase + Math.floor(pagesOutsideView) - (pageChangeDownTrigger - 1);
|
|
1555
|
+
updateVirtList = true;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
else if (this.scrollTopPrev > scrollTop) {
|
|
1559
|
+
// scroll up
|
|
1560
|
+
if (totalDeltaScrollVirt < pageHeight) {
|
|
1561
|
+
// we add pages to the top as soon as only one page (or smaller) is 'above' the visible view
|
|
1562
|
+
const pagesOutsideView = totalDeltaScrollVirt / pageHeight;
|
|
1563
|
+
this._pageBase = this.pageBase + Math.floor(pagesOutsideView) - (pageChangeDownTrigger - 2);
|
|
1564
|
+
if (this.pageBase < 0) {
|
|
1565
|
+
this._pageBase = 0; // pageBase cannot be lower than 0; if pageBase=0 then we have no pages above the visible view.
|
|
1566
|
+
}
|
|
1567
|
+
if (this._pageBase !== pageBaseOld) {
|
|
1568
|
+
updateVirtList = true;
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
this.scrollTopPrev = scrollTop;
|
|
1573
|
+
if (updateVirtList) {
|
|
1574
|
+
this.updateVirtualizedItemListIntern(itemsAll, this.pageBase - pageBaseOld);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
handleScrollGrouped(scrollTop, itemsAll) {
|
|
1578
|
+
// Notes:
|
|
1579
|
+
// This method is used in case the tree list is grouped => the group items have a different height than the other items.
|
|
1580
|
+
// This allows for an optimized and avaeraged calculation of the new pageBase.
|
|
1581
|
+
// pageBase stores the index of the first page which is virtualized.
|
|
1582
|
+
// totalDeltaScrollVirt corresponds to the total virtualized items height above the visible are!
|
|
1583
|
+
const totalDeltaScrollVirt = scrollTop - this.heightBefore;
|
|
1584
|
+
const pageHeightFirst3 = this.calculateVirtPageHeight(0) +
|
|
1585
|
+
this.calculateVirtPageHeight(1) +
|
|
1586
|
+
this.calculateVirtPageHeight(2);
|
|
1587
|
+
let updateVirtList = false;
|
|
1588
|
+
const pageHeightFirst1 = this.calculateVirtPageHeight(0);
|
|
1589
|
+
const pageHeightAvg = pageHeightFirst3 / 3;
|
|
1590
|
+
const pageBaseOld = this.pageBase;
|
|
1591
|
+
if (this.scrollTopPrev < scrollTop) {
|
|
1592
|
+
// Scroll down:
|
|
1593
|
+
// We do keep always between two and three pages virtualized above the view, when scrolling down.
|
|
1594
|
+
// => We remove pages from the top only when more than three pages are 'above' the visible view.
|
|
1595
|
+
// => It is mandatory, that the trigger points are calculated exactly in order to get a nice scrolling behavior for all situations.
|
|
1596
|
+
if (totalDeltaScrollVirt > pageHeightFirst3) {
|
|
1597
|
+
// Next calculation is averaged. It seems not needed to properly calculate it based on the all the real items.
|
|
1598
|
+
const pagesOutsideView = totalDeltaScrollVirt / pageHeightAvg;
|
|
1599
|
+
// Two pages shall remain 'above' the view;
|
|
1600
|
+
// It is important that this number is higher than the trigger when scrolling up (which is one page, see next else).
|
|
1601
|
+
// Thus we have a hysteresis of one page in order to avoid scrollbar jitters!!
|
|
1602
|
+
this._pageBase = this.pageBase + Math.floor(pagesOutsideView) - 2;
|
|
1603
|
+
updateVirtList = true;
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
else if (this.scrollTopPrev > scrollTop) {
|
|
1607
|
+
// scroll up
|
|
1608
|
+
if (totalDeltaScrollVirt < pageHeightFirst1) {
|
|
1609
|
+
// we add pages to the top as soon as only one page (or smaller) is 'above' the visible view
|
|
1610
|
+
const pagesOutsideView = totalDeltaScrollVirt / pageHeightAvg;
|
|
1611
|
+
this._pageBase = this.pageBase + Math.floor(pagesOutsideView) - 1;
|
|
1612
|
+
if (this.pageBase < 0) {
|
|
1613
|
+
this._pageBase = 0; // pageBase cannot be lower than 0; if pageBase=0 then we have no pages above the visible view.
|
|
1614
|
+
}
|
|
1615
|
+
if (this._pageBase !== pageBaseOld) {
|
|
1616
|
+
updateVirtList = true;
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
this.scrollTopPrev = scrollTop;
|
|
1621
|
+
if (updateVirtList) {
|
|
1622
|
+
this.updateVirtualizedItemListIntern(itemsAll, this.pageBase - pageBaseOld);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewVirtualizationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1626
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewVirtualizationService });
|
|
1627
|
+
}
|
|
1628
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewVirtualizationService, decorators: [{
|
|
1629
|
+
type: Injectable
|
|
1630
|
+
}] });
|
|
1631
|
+
|
|
1632
|
+
/**
|
|
1633
|
+
* Copyright Siemens 2016 - 2025.
|
|
1634
|
+
* SPDX-License-Identifier: MIT
|
|
1635
|
+
*/
|
|
1636
|
+
/*
|
|
1637
|
+
* WARNING: Parts of this component are made to be used in conjunction with Bootstrap.
|
|
1638
|
+
* Bootstrap is not included with this package and has to be installed separately.
|
|
1639
|
+
*/
|
|
1640
|
+
const rootDefaults = {
|
|
1641
|
+
label: 'root',
|
|
1642
|
+
level: ROOT_LEVEL,
|
|
1643
|
+
state: 'expanded',
|
|
1644
|
+
selectable: false
|
|
1645
|
+
};
|
|
1646
|
+
/**
|
|
1647
|
+
* Implements a tree view with the following main capabilities:
|
|
1648
|
+
* Showing multiple trees. The data of the trees is set via the input property 'items'.
|
|
1649
|
+
* Showing the trees in a flat mode with navigation/bread/crumb on top.
|
|
1650
|
+
* A tree/list item is composed of a 'folder' icon, any item icon, the label, two additional datafields and a context menu button.
|
|
1651
|
+
* Children of parent nodes are lazy loaded upon request (in case they are not yet available in model.)
|
|
1652
|
+
* Context menu support via context menu item: the context menu items can be set via input properties.
|
|
1653
|
+
* Multi selection and focus support.
|
|
1654
|
+
* Checkboxes and / or option boxes per tree node.
|
|
1655
|
+
* Virtualization support: Input properties allow to set the page size and the number of pages to be virtualized.
|
|
1656
|
+
* Current limitation is roughly half a million of nodes. This is due to some 'strange' behavior with flex containers.
|
|
1657
|
+
* Set the input properties 'pageSize' and 'pagesVirtualized' to a reasonable amount of virtualized items.
|
|
1658
|
+
* The number of virtualized items is the product of the pageSize and the pagesVirtualized (no of pages virtualized).
|
|
1659
|
+
* Choose a value in the area of 50 virtualized items, dependent on the screen size. Check at runtime if appropriate!
|
|
1660
|
+
* Grouped List support: The component does also support grouped lists.
|
|
1661
|
+
* See the test client implementation of this package for all functionality.
|
|
1662
|
+
*/
|
|
1663
|
+
class SiTreeViewComponent {
|
|
1664
|
+
/**
|
|
1665
|
+
* The context menu items which are bound to the context menu of all tree items,
|
|
1666
|
+
* or a menu item provider function that is invoked for each tree item once.
|
|
1667
|
+
*
|
|
1668
|
+
* @defaultValue []
|
|
1669
|
+
*/
|
|
1670
|
+
contextMenuItems = input([]);
|
|
1671
|
+
/**
|
|
1672
|
+
* The indentation in pixel for the children in respect to its parent.
|
|
1673
|
+
*
|
|
1674
|
+
* @defaultValue DEFAULT_CHILDREN_INDENTATION
|
|
1675
|
+
*/
|
|
1676
|
+
childrenIndentation = input(DEFAULT_CHILDREN_INDENTATION);
|
|
1677
|
+
/**
|
|
1678
|
+
* Enable horizontal scrolling. When disabled (the default), an ellipsis is used for overflowing text
|
|
1679
|
+
*
|
|
1680
|
+
* @defaultValue false
|
|
1681
|
+
*/
|
|
1682
|
+
horizontalScrolling = input(false, { transform: booleanAttribute });
|
|
1683
|
+
/**
|
|
1684
|
+
* Enable the compact mode, making it more vertically compact.
|
|
1685
|
+
*
|
|
1686
|
+
* @defaultValue false
|
|
1687
|
+
*/
|
|
1688
|
+
compactMode = input(false, { transform: booleanAttribute });
|
|
1689
|
+
/**
|
|
1690
|
+
* Enable buttons for collapse and expand all.
|
|
1691
|
+
* Does not work when `flatTree` is enabled.
|
|
1692
|
+
*
|
|
1693
|
+
* @defaultValue false
|
|
1694
|
+
*/
|
|
1695
|
+
expandCollapseAll = input(false, { transform: booleanAttribute });
|
|
1696
|
+
/**
|
|
1697
|
+
* Tooltip text shown for the expand all icon.
|
|
1698
|
+
*
|
|
1699
|
+
* @defaultValue
|
|
1700
|
+
* ```
|
|
1701
|
+
* $localize`:@@SI_TREE_VIEW.EXPAND_ALL:Expand all`
|
|
1702
|
+
* ```
|
|
1703
|
+
*/
|
|
1704
|
+
expandAllTooltip = input($localize `:@@SI_TREE_VIEW.EXPAND_ALL:Expand all`);
|
|
1705
|
+
/**
|
|
1706
|
+
* Tooltip text shown for the collapse all icon.
|
|
1707
|
+
*
|
|
1708
|
+
* @defaultValue
|
|
1709
|
+
* ```
|
|
1710
|
+
* $localize`:@@SI_TREE_VIEW.COLLAPSE_ALL:Collapse all`
|
|
1711
|
+
* ```
|
|
1712
|
+
*/
|
|
1713
|
+
collapseAllTooltip = input($localize `:@@SI_TREE_VIEW.COLLAPSE_ALL:Collapse all`);
|
|
1714
|
+
/**
|
|
1715
|
+
* Customize icons for treeview.
|
|
1716
|
+
*/
|
|
1717
|
+
icons = input();
|
|
1718
|
+
/**
|
|
1719
|
+
* Track-by function for tree items. By default, items are tracked by their identity.
|
|
1720
|
+
*
|
|
1721
|
+
* @deprecated has no effect and will be removed
|
|
1722
|
+
*
|
|
1723
|
+
* @defaultValue
|
|
1724
|
+
* ```
|
|
1725
|
+
* buildTrackByIdentity<TreeItem>()
|
|
1726
|
+
* ```
|
|
1727
|
+
*/
|
|
1728
|
+
trackByFunction = input(buildTrackByIdentity());
|
|
1729
|
+
/**
|
|
1730
|
+
* Number of rows per page. Used for the virtualization of rows (number of
|
|
1731
|
+
* rows per page).
|
|
1732
|
+
* @defaultValue 10
|
|
1733
|
+
* @defaultref {@link SiTreeViewVirtualizationService#pageSize}
|
|
1734
|
+
*/
|
|
1735
|
+
pageSize = input(10, {
|
|
1736
|
+
transform: (value) => (value < 5 ? 5 : value)
|
|
1737
|
+
});
|
|
1738
|
+
/**
|
|
1739
|
+
* Number of pages which are virtualized.
|
|
1740
|
+
* @defaultValue 6
|
|
1741
|
+
* @defaultref {@link SiTreeViewVirtualizationService#pagesVirtualized}
|
|
1742
|
+
*/
|
|
1743
|
+
pagesVirtualized = input(6, {
|
|
1744
|
+
transform: (value) => (value < 5 ? 5 : value)
|
|
1745
|
+
});
|
|
1746
|
+
/**
|
|
1747
|
+
* Whether "filled" icons should not be used when a tree item is selected.
|
|
1748
|
+
* Per default filled icons are used when available.
|
|
1749
|
+
* @defaultValue false
|
|
1750
|
+
*/
|
|
1751
|
+
disableFilledIcons = input(false, { transform: booleanAttribute });
|
|
1752
|
+
/**
|
|
1753
|
+
* Sets if the folder state icon shall be shown on the left (in LTR) or on the right (in LTR) side
|
|
1754
|
+
* of the tree item. Per default the icon will be shown on the left (in LTR). Has no
|
|
1755
|
+
* effect if flatTree is enabled.
|
|
1756
|
+
* @defaultValue true
|
|
1757
|
+
*/
|
|
1758
|
+
folderStateStart = input(true, { transform: booleanAttribute });
|
|
1759
|
+
/**
|
|
1760
|
+
* Sets if the tree list shall virtualize the tree items.
|
|
1761
|
+
* This input field must be set at startup and shall not be changed afterwards.
|
|
1762
|
+
* @defaultValue true
|
|
1763
|
+
*/
|
|
1764
|
+
isVirtualized = input(true, { transform: booleanAttribute });
|
|
1765
|
+
/**
|
|
1766
|
+
* Sets the root tree items of all the trees (Required).
|
|
1767
|
+
* @defaultValue []
|
|
1768
|
+
* @defaultref {@link _items}
|
|
1769
|
+
*/
|
|
1770
|
+
items = input([]);
|
|
1771
|
+
/**
|
|
1772
|
+
* Sets the tree item to be selected.
|
|
1773
|
+
*/
|
|
1774
|
+
selectedItem = input();
|
|
1775
|
+
/**
|
|
1776
|
+
* Sets if the tree shall force single tree item selection.
|
|
1777
|
+
* @defaultValue false
|
|
1778
|
+
*/
|
|
1779
|
+
singleSelectMode = input(false, { transform: booleanAttribute });
|
|
1780
|
+
/**
|
|
1781
|
+
* Shows or hides additional information below the label.
|
|
1782
|
+
* @defaultValue false
|
|
1783
|
+
*/
|
|
1784
|
+
enableDataField1 = input(false, { transform: booleanAttribute });
|
|
1785
|
+
/**
|
|
1786
|
+
* Shows or hides additional information below the label.
|
|
1787
|
+
* @defaultValue false
|
|
1788
|
+
* @defaultref {@link SiTreeViewService#enableDataField2}
|
|
1789
|
+
*/
|
|
1790
|
+
enableDataField2 = input(false, { transform: booleanAttribute });
|
|
1791
|
+
/**
|
|
1792
|
+
* Shows or hides state pipe.
|
|
1793
|
+
* @defaultValue true
|
|
1794
|
+
*/
|
|
1795
|
+
enableStateIndicator = input(true, { transform: booleanAttribute });
|
|
1796
|
+
/**
|
|
1797
|
+
* Shows or hides icon
|
|
1798
|
+
* @defaultValue true
|
|
1799
|
+
*/
|
|
1800
|
+
enableIcon = input(true, { transform: booleanAttribute });
|
|
1801
|
+
/**
|
|
1802
|
+
* Shows or hides context menu button.
|
|
1803
|
+
* @defaultValue true
|
|
1804
|
+
* @defaultref {@link SiTreeViewService#enableContextMenuButton}
|
|
1805
|
+
*/
|
|
1806
|
+
enableContextMenuButton = input(true, { transform: booleanAttribute });
|
|
1807
|
+
/**
|
|
1808
|
+
* Allows / disabled selecting of tree items by clicking on them.
|
|
1809
|
+
* @defaultValue false
|
|
1810
|
+
*/
|
|
1811
|
+
enableSelection = input(false, { transform: booleanAttribute });
|
|
1812
|
+
/**
|
|
1813
|
+
* Sets if children are deleted upon collapsing tree items. This feature might
|
|
1814
|
+
* be used, if children shall be lazy loaded always upon expanding a tree
|
|
1815
|
+
* item.
|
|
1816
|
+
* @defaultValue false
|
|
1817
|
+
*/
|
|
1818
|
+
deleteChildrenOnCollapse = input(false, { transform: booleanAttribute });
|
|
1819
|
+
/**
|
|
1820
|
+
* Sets if the tree view shall be displayed as flat tree list with a
|
|
1821
|
+
* breadcrumb. A flat tree only shows the one level at the time and lists the
|
|
1822
|
+
* tree items of the current level as a list.
|
|
1823
|
+
* @defaultValue false
|
|
1824
|
+
* @defaultref {@link SiTreeViewService#flatTree}
|
|
1825
|
+
*/
|
|
1826
|
+
flatTree = input(false);
|
|
1827
|
+
/**
|
|
1828
|
+
* Sets if the tree view is displayed as a grouped list.
|
|
1829
|
+
* Important: In this mode, only the first two hierarchies of the tree model
|
|
1830
|
+
* are considered!
|
|
1831
|
+
* @defaultValue false
|
|
1832
|
+
* @defaultref {@link SiTreeViewService#groupedList}
|
|
1833
|
+
*/
|
|
1834
|
+
groupedList = input(false, { transform: booleanAttribute });
|
|
1835
|
+
/**
|
|
1836
|
+
* Sets if the tree items shall show a checkbox.
|
|
1837
|
+
* @defaultValue false
|
|
1838
|
+
* @defaultref {@link SiTreeViewService#enableCheckbox}
|
|
1839
|
+
*/
|
|
1840
|
+
enableCheckbox = input(false, { transform: booleanAttribute });
|
|
1841
|
+
/**
|
|
1842
|
+
* Sets if the tree items shall show an optionbox.
|
|
1843
|
+
* @defaultValue false
|
|
1844
|
+
*/
|
|
1845
|
+
enableOptionbox = input(false, { transform: booleanAttribute });
|
|
1846
|
+
/**
|
|
1847
|
+
* Sets if the tree items should expand/collapse when clicking on them.
|
|
1848
|
+
* Does not work when `flatTree` is enabled or the tree item is not selectable.
|
|
1849
|
+
* @defaultValue false
|
|
1850
|
+
*/
|
|
1851
|
+
expandOnClick = input(false, { transform: booleanAttribute });
|
|
1852
|
+
/**
|
|
1853
|
+
* Sets if the checkbox state of a tree item is inherited to its children/parent.
|
|
1854
|
+
* @defaultValue true
|
|
1855
|
+
*/
|
|
1856
|
+
inheritChecked = input(true, { transform: booleanAttribute });
|
|
1857
|
+
/**
|
|
1858
|
+
* String to be shown when there are no content actions.
|
|
1859
|
+
*
|
|
1860
|
+
* @defaultValue 'No actions available'
|
|
1861
|
+
*/
|
|
1862
|
+
noActionsString = input('No actions available');
|
|
1863
|
+
/** Aria label for the tree view. Needed for a11y, alternatively use {@link ariaLabelledBy}. */
|
|
1864
|
+
ariaLabel = input();
|
|
1865
|
+
/** Aria labelled by for the tree view. Needed for a11y, alternatively use {@link ariaLabel}. */
|
|
1866
|
+
ariaLabelledBy = input();
|
|
1867
|
+
/**
|
|
1868
|
+
* Triggered upon virtualization (or unvirtualization) of a tree item.
|
|
1869
|
+
*/
|
|
1870
|
+
itemsVirtualizedChanged = output();
|
|
1871
|
+
/**
|
|
1872
|
+
* Triggered upon clicking the folder of a tree item.
|
|
1873
|
+
*/
|
|
1874
|
+
treeItemFolderClicked = output();
|
|
1875
|
+
/**
|
|
1876
|
+
* Triggered upon a state change of the folder of a tree item.
|
|
1877
|
+
*/
|
|
1878
|
+
treeItemFolderStateChanged = output();
|
|
1879
|
+
/**
|
|
1880
|
+
* Triggered upon clicking the label of a tree item.
|
|
1881
|
+
*/
|
|
1882
|
+
treeItemClicked = output();
|
|
1883
|
+
/**
|
|
1884
|
+
* Triggered upon clicking the checkbox of a tree item.
|
|
1885
|
+
*/
|
|
1886
|
+
treeItemCheckboxClicked = output();
|
|
1887
|
+
/**
|
|
1888
|
+
* Triggered upon the request of loading the children of a tree item.
|
|
1889
|
+
*/
|
|
1890
|
+
loadChildren = output();
|
|
1891
|
+
/**
|
|
1892
|
+
* Triggered upon the selection of a tree item (multi selection supported).
|
|
1893
|
+
*/
|
|
1894
|
+
treeItemsSelected = output();
|
|
1895
|
+
/**
|
|
1896
|
+
* The injected content with included SiTreeViewItemTemplateDirective.
|
|
1897
|
+
*/
|
|
1898
|
+
templates;
|
|
1899
|
+
initialized = false;
|
|
1900
|
+
updateTreeItemHeightRequired = true; // must be set to true so the height is initially calculated once at least
|
|
1901
|
+
updateGroupItemHeightRequired = true; // must be set to true so the height is initially calculated once at least
|
|
1902
|
+
selectedTreeItems = [];
|
|
1903
|
+
manuallySelectedTreeItems = false;
|
|
1904
|
+
latestFolderChanged;
|
|
1905
|
+
breadCrumbTreeItems = [];
|
|
1906
|
+
subscriptions = [];
|
|
1907
|
+
multiSelectionStart;
|
|
1908
|
+
_multiSelectionActive = false;
|
|
1909
|
+
domChangeObserver;
|
|
1910
|
+
scroll$;
|
|
1911
|
+
element = inject(ElementRef);
|
|
1912
|
+
siTreeViewService = inject(SiTreeViewService);
|
|
1913
|
+
siTreeViewConverterService = inject(SiTreeViewConverterService);
|
|
1914
|
+
siTreeViewVirtualizationService = inject(SiTreeViewVirtualizationService);
|
|
1915
|
+
siTreeViewItemHeightService = inject(SiTreeViewItemHeightService);
|
|
1916
|
+
cdRef = inject(ChangeDetectorRef);
|
|
1917
|
+
resizeObserver = inject(ResizeObserverService);
|
|
1918
|
+
/**
|
|
1919
|
+
* Create a virtual root node so there is just a single root node. This makes sure the tree
|
|
1920
|
+
* can be fully traversed starting from any node. This is needed e.g. for recursively
|
|
1921
|
+
* removing the "active" state from other nodes.
|
|
1922
|
+
*/
|
|
1923
|
+
virtualRoot = { ...rootDefaults };
|
|
1924
|
+
_items = signal(this.items());
|
|
1925
|
+
updateTreeItemDefaults(item) {
|
|
1926
|
+
item.showCheckbox ??= this.enableCheckbox();
|
|
1927
|
+
item.showOptionbox ??= this.enableOptionbox();
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* @internal
|
|
1931
|
+
*/
|
|
1932
|
+
computedIcons = computed(() => {
|
|
1933
|
+
return {
|
|
1934
|
+
...DEFAULT_TREE_ICON_SET,
|
|
1935
|
+
...this.icons()
|
|
1936
|
+
};
|
|
1937
|
+
});
|
|
1938
|
+
/** @internal */
|
|
1939
|
+
scrollChildIntoView = new Subject();
|
|
1940
|
+
/** @internal */
|
|
1941
|
+
childrenLoaded = new Subject();
|
|
1942
|
+
/**
|
|
1943
|
+
* @internal
|
|
1944
|
+
* Used internally by `SiTreeViewItemDirective` to determine if the items have changed,
|
|
1945
|
+
* and render the new items.
|
|
1946
|
+
*/
|
|
1947
|
+
evaluateForTreeItemsDiffer = new Subject();
|
|
1948
|
+
/** @internal */
|
|
1949
|
+
hasAnyChildren = true;
|
|
1950
|
+
/**
|
|
1951
|
+
* Gets the height of the div above the virtualized rows.
|
|
1952
|
+
*/
|
|
1953
|
+
get heightBefore() {
|
|
1954
|
+
return this.siTreeViewVirtualizationService.heightBefore + 'px';
|
|
1955
|
+
}
|
|
1956
|
+
/**
|
|
1957
|
+
* Gets the height of the div below the virtualized rows.
|
|
1958
|
+
*/
|
|
1959
|
+
get heightAfter() {
|
|
1960
|
+
return this.siTreeViewVirtualizationService.heightAfter + 'px';
|
|
1961
|
+
}
|
|
1962
|
+
/**
|
|
1963
|
+
* @internal
|
|
1964
|
+
* This is meant to be used for internal purpose.
|
|
1965
|
+
* Returns the virtualized items in the tree list uses virtualization, otherwise all items are returned as a flat list.
|
|
1966
|
+
* Bind these to the HTML.
|
|
1967
|
+
*/
|
|
1968
|
+
get itemsVirtualized() {
|
|
1969
|
+
return this.isVirtualized()
|
|
1970
|
+
? this.siTreeViewVirtualizationService.itemsVirtualized
|
|
1971
|
+
: this.siTreeViewConverterService.flattenedTrees;
|
|
1972
|
+
}
|
|
1973
|
+
children;
|
|
1974
|
+
treeItemContentTemplate;
|
|
1975
|
+
nextItmes;
|
|
1976
|
+
keyManager;
|
|
1977
|
+
/**
|
|
1978
|
+
* @internal
|
|
1979
|
+
* Returns index of the currently active Tree Item element in DOM
|
|
1980
|
+
* or null if there is no active tree item element
|
|
1981
|
+
*/
|
|
1982
|
+
get activeIndex() {
|
|
1983
|
+
// This method is called before afterViewInit. Everywhere else keymanager can be expected to exist.
|
|
1984
|
+
return this.keyManager?.activeItemIndex;
|
|
1985
|
+
}
|
|
1986
|
+
/** Can be used for [cdkDropListData] when using cdk drag and drop. */
|
|
1987
|
+
get dropListItems() {
|
|
1988
|
+
return this.itemsVirtualized;
|
|
1989
|
+
}
|
|
1990
|
+
ngOnChanges(changes) {
|
|
1991
|
+
// Compact mode change the CSS margins so it is necessary to
|
|
1992
|
+
// re-calc the tree item height
|
|
1993
|
+
if (changes.compactMode || changes.enableDataField1 || changes.enableDataField2) {
|
|
1994
|
+
this.updateTreeItemHeightRequired = true;
|
|
1995
|
+
}
|
|
1996
|
+
if (changes.flatTree) {
|
|
1997
|
+
this.handleTreeMode();
|
|
1998
|
+
}
|
|
1999
|
+
if (changes.pageSize) {
|
|
2000
|
+
this.siTreeViewVirtualizationService.pageSize = this.pageSize();
|
|
2001
|
+
this.resetVirtualizedItemList();
|
|
2002
|
+
}
|
|
2003
|
+
if (changes.pagesVirtualized) {
|
|
2004
|
+
this.siTreeViewVirtualizationService.pagesVirtualized = this.pagesVirtualized();
|
|
2005
|
+
this.resetVirtualizedItemList();
|
|
2006
|
+
}
|
|
2007
|
+
if (changes.enableCheckbox) {
|
|
2008
|
+
for (const element of this._items()) {
|
|
2009
|
+
enableCheckboxRecursive(element, this.enableCheckbox());
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
if (changes.enableOptionbox) {
|
|
2013
|
+
for (const element of this._items()) {
|
|
2014
|
+
enableOptionboxRecursive(element, this.enableOptionbox());
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
if (changes.groupedList) {
|
|
2018
|
+
this.siTreeViewService.groupedList = this.groupedList();
|
|
2019
|
+
if (this.groupedList()) {
|
|
2020
|
+
this.updateGroupItemHeightRequired = true;
|
|
2021
|
+
}
|
|
2022
|
+
this.fillFlattenedTree(this._items(), true);
|
|
2023
|
+
}
|
|
2024
|
+
if (changes.items) {
|
|
2025
|
+
this.treeItemsUpdated();
|
|
2026
|
+
}
|
|
2027
|
+
if (changes.selectedItem) {
|
|
2028
|
+
this.selectTreeItems(this.selectedItem());
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
ngOnInit() {
|
|
2032
|
+
this.scroll$ = defer(() => fromEvent(this.treeViewInnerElement.nativeElement, 'scroll'));
|
|
2033
|
+
this.siTreeViewService.scroll$ = this.scroll$;
|
|
2034
|
+
if (this.isVirtualized()) {
|
|
2035
|
+
this.subscriptions.push(this.scroll$.subscribe(event => this.onScroll(event)));
|
|
2036
|
+
}
|
|
2037
|
+
this.subscriptions.push(this.siTreeViewService.clickEvent.subscribe(event => this.onItemClicked(event)));
|
|
2038
|
+
this.subscriptions.push(this.siTreeViewService.folderClickEvent.subscribe(event => this.onItemFolderClicked(event)));
|
|
2039
|
+
this.subscriptions.push(this.siTreeViewService.checkboxClickEvent.subscribe(event => this.onItemCheckboxClicked(event)));
|
|
2040
|
+
this.subscriptions.push(this.siTreeViewService.loadChildrenEvent.subscribe(event => this.onLoadChildren(event)));
|
|
2041
|
+
this.subscriptions.push(this.siTreeViewService.scrollIntoViewEvent.subscribe(event => this.onScrollIntoView(event)));
|
|
2042
|
+
this.subscriptions.push(this.siTreeViewService.focusParentEvent.subscribe(event => {
|
|
2043
|
+
if (!this.flatTree()) {
|
|
2044
|
+
this.focusParentItem(event);
|
|
2045
|
+
return;
|
|
2046
|
+
}
|
|
2047
|
+
this.onFlatTreeNavigateUp();
|
|
2048
|
+
}));
|
|
2049
|
+
this.subscriptions.push(this.siTreeViewService.focusFirstChildEvent.subscribe(event => this.focusFirstChildItem(event)));
|
|
2050
|
+
this.subscriptions.push(this.siTreeViewVirtualizationService.itemsVirtualizedChanged.subscribe((event) => {
|
|
2051
|
+
this.itemsVirtualizedChanged.emit(event);
|
|
2052
|
+
this.evaluateForTreeItemsDiffer.next();
|
|
2053
|
+
this.cdRef.markForCheck();
|
|
2054
|
+
}));
|
|
2055
|
+
this.initialized = true;
|
|
2056
|
+
this.handleTreeMode();
|
|
2057
|
+
}
|
|
2058
|
+
ngAfterViewInit() {
|
|
2059
|
+
this.addClassObserver();
|
|
2060
|
+
this.subscriptions.push(this.monitorTreeSizeChanges().subscribe(d => this.updatePageSize(d)));
|
|
2061
|
+
this.keyManager = new FocusKeyManager(this.getChildren())
|
|
2062
|
+
.withWrap()
|
|
2063
|
+
.withAllowedModifierKeys(['shiftKey'])
|
|
2064
|
+
.withHomeAndEnd()
|
|
2065
|
+
.withTypeAhead();
|
|
2066
|
+
queueMicrotask(() => this.keyManager.updateActiveItem(0));
|
|
2067
|
+
}
|
|
2068
|
+
ngAfterViewChecked() {
|
|
2069
|
+
if (this.updateTreeItemHeightRequired &&
|
|
2070
|
+
this.siTreeViewConverterService.flattenedTrees.length > 0) {
|
|
2071
|
+
const oldHeight = this.siTreeViewItemHeightService.itemHeight;
|
|
2072
|
+
let newHeight;
|
|
2073
|
+
if (this.isVirtualized()) {
|
|
2074
|
+
newHeight = this.siTreeViewItemHeightService.updateItemHeight(this.treeViewInnerElement.nativeElement, this.siTreeViewConverterService.flattenedTrees, this.siTreeViewVirtualizationService.itemBaseIdx, this.siTreeViewVirtualizationService.itemsVirtualizedCount);
|
|
2075
|
+
}
|
|
2076
|
+
else {
|
|
2077
|
+
newHeight = this.siTreeViewItemHeightService.updateItemHeight(this.treeViewInnerElement.nativeElement, this.siTreeViewConverterService.flattenedTrees, 0, this.siTreeViewConverterService.flattenedTrees.length);
|
|
2078
|
+
}
|
|
2079
|
+
if (newHeight !== undefined && newHeight > 0) {
|
|
2080
|
+
this.updateTreeItemHeightRequired = false;
|
|
2081
|
+
if (oldHeight !== newHeight) {
|
|
2082
|
+
const task = () => {
|
|
2083
|
+
this.updateVirtualizedItemList();
|
|
2084
|
+
this.cdRef.markForCheck();
|
|
2085
|
+
};
|
|
2086
|
+
asyncScheduler.schedule(task, 0);
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
if (this.updateGroupItemHeightRequired &&
|
|
2091
|
+
this.siTreeViewConverterService.flattenedTrees.length > 0) {
|
|
2092
|
+
const oldHeight = this.siTreeViewItemHeightService.groupItemHeight;
|
|
2093
|
+
let newHeight;
|
|
2094
|
+
if (this.isVirtualized()) {
|
|
2095
|
+
newHeight = this.siTreeViewItemHeightService.updateGroupedItemHeight(this.treeViewInnerElement.nativeElement, this.siTreeViewConverterService.flattenedTrees, this.siTreeViewVirtualizationService.itemBaseIdx, this.siTreeViewVirtualizationService.itemsVirtualizedCount);
|
|
2096
|
+
}
|
|
2097
|
+
else {
|
|
2098
|
+
newHeight = this.siTreeViewItemHeightService.updateGroupedItemHeight(this.treeViewInnerElement.nativeElement, this.siTreeViewConverterService.flattenedTrees, 0, this.siTreeViewConverterService.flattenedTrees.length);
|
|
2099
|
+
}
|
|
2100
|
+
if (newHeight !== undefined) {
|
|
2101
|
+
this.updateGroupItemHeightRequired = false;
|
|
2102
|
+
if (oldHeight !== newHeight) {
|
|
2103
|
+
const task = () => {
|
|
2104
|
+
this.updateVirtualizedItemList();
|
|
2105
|
+
this.cdRef.markForCheck();
|
|
2106
|
+
};
|
|
2107
|
+
asyncScheduler.schedule(task, 0);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
ngOnDestroy() {
|
|
2113
|
+
this.subscriptions
|
|
2114
|
+
.filter(subscription => !!subscription)
|
|
2115
|
+
.forEach(subscription => subscription.unsubscribe());
|
|
2116
|
+
this.domChangeObserver?.disconnect();
|
|
2117
|
+
}
|
|
2118
|
+
/**
|
|
2119
|
+
* Returns the last breadcrumb tree item. Can be null in case the flat tree
|
|
2120
|
+
* shows the root.
|
|
2121
|
+
*/
|
|
2122
|
+
get lastBreadCrumbItem() {
|
|
2123
|
+
const item = this.breadCrumbTreeItems[this.breadCrumbTreeItems.length - 1];
|
|
2124
|
+
return item ? item : null;
|
|
2125
|
+
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Returns true if the header shows the root/home of the tree.
|
|
2128
|
+
*/
|
|
2129
|
+
get headerShowsRoot() {
|
|
2130
|
+
return this.lastBreadCrumbItem == null;
|
|
2131
|
+
}
|
|
2132
|
+
/**
|
|
2133
|
+
* Called by the owner of the tree upon returning the retrieved children of a
|
|
2134
|
+
* 'load children' request.
|
|
2135
|
+
*/
|
|
2136
|
+
childrenLoadingDone(item, children) {
|
|
2137
|
+
const oldState = item.state ?? 'collapsed';
|
|
2138
|
+
if (item?.state === 'expanding') {
|
|
2139
|
+
initializeTreeItemsRecursive(children, item, itemToUpdate => this.updateTreeItemDefaults(itemToUpdate));
|
|
2140
|
+
item.children = children;
|
|
2141
|
+
item.state = 'expanded';
|
|
2142
|
+
}
|
|
2143
|
+
const newState = item.state ?? 'collapsed';
|
|
2144
|
+
this.updateBreadCrumb(this.evalLowestBreadCrumbNode());
|
|
2145
|
+
if (this.flatTree()) {
|
|
2146
|
+
this.fillFlattenedTree(children);
|
|
2147
|
+
this.focusFirstItemFlattened();
|
|
2148
|
+
}
|
|
2149
|
+
else {
|
|
2150
|
+
this.fillFlattenedTree(this._items());
|
|
2151
|
+
}
|
|
2152
|
+
if (oldState !== newState) {
|
|
2153
|
+
this.treeItemFolderStateChanged.emit(new FolderStateEventArgs(item, oldState, newState));
|
|
2154
|
+
}
|
|
2155
|
+
this.childrenLoaded.next(item);
|
|
2156
|
+
this.cdRef.markForCheck();
|
|
2157
|
+
}
|
|
2158
|
+
onFlatTreeNavigateUp() {
|
|
2159
|
+
if (this.lastBreadCrumbItem) {
|
|
2160
|
+
const last = this.lastBreadCrumbItem;
|
|
2161
|
+
this.onBreadCrumbItemClicked(last.parent);
|
|
2162
|
+
setTimeout(() => this.focusItem(last));
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
onFlatTreeNavigateHome() {
|
|
2166
|
+
this.onBreadCrumbItemClicked();
|
|
2167
|
+
this.focusFirstItemFlattened();
|
|
2168
|
+
}
|
|
2169
|
+
getChildren() {
|
|
2170
|
+
return !this.treeItemContentTemplate ? this.children : this.nextItmes;
|
|
2171
|
+
}
|
|
2172
|
+
focusItem(item) {
|
|
2173
|
+
const children = this.getChildren();
|
|
2174
|
+
const component = children?.find(child => child.treeItem === item);
|
|
2175
|
+
if (component) {
|
|
2176
|
+
this.keyManager.setActiveItem(component);
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
focusParentItem(item) {
|
|
2180
|
+
const parent = item.parent;
|
|
2181
|
+
if (parent && parent.level !== ROOT_LEVEL) {
|
|
2182
|
+
this.focusItem(parent);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
focusFirstChildItem(item) {
|
|
2186
|
+
const firstChild = item.children?.[0];
|
|
2187
|
+
if (firstChild) {
|
|
2188
|
+
const children = this.getChildren();
|
|
2189
|
+
const firstChildComponent = children?.find(child => child.treeItem === firstChild);
|
|
2190
|
+
if (firstChildComponent) {
|
|
2191
|
+
this.keyManager.setActiveItem(firstChildComponent);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
/**
|
|
2196
|
+
* Updates the tree to visualize the provided tree item by expanding all its parent items, collapsing all
|
|
2197
|
+
* other first level tree items and scroll to the provided item.
|
|
2198
|
+
* @param item - The tree item that shall be visible.
|
|
2199
|
+
*/
|
|
2200
|
+
showTreeItem(item) {
|
|
2201
|
+
this.doShowTreeItem(item);
|
|
2202
|
+
const task = () => {
|
|
2203
|
+
this.scrollChildIntoView.next(item);
|
|
2204
|
+
this.cdRef.markForCheck();
|
|
2205
|
+
};
|
|
2206
|
+
asyncScheduler.schedule(task, 0);
|
|
2207
|
+
}
|
|
2208
|
+
doShowTreeItem(item, collapseOtherNodes = true) {
|
|
2209
|
+
if (item.parent && item.parent.level !== ROOT_LEVEL) {
|
|
2210
|
+
this.expandTreeItem(item.parent);
|
|
2211
|
+
if (item.parent.parent && item.parent.parent.level !== ROOT_LEVEL) {
|
|
2212
|
+
this.doShowTreeItem(item.parent, collapseOtherNodes);
|
|
2213
|
+
}
|
|
2214
|
+
else if (collapseOtherNodes) {
|
|
2215
|
+
const myRoot = item.parent;
|
|
2216
|
+
for (const root of this._items()) {
|
|
2217
|
+
if (myRoot !== root) {
|
|
2218
|
+
this.collapseTreeItem(root);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
/**
|
|
2225
|
+
* Expands all tree items.
|
|
2226
|
+
* @param items - Optional param for recursion, will expand these items. If empty, all tree items will be expanded.
|
|
2227
|
+
*/
|
|
2228
|
+
expandAll(items) {
|
|
2229
|
+
(items ?? this._items()).forEach(item => {
|
|
2230
|
+
if (hasChildren(item) && childrenLoaded(item)) {
|
|
2231
|
+
if (item.state === 'collapsed') {
|
|
2232
|
+
this.expandTreeItem(item);
|
|
2233
|
+
}
|
|
2234
|
+
this.expandAll(item.children);
|
|
2235
|
+
}
|
|
2236
|
+
});
|
|
2237
|
+
}
|
|
2238
|
+
/**
|
|
2239
|
+
* Expands the provided tree item.
|
|
2240
|
+
* @param item - The tree item to be expanded.
|
|
2241
|
+
*/
|
|
2242
|
+
expandTreeItem(item) {
|
|
2243
|
+
const oldState = removeUndefinedState(item.state);
|
|
2244
|
+
expand(item);
|
|
2245
|
+
this.latestFolderChanged = item;
|
|
2246
|
+
this.siTreeViewService.folderClickEvent.next(new FolderStateEventArgs(item, oldState, removeUndefinedState(item.state)));
|
|
2247
|
+
}
|
|
2248
|
+
/**
|
|
2249
|
+
* Collapses all tree items.
|
|
2250
|
+
* @param items - Optional param for recursion, will collapse these items. If empty, all tree items will be collapsed.
|
|
2251
|
+
*/
|
|
2252
|
+
collapseAll(items) {
|
|
2253
|
+
(items ?? this._items()).forEach(item => {
|
|
2254
|
+
if (hasChildren(item)) {
|
|
2255
|
+
if (item.state === 'expanded' || item.state === 'expanding') {
|
|
2256
|
+
this.collapseTreeItem(item);
|
|
2257
|
+
}
|
|
2258
|
+
this.collapseAll(item.children);
|
|
2259
|
+
}
|
|
2260
|
+
});
|
|
2261
|
+
this.resetVirtualizedItemList();
|
|
2262
|
+
}
|
|
2263
|
+
/**
|
|
2264
|
+
* Collapses the provided tree item.
|
|
2265
|
+
* @param item - The tree item to be collapsed.
|
|
2266
|
+
*/
|
|
2267
|
+
collapseTreeItem(item) {
|
|
2268
|
+
const oldState = item.state ?? 'collapsed';
|
|
2269
|
+
collapse(item);
|
|
2270
|
+
this.latestFolderChanged = item;
|
|
2271
|
+
this.siTreeViewService.folderClickEvent.next(new FolderStateEventArgs(item, oldState, removeUndefinedState(item.state)));
|
|
2272
|
+
}
|
|
2273
|
+
/**
|
|
2274
|
+
* Add tree items as root elements or as children of an existing tree item.
|
|
2275
|
+
* @param children - Tree items to add.
|
|
2276
|
+
* @param parent - Optional parent tree item to which the items shall be added.
|
|
2277
|
+
* @param position - Optional position where to insert the tree items among their siblings.
|
|
2278
|
+
*/
|
|
2279
|
+
addChildItems(children, parent, position) {
|
|
2280
|
+
addChildItems(parent ?? this.virtualRoot, children, position, item => this.updateTreeItemDefaults(item));
|
|
2281
|
+
this.refresh();
|
|
2282
|
+
}
|
|
2283
|
+
/**
|
|
2284
|
+
* Forces a refresh of the view considering the current tree item model. Needs
|
|
2285
|
+
* to be called when tree items have been added, removed, or updated via model
|
|
2286
|
+
* in ways that do not trigger an automatic update of the view.
|
|
2287
|
+
*/
|
|
2288
|
+
refresh() {
|
|
2289
|
+
if (!this.flatTree()) {
|
|
2290
|
+
this.fillFlattenedTree(this._items());
|
|
2291
|
+
}
|
|
2292
|
+
else {
|
|
2293
|
+
this.fillFlattenedTree(this.evalListItemsForFlatTreeMode());
|
|
2294
|
+
}
|
|
2295
|
+
this.cdRef.markForCheck();
|
|
2296
|
+
}
|
|
2297
|
+
/**
|
|
2298
|
+
* Scrolls the specified tree item into view. Tree items will be expanded if
|
|
2299
|
+
* required.
|
|
2300
|
+
*/
|
|
2301
|
+
scrollItemIntoView(treeItem) {
|
|
2302
|
+
this.onScrollIntoViewByConsumer(treeItem);
|
|
2303
|
+
}
|
|
2304
|
+
evalListItemsForFlatTreeMode() {
|
|
2305
|
+
return this.lastBreadCrumbItem ? (this.lastBreadCrumbItem.children ?? []) : this._items();
|
|
2306
|
+
}
|
|
2307
|
+
collapseChildrenFlatTreeModeOnly(items) {
|
|
2308
|
+
this.collapseChildren(items, true);
|
|
2309
|
+
}
|
|
2310
|
+
collapseChildren(items, flatModeOnly = false) {
|
|
2311
|
+
if (flatModeOnly && !this.flatTree()) {
|
|
2312
|
+
return;
|
|
2313
|
+
}
|
|
2314
|
+
for (const item of items) {
|
|
2315
|
+
if (item.state === 'expanded' || item.state === 'expanding') {
|
|
2316
|
+
const oldState = item.state;
|
|
2317
|
+
collapse(item);
|
|
2318
|
+
this.latestFolderChanged = item;
|
|
2319
|
+
this.treeItemFolderStateChanged.emit(new FolderStateEventArgs(item, oldState, item.state));
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
onKeyUpShift() {
|
|
2324
|
+
if (this._multiSelectionActive) {
|
|
2325
|
+
this._multiSelectionActive = false;
|
|
2326
|
+
this.emitSelectedItems();
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
onKeyUpCtrl() {
|
|
2330
|
+
if (this._multiSelectionActive) {
|
|
2331
|
+
this._multiSelectionActive = false;
|
|
2332
|
+
this.emitSelectedItems();
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
onKeyUpMeta() {
|
|
2336
|
+
if (this._multiSelectionActive) {
|
|
2337
|
+
this._multiSelectionActive = false;
|
|
2338
|
+
this.emitSelectedItems();
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
onMouseLeave() {
|
|
2342
|
+
if (this._multiSelectionActive) {
|
|
2343
|
+
this._multiSelectionActive = false;
|
|
2344
|
+
this.emitSelectedItems();
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
handleKeydown(event) {
|
|
2348
|
+
this.keyManager.onKeydown(event);
|
|
2349
|
+
}
|
|
2350
|
+
onItemClicked(event) {
|
|
2351
|
+
let skipFocus = false;
|
|
2352
|
+
if (!event.target.selectable) {
|
|
2353
|
+
return;
|
|
2354
|
+
}
|
|
2355
|
+
this.manuallySelectedTreeItems = true;
|
|
2356
|
+
if ((event.mouseEvent.ctrlKey ||
|
|
2357
|
+
(navigator.userAgent.includes('Mac') && event.mouseEvent.metaKey)) &&
|
|
2358
|
+
!this.singleSelectMode()) {
|
|
2359
|
+
this._multiSelectionActive = true;
|
|
2360
|
+
this.multiSelectionStart = event.target;
|
|
2361
|
+
if (event.target.selected) {
|
|
2362
|
+
skipFocus = true;
|
|
2363
|
+
}
|
|
2364
|
+
event.target.selected = !event.target.selected;
|
|
2365
|
+
if (event.target.selected && !this.singleSelectMode()) {
|
|
2366
|
+
this.selectedTreeItems.push(event.target);
|
|
2367
|
+
}
|
|
2368
|
+
else {
|
|
2369
|
+
const idx = this.selectedTreeItems.indexOf(event.target);
|
|
2370
|
+
if (idx !== -1) {
|
|
2371
|
+
this.selectedTreeItems.splice(idx, 1);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
else if (event.mouseEvent.shiftKey && !this.singleSelectMode()) {
|
|
2376
|
+
this._multiSelectionActive = true;
|
|
2377
|
+
// If the anchor has not been established, set it to the first item in the selected
|
|
2378
|
+
// items list if defined ELSE the first item in the tree
|
|
2379
|
+
if (!this.multiSelectionStart) {
|
|
2380
|
+
this.multiSelectionStart = this.selectedTreeItems?.[0] ?? this._items()?.[0];
|
|
2381
|
+
}
|
|
2382
|
+
// If the tree is in flat mode, ensure the anchor is inside the currently selected folder
|
|
2383
|
+
if (this.flatTree()) {
|
|
2384
|
+
const treeItems = (event.target.parent ? event.target.parent.children : this._items()) ?? [];
|
|
2385
|
+
if (treeItems.findIndex(ti => ti === this.multiSelectionStart) < 0) {
|
|
2386
|
+
// Move anchor to top-level item in current folder!
|
|
2387
|
+
this.multiSelectionStart = treeItems[0];
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
for (const element of this._items()) {
|
|
2391
|
+
selectRecursive(element, false);
|
|
2392
|
+
}
|
|
2393
|
+
this.multiSelectionStart.selected = true;
|
|
2394
|
+
const selectedItems = selectItemsBetween(this._items(), this.multiSelectionStart, event.target);
|
|
2395
|
+
this.selectedTreeItems = [this.multiSelectionStart];
|
|
2396
|
+
if (selectedItems) {
|
|
2397
|
+
this.selectedTreeItems.push(...selectedItems);
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
else {
|
|
2401
|
+
this.multiSelectionStart = event.target;
|
|
2402
|
+
for (const element of this._items()) {
|
|
2403
|
+
selectRecursive(element, false);
|
|
2404
|
+
}
|
|
2405
|
+
event.target.selected = true;
|
|
2406
|
+
this.selectedTreeItems = [event.target];
|
|
2407
|
+
}
|
|
2408
|
+
for (const element of this._items()) {
|
|
2409
|
+
resetActive(element);
|
|
2410
|
+
}
|
|
2411
|
+
if (!skipFocus) {
|
|
2412
|
+
setActive(event.target, true);
|
|
2413
|
+
}
|
|
2414
|
+
this.treeItemClicked.emit(event.target);
|
|
2415
|
+
if (!this._multiSelectionActive) {
|
|
2416
|
+
this.emitSelectedItems();
|
|
2417
|
+
// Note, if multi selection would be active, we would emit the selected items only upon 'keyup' event for Shift and Control
|
|
2418
|
+
// and upon document.mouseleave event
|
|
2419
|
+
}
|
|
2420
|
+
this.cdRef.markForCheck();
|
|
2421
|
+
this.siTreeViewService.triggerMarkForCheck.next();
|
|
2422
|
+
}
|
|
2423
|
+
emitSelectedItems() {
|
|
2424
|
+
if (this.enableSelection()) {
|
|
2425
|
+
if (this.siTreeViewService.groupedList) {
|
|
2426
|
+
const filtered = this.selectedTreeItems.filter(item => !this.siTreeViewService.isGroupedItem(item));
|
|
2427
|
+
this.treeItemsSelected.emit(filtered);
|
|
2428
|
+
}
|
|
2429
|
+
else {
|
|
2430
|
+
this.treeItemsSelected.emit(this.selectedTreeItems);
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
handleTreeMode() {
|
|
2435
|
+
let ti;
|
|
2436
|
+
if (this.isVirtualized()) {
|
|
2437
|
+
ti = this.siTreeViewVirtualizationService.calculateFirstVisibleTreeItem();
|
|
2438
|
+
}
|
|
2439
|
+
if (this.flatTree()) {
|
|
2440
|
+
this.siTreeViewService.childrenIndentation = 0;
|
|
2441
|
+
if (this.selectedTreeItems.length && this.manuallySelectedTreeItems) {
|
|
2442
|
+
// manually selected items => display the (children of) parent of the (highest or first) selected item,
|
|
2443
|
+
// if there is no parent display the root node
|
|
2444
|
+
const sorted = this.selectedTreeItems.sort((itemA, itemB) => (itemA.level ?? 0) - (itemB.level ?? 0));
|
|
2445
|
+
this.fillFlattenedTree(sorted[0].parent?.children ?? this._items(), true);
|
|
2446
|
+
}
|
|
2447
|
+
else if (!this.latestFolderChanged) {
|
|
2448
|
+
// no folder state change of any tree item so far => display the root item in the list
|
|
2449
|
+
this.fillFlattenedTree(this._items(), true);
|
|
2450
|
+
}
|
|
2451
|
+
else if (this.latestFolderChanged.state === 'expanded') {
|
|
2452
|
+
this.fillFlattenedTree(this.latestFolderChanged.children ?? [], true);
|
|
2453
|
+
}
|
|
2454
|
+
else if (this.latestFolderChanged.parent) {
|
|
2455
|
+
this.fillFlattenedTree(this.latestFolderChanged.parent?.children ?? [], true);
|
|
2456
|
+
}
|
|
2457
|
+
else {
|
|
2458
|
+
this.fillFlattenedTree(this._items(), true);
|
|
2459
|
+
}
|
|
2460
|
+
this.updateBreadCrumb(this.evalLowestBreadCrumbNode());
|
|
2461
|
+
if (ti && !this.siTreeViewConverterService.flattenedTrees.includes(ti, 0)) {
|
|
2462
|
+
ti = this.siTreeViewConverterService.flattenedTrees[0];
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
else {
|
|
2466
|
+
this.siTreeViewService.childrenIndentation = this.childrenIndentation();
|
|
2467
|
+
this.fillFlattenedTree(this._items(), true);
|
|
2468
|
+
}
|
|
2469
|
+
this.onScrollIntoViewByConsumer(ti);
|
|
2470
|
+
}
|
|
2471
|
+
evalLowestBreadCrumbNode() {
|
|
2472
|
+
if (this.latestFolderChanged) {
|
|
2473
|
+
return this.latestFolderChanged.state === 'expanded'
|
|
2474
|
+
? this.latestFolderChanged
|
|
2475
|
+
: this.latestFolderChanged.parent;
|
|
2476
|
+
}
|
|
2477
|
+
return undefined;
|
|
2478
|
+
}
|
|
2479
|
+
treeViewInnerElement;
|
|
2480
|
+
onItemFolderClicked(eventArgs) {
|
|
2481
|
+
this.treeItemFolderClicked.emit(eventArgs);
|
|
2482
|
+
this.treeItemFolderStateChanged.emit(eventArgs);
|
|
2483
|
+
this.latestFolderChanged = eventArgs.treeItem;
|
|
2484
|
+
this.updateBreadCrumb(this.evalLowestBreadCrumbNode());
|
|
2485
|
+
if (!this.flatTree()) {
|
|
2486
|
+
this.fillFlattenedTree(this._items());
|
|
2487
|
+
}
|
|
2488
|
+
else if (this.latestFolderChanged.state === 'expanded') {
|
|
2489
|
+
this.fillFlattenedTree(this.latestFolderChanged.children ?? []);
|
|
2490
|
+
this.focusFirstItemFlattened();
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
updateBreadCrumb(treeItem) {
|
|
2494
|
+
if (!treeItem || treeItem.level === ROOT_LEVEL) {
|
|
2495
|
+
this.breadCrumbTreeItems = [];
|
|
2496
|
+
}
|
|
2497
|
+
else {
|
|
2498
|
+
this.breadCrumbTreeItems = [treeItem];
|
|
2499
|
+
this.pushParentItemsIntoBreadCrumbRecursive(treeItem);
|
|
2500
|
+
this.breadCrumbTreeItems = this.breadCrumbTreeItems.reverse();
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
pushParentItemsIntoBreadCrumbRecursive(treeItem) {
|
|
2504
|
+
if (treeItem?.parent && treeItem?.parent?.level !== ROOT_LEVEL) {
|
|
2505
|
+
this.breadCrumbTreeItems.push(treeItem.parent);
|
|
2506
|
+
this.pushParentItemsIntoBreadCrumbRecursive(treeItem.parent);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
onItemCheckboxClicked(eventArgs) {
|
|
2510
|
+
this.siTreeViewService.triggerMarkForCheck.next();
|
|
2511
|
+
this.treeItemCheckboxClicked.emit(eventArgs);
|
|
2512
|
+
}
|
|
2513
|
+
onLoadChildren(treeItem) {
|
|
2514
|
+
this.loadChildren.emit(new LoadChildrenEventArgs(treeItem, (item, children) => this.childrenLoadingDone(item, children)));
|
|
2515
|
+
}
|
|
2516
|
+
setFlatTreeSelectedFolder(treeItem) {
|
|
2517
|
+
if (this.flatTree()) {
|
|
2518
|
+
this.latestFolderChanged = treeItem;
|
|
2519
|
+
if (treeItem) {
|
|
2520
|
+
expand(treeItem);
|
|
2521
|
+
}
|
|
2522
|
+
this.onBreadCrumbItemClicked(treeItem);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
onBreadCrumbItemClicked(treeItem) {
|
|
2526
|
+
if (treeItem && treeItem.level !== ROOT_LEVEL) {
|
|
2527
|
+
this.fillFlattenedTree(treeItem.children ?? [], true);
|
|
2528
|
+
this.focusFirstItemFlattened();
|
|
2529
|
+
}
|
|
2530
|
+
else {
|
|
2531
|
+
this.fillFlattenedTree(this._items(), true);
|
|
2532
|
+
this.focusFirstItemFlattened();
|
|
2533
|
+
}
|
|
2534
|
+
this.updateBreadCrumb(treeItem);
|
|
2535
|
+
}
|
|
2536
|
+
onScroll(event) {
|
|
2537
|
+
if (this.isVirtualized()) {
|
|
2538
|
+
const scrollTop = event.target.scrollTop;
|
|
2539
|
+
this.siTreeViewVirtualizationService.handleScroll(scrollTop, this.siTreeViewConverterService.flattenedTrees);
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
/**
|
|
2543
|
+
* Called by the consumer when he wants a node to be scrolled into view.
|
|
2544
|
+
*/
|
|
2545
|
+
onScrollIntoViewByConsumer(treeItem) {
|
|
2546
|
+
if (treeItem) {
|
|
2547
|
+
if (this.isVirtualized()) {
|
|
2548
|
+
this.siTreeViewVirtualizationService.virtualizeItem(treeItem, this.siTreeViewConverterService.flattenedTrees);
|
|
2549
|
+
}
|
|
2550
|
+
// wait one cycle until the new children (in case of page virtualization) are created
|
|
2551
|
+
const task = () => {
|
|
2552
|
+
this.doShowTreeItem(treeItem, false); // keep previously opened nodes as it is
|
|
2553
|
+
asyncScheduler.schedule(() => {
|
|
2554
|
+
this.scrollChildIntoView.next(treeItem);
|
|
2555
|
+
this.cdRef.markForCheck();
|
|
2556
|
+
}, 0);
|
|
2557
|
+
};
|
|
2558
|
+
asyncScheduler.schedule(task, 0);
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
onScrollIntoView(elementTreeItem) {
|
|
2562
|
+
const clientRectNode = elementTreeItem.nativeElement.getBoundingClientRect();
|
|
2563
|
+
const clientRect = this.element.nativeElement.getBoundingClientRect();
|
|
2564
|
+
if (clientRectNode.top < clientRect.top ||
|
|
2565
|
+
clientRectNode.top + this.siTreeViewItemHeightService.itemHeight > clientRect.bottom) {
|
|
2566
|
+
elementTreeItem.nativeElement.scrollIntoView();
|
|
2567
|
+
}
|
|
2568
|
+
this.cdRef.markForCheck();
|
|
2569
|
+
}
|
|
2570
|
+
fillFlattenedTree(items, resetVirtualization = false) {
|
|
2571
|
+
this.collapseChildrenFlatTreeModeOnly(items);
|
|
2572
|
+
this.siTreeViewConverterService.fillFlattenedTree(items, this.flatTree());
|
|
2573
|
+
if (resetVirtualization) {
|
|
2574
|
+
this.resetVirtualizedItemList();
|
|
2575
|
+
}
|
|
2576
|
+
else {
|
|
2577
|
+
this.updateVirtualizedItemList();
|
|
2578
|
+
}
|
|
2579
|
+
this.evaluateForTreeItemsDiffer.next();
|
|
2580
|
+
}
|
|
2581
|
+
focusFirstItemFlattened() {
|
|
2582
|
+
setTimeout(() => this.keyManager.setFirstItemActive());
|
|
2583
|
+
}
|
|
2584
|
+
updateHasChildren() {
|
|
2585
|
+
this.hasAnyChildren = !!this.siTreeViewConverterService.flattenedTrees?.some(item => hasChildren(item));
|
|
2586
|
+
}
|
|
2587
|
+
updateVirtualizedItemList() {
|
|
2588
|
+
this.updateHasChildren();
|
|
2589
|
+
if (this.isVirtualized() && this.initialized) {
|
|
2590
|
+
this.siTreeViewVirtualizationService.updateVirtualizedItemList(this.siTreeViewConverterService.flattenedTrees);
|
|
2591
|
+
this.cdRef.markForCheck();
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
resetVirtualizedItemList() {
|
|
2595
|
+
this.updateHasChildren();
|
|
2596
|
+
if (this.isVirtualized() && this.initialized) {
|
|
2597
|
+
this.siTreeViewVirtualizationService.resetVirtualizedItemList(this.siTreeViewConverterService.flattenedTrees);
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
/**
|
|
2601
|
+
* Track class changes since adding classes like `.tree-sm` or `.tree-xs` change the item height.
|
|
2602
|
+
* Changes have to trigger the SiTreeViewItemHeightService otherwise the virtualized items are
|
|
2603
|
+
* calculated incorrectly which cause rendering issues.
|
|
2604
|
+
*/
|
|
2605
|
+
addClassObserver() {
|
|
2606
|
+
this.domChangeObserver = new MutationObserver((mutations) => {
|
|
2607
|
+
mutations.forEach((mutation) => {
|
|
2608
|
+
this.updateTreeItemHeightRequired = true;
|
|
2609
|
+
if (this.groupedList()) {
|
|
2610
|
+
this.updateGroupItemHeightRequired = true;
|
|
2611
|
+
}
|
|
2612
|
+
this.cdRef.markForCheck();
|
|
2613
|
+
});
|
|
2614
|
+
});
|
|
2615
|
+
this.domChangeObserver.observe(this.element.nativeElement, {
|
|
2616
|
+
attributeFilter: ['class', 'style']
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2619
|
+
/**
|
|
2620
|
+
* Create an observable to track visible dimensions and item height of the tree view.
|
|
2621
|
+
* It's necessary to dynamically increase the `pageSize` to render the correct amount
|
|
2622
|
+
* of visible tree items.
|
|
2623
|
+
* @returns observable with the current tree dimensions.
|
|
2624
|
+
*/
|
|
2625
|
+
monitorTreeSizeChanges() {
|
|
2626
|
+
const resize = this.resizeObserver.observe(this.element.nativeElement, 100, true, true);
|
|
2627
|
+
const merged = merge(resize, this.siTreeViewItemHeightService.itemHeightChange);
|
|
2628
|
+
return merged.pipe(withLatestFrom(resize), map(x => x[1]));
|
|
2629
|
+
}
|
|
2630
|
+
/**
|
|
2631
|
+
* Dynamically calculate and update the virtual pageSize to render the correct amount of tree items.
|
|
2632
|
+
* @param dimension - current tree dimensions.
|
|
2633
|
+
*/
|
|
2634
|
+
updatePageSize(dimension) {
|
|
2635
|
+
if (this.isVirtualized()) {
|
|
2636
|
+
// Re-calc number of virtualized items based on the visible component dimensions
|
|
2637
|
+
const itemHeight = this.siTreeViewItemHeightService.itemHeight;
|
|
2638
|
+
// Proceeding with itemHeight==0 leads to an error in
|
|
2639
|
+
// SiTreeViewVirtualizationService.updateListItemsTypeCount. It happens
|
|
2640
|
+
// when the component is created but not yet visible.
|
|
2641
|
+
if (!itemHeight) {
|
|
2642
|
+
return;
|
|
2643
|
+
}
|
|
2644
|
+
// Set page size to half the no. of items visible on the screen following
|
|
2645
|
+
// the recommendations in SiTreeViewVirtualizationService.
|
|
2646
|
+
const pageSize = Math.floor(dimension.height / itemHeight / 2);
|
|
2647
|
+
// Once the pageSize is initialized we are only allowed to increase
|
|
2648
|
+
// the number of virtualized items but do never reduce the size.
|
|
2649
|
+
// Since this would lead to a incorrect calculation of heightAfter
|
|
2650
|
+
// (see calculateBeforeAndAfter)
|
|
2651
|
+
if (pageSize > 0 && pageSize > this.siTreeViewVirtualizationService.pageSize) {
|
|
2652
|
+
this.siTreeViewVirtualizationService.pageSize = pageSize;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
/**
|
|
2657
|
+
* Make sure to always have a single item for single selection or if there is only one item in the array.
|
|
2658
|
+
*/
|
|
2659
|
+
coerceToSelectionType(treeItem) {
|
|
2660
|
+
if (Array.isArray(treeItem) && (treeItem.length <= 1 || this.singleSelectMode())) {
|
|
2661
|
+
// If array is empty, this will set it to undefined
|
|
2662
|
+
return treeItem[0];
|
|
2663
|
+
}
|
|
2664
|
+
return treeItem;
|
|
2665
|
+
}
|
|
2666
|
+
treeItemsUpdated() {
|
|
2667
|
+
this.selectedTreeItems = [];
|
|
2668
|
+
const items = this.items();
|
|
2669
|
+
this._items.set(items);
|
|
2670
|
+
this.virtualRoot = { ...rootDefaults, children: items };
|
|
2671
|
+
setTreeItemDefaults(this.virtualRoot, item => this.updateTreeItemDefaults(item));
|
|
2672
|
+
initializeTreeItemsRecursive(items, this.virtualRoot, item => this.updateTreeItemDefaults(item));
|
|
2673
|
+
this.fillFlattenedTree(items, true);
|
|
2674
|
+
this.latestFolderChanged = items[0];
|
|
2675
|
+
}
|
|
2676
|
+
selectTreeItems(treeItem) {
|
|
2677
|
+
const items = this.coerceToSelectionType(treeItem);
|
|
2678
|
+
const isMultipleTreeItems = Array.isArray(items);
|
|
2679
|
+
if ((isMultipleTreeItems && items.length) ||
|
|
2680
|
+
(!isMultipleTreeItems && items) ||
|
|
2681
|
+
this.selectedTreeItems.length) {
|
|
2682
|
+
this.manuallySelectedTreeItems = false;
|
|
2683
|
+
}
|
|
2684
|
+
if (!isMultipleTreeItems && items && !items.selectable) {
|
|
2685
|
+
return;
|
|
2686
|
+
}
|
|
2687
|
+
for (const element of this._items()) {
|
|
2688
|
+
selectRecursive(element, false);
|
|
2689
|
+
}
|
|
2690
|
+
this.selectedTreeItems = [];
|
|
2691
|
+
if (!items) {
|
|
2692
|
+
this.siTreeViewService.triggerMarkForCheck.next();
|
|
2693
|
+
return;
|
|
2694
|
+
}
|
|
2695
|
+
// If this is single select or multi select with only one item
|
|
2696
|
+
if (!isMultipleTreeItems) {
|
|
2697
|
+
items.selected = true;
|
|
2698
|
+
this.selectedTreeItems.push(items);
|
|
2699
|
+
this.setFlatTreeSelectedFolder(items.parent);
|
|
2700
|
+
if (this.isVirtualized()) {
|
|
2701
|
+
this.siTreeViewVirtualizationService.virtualizeItem(items, this.siTreeViewConverterService.flattenedTrees);
|
|
2702
|
+
}
|
|
2703
|
+
// wait one cycle until the new children (in case of page virtualization) are created
|
|
2704
|
+
const task = () => {
|
|
2705
|
+
this.scrollChildIntoView.next(items);
|
|
2706
|
+
this.cdRef.markForCheck();
|
|
2707
|
+
this.siTreeViewService.triggerMarkForCheck.next();
|
|
2708
|
+
};
|
|
2709
|
+
asyncScheduler.schedule(task, 0);
|
|
2710
|
+
}
|
|
2711
|
+
else {
|
|
2712
|
+
// Multi select with multiple items
|
|
2713
|
+
const task = () => {
|
|
2714
|
+
for (const item of items) {
|
|
2715
|
+
if (item.selectable === false) {
|
|
2716
|
+
continue;
|
|
2717
|
+
}
|
|
2718
|
+
item.selected = true;
|
|
2719
|
+
this.selectedTreeItems.push(item);
|
|
2720
|
+
}
|
|
2721
|
+
this.cdRef.markForCheck();
|
|
2722
|
+
this.siTreeViewService.triggerMarkForCheck.next();
|
|
2723
|
+
};
|
|
2724
|
+
asyncScheduler.schedule(task, 0);
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2728
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: SiTreeViewComponent, isStandalone: true, selector: "si-tree-view", inputs: { contextMenuItems: { classPropertyName: "contextMenuItems", publicName: "contextMenuItems", isSignal: true, isRequired: false, transformFunction: null }, childrenIndentation: { classPropertyName: "childrenIndentation", publicName: "childrenIndentation", isSignal: true, isRequired: false, transformFunction: null }, horizontalScrolling: { classPropertyName: "horizontalScrolling", publicName: "horizontalScrolling", isSignal: true, isRequired: false, transformFunction: null }, compactMode: { classPropertyName: "compactMode", publicName: "compactMode", isSignal: true, isRequired: false, transformFunction: null }, expandCollapseAll: { classPropertyName: "expandCollapseAll", publicName: "expandCollapseAll", isSignal: true, isRequired: false, transformFunction: null }, expandAllTooltip: { classPropertyName: "expandAllTooltip", publicName: "expandAllTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapseAllTooltip: { classPropertyName: "collapseAllTooltip", publicName: "collapseAllTooltip", isSignal: true, isRequired: false, transformFunction: null }, icons: { classPropertyName: "icons", publicName: "icons", isSignal: true, isRequired: false, transformFunction: null }, trackByFunction: { classPropertyName: "trackByFunction", publicName: "trackByFunction", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, pagesVirtualized: { classPropertyName: "pagesVirtualized", publicName: "pagesVirtualized", isSignal: true, isRequired: false, transformFunction: null }, disableFilledIcons: { classPropertyName: "disableFilledIcons", publicName: "disableFilledIcons", isSignal: true, isRequired: false, transformFunction: null }, folderStateStart: { classPropertyName: "folderStateStart", publicName: "folderStateStart", isSignal: true, isRequired: false, transformFunction: null }, isVirtualized: { classPropertyName: "isVirtualized", publicName: "isVirtualized", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, selectedItem: { classPropertyName: "selectedItem", publicName: "selectedItem", isSignal: true, isRequired: false, transformFunction: null }, singleSelectMode: { classPropertyName: "singleSelectMode", publicName: "singleSelectMode", isSignal: true, isRequired: false, transformFunction: null }, enableDataField1: { classPropertyName: "enableDataField1", publicName: "enableDataField1", isSignal: true, isRequired: false, transformFunction: null }, enableDataField2: { classPropertyName: "enableDataField2", publicName: "enableDataField2", isSignal: true, isRequired: false, transformFunction: null }, enableStateIndicator: { classPropertyName: "enableStateIndicator", publicName: "enableStateIndicator", isSignal: true, isRequired: false, transformFunction: null }, enableIcon: { classPropertyName: "enableIcon", publicName: "enableIcon", isSignal: true, isRequired: false, transformFunction: null }, enableContextMenuButton: { classPropertyName: "enableContextMenuButton", publicName: "enableContextMenuButton", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null }, deleteChildrenOnCollapse: { classPropertyName: "deleteChildrenOnCollapse", publicName: "deleteChildrenOnCollapse", isSignal: true, isRequired: false, transformFunction: null }, flatTree: { classPropertyName: "flatTree", publicName: "flatTree", isSignal: true, isRequired: false, transformFunction: null }, groupedList: { classPropertyName: "groupedList", publicName: "groupedList", isSignal: true, isRequired: false, transformFunction: null }, enableCheckbox: { classPropertyName: "enableCheckbox", publicName: "enableCheckbox", isSignal: true, isRequired: false, transformFunction: null }, enableOptionbox: { classPropertyName: "enableOptionbox", publicName: "enableOptionbox", isSignal: true, isRequired: false, transformFunction: null }, expandOnClick: { classPropertyName: "expandOnClick", publicName: "expandOnClick", isSignal: true, isRequired: false, transformFunction: null }, inheritChecked: { classPropertyName: "inheritChecked", publicName: "inheritChecked", isSignal: true, isRequired: false, transformFunction: null }, noActionsString: { classPropertyName: "noActionsString", publicName: "noActionsString", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemsVirtualizedChanged: "itemsVirtualizedChanged", treeItemFolderClicked: "treeItemFolderClicked", treeItemFolderStateChanged: "treeItemFolderStateChanged", treeItemClicked: "treeItemClicked", treeItemCheckboxClicked: "treeItemCheckboxClicked", loadChildren: "loadChildren", treeItemsSelected: "treeItemsSelected" }, host: { listeners: { "document:keyup.shift": "onKeyUpShift()", "document:keyup.control": "onKeyUpCtrl()", "document:keyup.meta": "onKeyUpMeta()", "document:mouseleave": "onMouseLeave()", "keydown": "handleKeydown($event)" } }, providers: [
|
|
2729
|
+
SiTreeViewConverterService,
|
|
2730
|
+
SiTreeViewItemHeightService,
|
|
2731
|
+
SiTreeViewService,
|
|
2732
|
+
SiTreeViewVirtualizationService
|
|
2733
|
+
], queries: [{ propertyName: "treeItemContentTemplate", first: true, predicate: SiTreeViewItemDirective, descendants: true, read: TemplateRef }, { propertyName: "templates", predicate: SiTreeViewItemTemplateDirective }, { propertyName: "nextItmes", predicate: SiTreeViewItemComponent, descendants: true }], viewQueries: [{ propertyName: "treeViewInnerElement", first: true, predicate: ["treeViewInner"], descendants: true, read: ElementRef, static: true }, { propertyName: "children", predicate: SiTreeViewItemComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (!flatTree() && expandCollapseAll()) {\n <div class=\"si-tree-view-expand-collapse-container p-4\">\n <button\n class=\"btn btn-sm btn-circle btn-tertiary\"\n type=\"button\"\n [title]=\"expandAllTooltip() | translate\"\n (click)=\"expandAll()\"\n >\n <span class=\"element-expand-all\"></span>\n </button>\n <button\n class=\"btn btn-sm btn-circle btn-tertiary ms-4\"\n type=\"button\"\n [title]=\"collapseAllTooltip() | translate\"\n (click)=\"collapseAll()\"\n >\n <span class=\"element-collapse-all\"></span>\n </button>\n </div>\n}\n@if (flatTree()) {\n <div class=\"si-tree-view-header\">\n <span\n class=\"si-tree-view-header-btn si-tree-view-header-root\"\n tabindex=\"0\"\n [class.disabled]=\"headerShowsRoot\"\n [ngClass]=\"computedIcons().headerHome\"\n (click)=\"onFlatTreeNavigateHome()\"\n (keydown.enter)=\"onFlatTreeNavigateHome()\"\n ></span>\n @if (lastBreadCrumbItem) {\n <span\n class=\"si-tree-view-header-btn\"\n tabindex=\"0\"\n [class.disabled]=\"headerShowsRoot\"\n [ngClass]=\"computedIcons().headerArrow\"\n (click)=\"onFlatTreeNavigateUp()\"\n (keydown.enter)=\"onFlatTreeNavigateUp()\"\n ></span>\n }\n @if (lastBreadCrumbItem) {\n <span class=\"text-center text-truncate\">{{ lastBreadCrumbItem.label | translate }}</span>\n }\n </div>\n}\n<div\n #treeViewInner\n cdkScrollable\n class=\"si-tree-view focus-inside\"\n role=\"tree\"\n [attr.aria-multiselectable]=\"!singleSelectMode()\"\n [attr.aria-label]=\"ariaLabel() ? (ariaLabel() | translate) : undefined\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [class.si-tree-horizontal-scroll]=\"horizontalScrolling()\"\n [class.si-tree-view-flat]=\"flatTree()\"\n [class.si-tree-expand-collapse]=\"!flatTree() && expandCollapseAll()\"\n>\n @if (isVirtualized()) {\n <div [class.w-100]=\"horizontalScrolling()\" [style.height]=\"heightBefore\"></div>\n }\n @if (itemsVirtualized) {\n <div class=\"si-tree-view-root-ul\">\n <ng-content select=\"[cdkDropList], [siTreeViewItem]\" />\n @if (!treeItemContentTemplate) {\n <si-tree-view-item *siTreeViewItem=\"let index = index; let treeItem = treeItem\" />\n }\n </div>\n }\n @if (isVirtualized()) {\n <div [class.w-100]=\"horizontalScrolling()\" [style.height]=\"heightAfter\"></div>\n }\n</div>\n", styles: [":host{--si-tree-view-background: var(--element-base-1);--si-tree-view-border-color: var(--element-ui-4);--si-tree-view-icon-size: 24px;--si-tree-view-padding-base-horizontal: 8px;--si-tree-view-padding-base-vertical: 8px;--si-tree-view-item-hover-color: var(--element-base-1-hover);--si-tree-view-item-select-color: var(--element-base-1-selected);--si-tree-view-item-line-height: 1.143;--si-tree-view-item-min-height: 40px;--si-tree-view-item-object-data-field-1-color: var(--element-text-secondary);--si-tree-view-item-object-data-h5-font-size: .875rem;--si-tree-view-item-object-data-h5-font-weight: normal}:host-context(.tree-sm){--si-tree-view-item-min-height: 32px;--si-tree-view-padding-base-vertical: 0px}:host-context(.tree-xs){--si-tree-view-item-min-height: 24px;--si-tree-view-padding-base-vertical: 0px}:host{display:flex;flex-direction:column;background-color:var(--si-tree-view-background)}.si-tree-view-header{padding:calc(var(--si-tree-view-padding-base-horizontal) / 2);border-block-end:1px solid var(--si-tree-view-border-color)}.si-tree-view-header>*{align-self:center}.si-tree-view-header-btn{cursor:pointer;margin-inline-end:calc(var(--si-tree-view-padding-base-horizontal) / 2);font-size:var(--si-tree-view-icon-size)}.si-tree-view-header-root{margin-inline-end:0}.si-tree-view{overflow:auto;flex:1 0 0;min-block-size:0}.si-tree-view.si-tree-horizontal-scroll{display:flex;flex-wrap:wrap;align-content:flex-start}.si-tree-view-root-ul{list-style:none;padding:0;margin:0;flex:1 1 auto}::ng-deep .si-tree-view-top-level-item{margin-block-start:8px}.si-tree-expand-collapse ::ng-deep .si-tree-view-top-level-item:first-child{margin-block-start:0}@supports (-webkit-touch-callout: none){.si-tree-horizontal-scroll{transform:translateZ(0)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: SiTranslateModule }, { kind: "pipe", type: i1.SiTranslatePipe, name: "translate" }, { kind: "component", type: SiTreeViewItemComponent, selector: "si-tree-view-item" }, { kind: "ngmodule", type: CdkScrollableModule }, { kind: "directive", type: i2.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: SiTreeViewItemDirective, selector: "[siTreeViewItem]" }] });
|
|
2734
|
+
}
|
|
2735
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewComponent, decorators: [{
|
|
2736
|
+
type: Component,
|
|
2737
|
+
args: [{ selector: 'si-tree-view', providers: [
|
|
2738
|
+
SiTreeViewConverterService,
|
|
2739
|
+
SiTreeViewItemHeightService,
|
|
2740
|
+
SiTreeViewService,
|
|
2741
|
+
SiTreeViewVirtualizationService
|
|
2742
|
+
], imports: [
|
|
2743
|
+
NgClass,
|
|
2744
|
+
SiTranslateModule,
|
|
2745
|
+
SiTreeViewItemComponent,
|
|
2746
|
+
CdkScrollableModule,
|
|
2747
|
+
SiTreeViewItemDirective
|
|
2748
|
+
], template: "@if (!flatTree() && expandCollapseAll()) {\n <div class=\"si-tree-view-expand-collapse-container p-4\">\n <button\n class=\"btn btn-sm btn-circle btn-tertiary\"\n type=\"button\"\n [title]=\"expandAllTooltip() | translate\"\n (click)=\"expandAll()\"\n >\n <span class=\"element-expand-all\"></span>\n </button>\n <button\n class=\"btn btn-sm btn-circle btn-tertiary ms-4\"\n type=\"button\"\n [title]=\"collapseAllTooltip() | translate\"\n (click)=\"collapseAll()\"\n >\n <span class=\"element-collapse-all\"></span>\n </button>\n </div>\n}\n@if (flatTree()) {\n <div class=\"si-tree-view-header\">\n <span\n class=\"si-tree-view-header-btn si-tree-view-header-root\"\n tabindex=\"0\"\n [class.disabled]=\"headerShowsRoot\"\n [ngClass]=\"computedIcons().headerHome\"\n (click)=\"onFlatTreeNavigateHome()\"\n (keydown.enter)=\"onFlatTreeNavigateHome()\"\n ></span>\n @if (lastBreadCrumbItem) {\n <span\n class=\"si-tree-view-header-btn\"\n tabindex=\"0\"\n [class.disabled]=\"headerShowsRoot\"\n [ngClass]=\"computedIcons().headerArrow\"\n (click)=\"onFlatTreeNavigateUp()\"\n (keydown.enter)=\"onFlatTreeNavigateUp()\"\n ></span>\n }\n @if (lastBreadCrumbItem) {\n <span class=\"text-center text-truncate\">{{ lastBreadCrumbItem.label | translate }}</span>\n }\n </div>\n}\n<div\n #treeViewInner\n cdkScrollable\n class=\"si-tree-view focus-inside\"\n role=\"tree\"\n [attr.aria-multiselectable]=\"!singleSelectMode()\"\n [attr.aria-label]=\"ariaLabel() ? (ariaLabel() | translate) : undefined\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [class.si-tree-horizontal-scroll]=\"horizontalScrolling()\"\n [class.si-tree-view-flat]=\"flatTree()\"\n [class.si-tree-expand-collapse]=\"!flatTree() && expandCollapseAll()\"\n>\n @if (isVirtualized()) {\n <div [class.w-100]=\"horizontalScrolling()\" [style.height]=\"heightBefore\"></div>\n }\n @if (itemsVirtualized) {\n <div class=\"si-tree-view-root-ul\">\n <ng-content select=\"[cdkDropList], [siTreeViewItem]\" />\n @if (!treeItemContentTemplate) {\n <si-tree-view-item *siTreeViewItem=\"let index = index; let treeItem = treeItem\" />\n }\n </div>\n }\n @if (isVirtualized()) {\n <div [class.w-100]=\"horizontalScrolling()\" [style.height]=\"heightAfter\"></div>\n }\n</div>\n", styles: [":host{--si-tree-view-background: var(--element-base-1);--si-tree-view-border-color: var(--element-ui-4);--si-tree-view-icon-size: 24px;--si-tree-view-padding-base-horizontal: 8px;--si-tree-view-padding-base-vertical: 8px;--si-tree-view-item-hover-color: var(--element-base-1-hover);--si-tree-view-item-select-color: var(--element-base-1-selected);--si-tree-view-item-line-height: 1.143;--si-tree-view-item-min-height: 40px;--si-tree-view-item-object-data-field-1-color: var(--element-text-secondary);--si-tree-view-item-object-data-h5-font-size: .875rem;--si-tree-view-item-object-data-h5-font-weight: normal}:host-context(.tree-sm){--si-tree-view-item-min-height: 32px;--si-tree-view-padding-base-vertical: 0px}:host-context(.tree-xs){--si-tree-view-item-min-height: 24px;--si-tree-view-padding-base-vertical: 0px}:host{display:flex;flex-direction:column;background-color:var(--si-tree-view-background)}.si-tree-view-header{padding:calc(var(--si-tree-view-padding-base-horizontal) / 2);border-block-end:1px solid var(--si-tree-view-border-color)}.si-tree-view-header>*{align-self:center}.si-tree-view-header-btn{cursor:pointer;margin-inline-end:calc(var(--si-tree-view-padding-base-horizontal) / 2);font-size:var(--si-tree-view-icon-size)}.si-tree-view-header-root{margin-inline-end:0}.si-tree-view{overflow:auto;flex:1 0 0;min-block-size:0}.si-tree-view.si-tree-horizontal-scroll{display:flex;flex-wrap:wrap;align-content:flex-start}.si-tree-view-root-ul{list-style:none;padding:0;margin:0;flex:1 1 auto}::ng-deep .si-tree-view-top-level-item{margin-block-start:8px}.si-tree-expand-collapse ::ng-deep .si-tree-view-top-level-item:first-child{margin-block-start:0}@supports (-webkit-touch-callout: none){.si-tree-horizontal-scroll{transform:translateZ(0)}}\n"] }]
|
|
2749
|
+
}], propDecorators: { templates: [{
|
|
2750
|
+
type: ContentChildren,
|
|
2751
|
+
args: [SiTreeViewItemTemplateDirective]
|
|
2752
|
+
}], children: [{
|
|
2753
|
+
type: ViewChildren,
|
|
2754
|
+
args: [SiTreeViewItemComponent]
|
|
2755
|
+
}], treeItemContentTemplate: [{
|
|
2756
|
+
type: ContentChild,
|
|
2757
|
+
args: [SiTreeViewItemDirective, { read: TemplateRef }]
|
|
2758
|
+
}], nextItmes: [{
|
|
2759
|
+
type: ContentChildren,
|
|
2760
|
+
args: [SiTreeViewItemComponent, { descendants: true }]
|
|
2761
|
+
}], onKeyUpShift: [{
|
|
2762
|
+
type: HostListener,
|
|
2763
|
+
args: ['document:keyup.shift']
|
|
2764
|
+
}], onKeyUpCtrl: [{
|
|
2765
|
+
type: HostListener,
|
|
2766
|
+
args: ['document:keyup.control']
|
|
2767
|
+
}], onKeyUpMeta: [{
|
|
2768
|
+
type: HostListener,
|
|
2769
|
+
args: ['document:keyup.meta']
|
|
2770
|
+
}], onMouseLeave: [{
|
|
2771
|
+
type: HostListener,
|
|
2772
|
+
args: ['document:mouseleave']
|
|
2773
|
+
}], handleKeydown: [{
|
|
2774
|
+
type: HostListener,
|
|
2775
|
+
args: ['keydown', ['$event']]
|
|
2776
|
+
}], treeViewInnerElement: [{
|
|
2777
|
+
type: ViewChild,
|
|
2778
|
+
args: ['treeViewInner', { read: ElementRef, static: true }]
|
|
2779
|
+
}] } });
|
|
2780
|
+
|
|
2781
|
+
/**
|
|
2782
|
+
* Copyright Siemens 2016 - 2025.
|
|
2783
|
+
* SPDX-License-Identifier: MIT
|
|
2784
|
+
*/
|
|
2785
|
+
class SiTreeViewModule {
|
|
2786
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
2787
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewModule, imports: [SiTreeViewComponent,
|
|
2788
|
+
SiTreeViewItemComponent,
|
|
2789
|
+
SiTreeViewItemDirective,
|
|
2790
|
+
SiTreeViewItemTemplateDirective], exports: [SiTreeViewComponent,
|
|
2791
|
+
SiTreeViewItemComponent,
|
|
2792
|
+
SiTreeViewItemDirective,
|
|
2793
|
+
SiTreeViewItemTemplateDirective] });
|
|
2794
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewModule, imports: [SiTreeViewComponent,
|
|
2795
|
+
SiTreeViewItemComponent] });
|
|
2796
|
+
}
|
|
2797
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTreeViewModule, decorators: [{
|
|
2798
|
+
type: NgModule,
|
|
2799
|
+
args: [{
|
|
2800
|
+
imports: [
|
|
2801
|
+
SiTreeViewComponent,
|
|
2802
|
+
SiTreeViewItemComponent,
|
|
2803
|
+
SiTreeViewItemDirective,
|
|
2804
|
+
SiTreeViewItemTemplateDirective
|
|
2805
|
+
],
|
|
2806
|
+
exports: [
|
|
2807
|
+
SiTreeViewComponent,
|
|
2808
|
+
SiTreeViewItemComponent,
|
|
2809
|
+
SiTreeViewItemDirective,
|
|
2810
|
+
SiTreeViewItemTemplateDirective
|
|
2811
|
+
]
|
|
2812
|
+
}]
|
|
2813
|
+
}] });
|
|
2814
|
+
|
|
2815
|
+
/**
|
|
2816
|
+
*
|
|
2817
|
+
* @param treeItems - TreeItem array which is used with the si-tree-view.
|
|
2818
|
+
* @param event - event object which is emitted by cdkDropListDropped.
|
|
2819
|
+
* @returns reordered TreeItems list.
|
|
2820
|
+
*/
|
|
2821
|
+
const reorderTreeItem = (treeItems, event) => {
|
|
2822
|
+
if (event.currentIndex === event.previousIndex) {
|
|
2823
|
+
return treeItems;
|
|
2824
|
+
}
|
|
2825
|
+
const targetIndex = event.currentIndex < event.previousIndex ? event.currentIndex - 1 : event.currentIndex;
|
|
2826
|
+
modifyTreeStructure(treeItems, event, treeItems, targetIndex);
|
|
2827
|
+
return treeItems;
|
|
2828
|
+
};
|
|
2829
|
+
/**
|
|
2830
|
+
*
|
|
2831
|
+
* @param sourceTreeItems - TreeItem array of the source tree from where item is being dragged.
|
|
2832
|
+
* @param targetTreeItems - TreeItem array of the target tree where item is being dropped.
|
|
2833
|
+
* @param event - event object which is emitted by cdkDropListDropped.
|
|
2834
|
+
* @param removeFromSource - whether to remove item from its source tree after moving to target.
|
|
2835
|
+
* @returns modified TreeItems list of source and target trees.
|
|
2836
|
+
*/
|
|
2837
|
+
const transferTreeItem = (sourceTreeItems, targetTreeItems, event, removeFromSource = false) => {
|
|
2838
|
+
modifyTreeStructure(sourceTreeItems, event, targetTreeItems, event.currentIndex - 1, removeFromSource);
|
|
2839
|
+
return {
|
|
2840
|
+
sourceTree: sourceTreeItems,
|
|
2841
|
+
targetTree: targetTreeItems
|
|
2842
|
+
};
|
|
2843
|
+
};
|
|
2844
|
+
/**
|
|
2845
|
+
*
|
|
2846
|
+
* @param sourceTree - TreeItems array from where item needs to be removed.
|
|
2847
|
+
* @param itemToRemove - TreeItem which needs to be removed.
|
|
2848
|
+
* @returns Updated TreeItems array.
|
|
2849
|
+
*/
|
|
2850
|
+
const removeItemFromTree = (sourceTree, itemToRemove) => {
|
|
2851
|
+
const sourceItem = findTreeItem(sourceTree, itemToRemove);
|
|
2852
|
+
const itemParent = sourceItem?.parent;
|
|
2853
|
+
if (!itemParent) {
|
|
2854
|
+
console.error('Item parent not found.');
|
|
2855
|
+
return sourceTree;
|
|
2856
|
+
}
|
|
2857
|
+
if (itemParent.children) {
|
|
2858
|
+
const itemIndex = itemParent.children.indexOf(itemToRemove);
|
|
2859
|
+
itemParent.children?.splice(itemIndex, 1);
|
|
2860
|
+
}
|
|
2861
|
+
return sourceTree;
|
|
2862
|
+
};
|
|
2863
|
+
const findTreeItem = (array, targetItem) => {
|
|
2864
|
+
for (const obj of array) {
|
|
2865
|
+
// Check if the current item reference is the same as the target object reference
|
|
2866
|
+
if (obj === targetItem) {
|
|
2867
|
+
return obj; // Found the item, return it
|
|
2868
|
+
}
|
|
2869
|
+
// If the current item has nested children, recursively search within them
|
|
2870
|
+
const key = 'children';
|
|
2871
|
+
if (Array.isArray(obj[key])) {
|
|
2872
|
+
const found = findTreeItem(obj[key], targetItem);
|
|
2873
|
+
if (found)
|
|
2874
|
+
return found; // If found in nested array, return it
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
return null; // Object not found
|
|
2878
|
+
};
|
|
2879
|
+
const modifyTreeStructure = (sourceItems, event, targetItems, targetIndex, removeFromSource = true) => {
|
|
2880
|
+
const sourceTreeItem = findTreeItem(sourceItems, event.previousContainer.data[event.previousIndex]);
|
|
2881
|
+
if (!sourceTreeItem) {
|
|
2882
|
+
console.error('Source tree item not found');
|
|
2883
|
+
return;
|
|
2884
|
+
}
|
|
2885
|
+
const sourceTreeItemCopy = structuredClone(sourceTreeItem);
|
|
2886
|
+
const targetTreeItem = findTreeItem(targetItems, event.container.data[targetIndex < 0 ? 0 : targetIndex]);
|
|
2887
|
+
if (!targetTreeItem) {
|
|
2888
|
+
console.error('Target tree item not found');
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
if (findTreeItem(sourceTreeItem.children, targetTreeItem)) {
|
|
2892
|
+
console.error('Cannot move parent into its own child');
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2895
|
+
const targetItemParent = targetTreeItem?.parent;
|
|
2896
|
+
if (targetIndex < 0) {
|
|
2897
|
+
sourceTreeItemCopy.parent = targetItemParent;
|
|
2898
|
+
sourceTreeItemCopy.level = targetItemParent?.level ? targetItemParent.level + 1 : 0;
|
|
2899
|
+
targetItemParent?.children?.splice(0, 0, sourceTreeItemCopy);
|
|
2900
|
+
}
|
|
2901
|
+
else if (targetTreeItem?.state === 'expanded') {
|
|
2902
|
+
sourceTreeItemCopy.parent = targetTreeItem;
|
|
2903
|
+
sourceTreeItemCopy.level = targetTreeItem.level ? targetTreeItem.level + 1 : 0;
|
|
2904
|
+
if (targetTreeItem.children?.length) {
|
|
2905
|
+
targetTreeItem.children = [sourceTreeItemCopy, ...targetTreeItem.children];
|
|
2906
|
+
}
|
|
2907
|
+
else {
|
|
2908
|
+
targetTreeItem.children = [sourceTreeItemCopy];
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
else {
|
|
2912
|
+
if (targetItemParent) {
|
|
2913
|
+
const targetItemIndex = targetItemParent.children?.indexOf(targetTreeItem) ?? -1;
|
|
2914
|
+
sourceTreeItemCopy.parent = targetItemParent;
|
|
2915
|
+
sourceTreeItemCopy.level = targetItemParent.level ? targetItemParent.level + 1 : 0;
|
|
2916
|
+
targetItemParent?.children?.splice(targetItemIndex + 1, 0, sourceTreeItemCopy);
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
const sourceTreeItemParent = sourceTreeItem.parent;
|
|
2920
|
+
if (removeFromSource && sourceTreeItemParent) {
|
|
2921
|
+
const sourceItemIndex = sourceTreeItemParent.children?.indexOf(sourceTreeItem) ?? -1;
|
|
2922
|
+
sourceTreeItemParent?.children?.splice(sourceItemIndex, 1);
|
|
2923
|
+
}
|
|
2924
|
+
};
|
|
2925
|
+
|
|
2926
|
+
/**
|
|
2927
|
+
* Copyright Siemens 2016 - 2025.
|
|
2928
|
+
* SPDX-License-Identifier: MIT
|
|
2929
|
+
*/
|
|
2930
|
+
|
|
2931
|
+
/**
|
|
2932
|
+
* Generated bundle index. Do not edit.
|
|
2933
|
+
*/
|
|
2934
|
+
|
|
2935
|
+
export { CheckboxClickEventArgs, ClickEventArgs, DEFAULT_CHILDREN_INDENTATION, DEFAULT_TREE_ICON_SET, FolderStateEventArgs, ItemsVirtualizedArgs, LoadChildrenEventArgs, ROOT_LEVEL, SiTreeViewComponent, SiTreeViewItemComponent, SiTreeViewItemDirective, SiTreeViewItemTemplateDirective, SiTreeViewModule, addChildItem, addChildItems, boxClicked, childrenLoaded, collapse, deleteItem, doFolderStateChange, enableCheckboxRecursive, enableOptionboxRecursive, expand, expandRecursive, hasChildren, initializeTreeItemsRecursive, parentCountRecursive, removeItemFromTree, removeUndefinedState, reorderTreeItem, resetActive, selectItemsBetween, selectRecursive, setActive, setBoxStateRecursive, setSelectable, setTreeItemDefaults, transferTreeItem };
|
|
2936
|
+
//# sourceMappingURL=siemens-element-ng-tree-view.mjs.map
|