@sdcorejs/angular 19.1.5 → 19.2.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/README.md +12 -4
- package/assets/scss/core/menu.scss +18 -0
- package/assets/scss/core/utilities/_misc.scss +15 -0
- package/assets/scss/sd-core.scss +1 -0
- package/components/anchor/src/components/anchor/anchor.component.d.ts +3 -1
- package/components/badge/src/badge.component.d.ts +1 -0
- package/components/ckeditor-styles/src/ckeditor-styles.component.d.ts +1 -1
- package/components/form-generic/src/components/form-builder/components/expression-builder/expression-builder.component.d.ts +2 -1
- package/components/form-generic/src/components/form-builder/form-builder.component.d.ts +3 -1
- package/components/form-generic/src/components/form-render/components/item/components/checkbox/checkbox.component.d.ts +34 -0
- package/components/form-generic/src/components/form-render/components/item/components/index.d.ts +1 -0
- package/components/form-generic/src/components/form-render/components/item/components/table/table.component.d.ts +6 -1
- package/components/form-generic/src/components/sd-feel-expression/sd-feel-expression.component.d.ts +1 -1
- package/components/form-generic/src/configurations/form.configuration.d.ts +1 -1
- package/components/form-generic/src/models/form-generic-component.model.d.ts +8 -8
- package/components/form-generic/src/models/form-generic-definition-selection.model.d.ts +5 -5
- package/components/form-generic/src/models/form-generic-expression.model.d.ts +12 -12
- package/components/form-generic/src/models/index.d.ts +1 -0
- package/components/form-generic/src/services/form-generic.service.d.ts +2 -2
- package/components/import-excel/src/import-excel.component.d.ts +1 -0
- package/components/index.d.ts +6 -1
- package/components/mini-editor/src/mini-editor.model.d.ts +1 -1
- package/components/modal/src/modal.component.d.ts +3 -2
- package/components/modal-resizable/src/modal-resizable.component.d.ts +92 -0
- package/components/modal-resizable/src/modal-resizable.registry.d.ts +22 -0
- package/components/org-chart/src/org-chart.component.d.ts +6 -0
- package/components/preview/src/preview-image/preview-image.component.d.ts +1 -0
- package/components/preview/src/preview-pdf/pdf-worker-inline.generated.d.ts +7 -0
- package/components/query-bar/src/components/actions-bar/actions-bar.component.d.ts +6 -2
- package/components/query-bar/src/components/build-chip/build-chip.component.d.ts +4 -1
- package/components/query-bar/src/components/chip-popover/chip-popover.component.d.ts +8 -0
- package/components/query-bar/src/components/field-picker/field-picker.component.d.ts +2 -0
- package/components/query-bar/src/components/inline-chip/inline-chip.component.d.ts +2 -0
- package/components/query-bar/src/components/inline-value-chip/inline-value-chip.component.d.ts +3 -3
- package/components/query-bar/src/components/saved-filters-menu/saved-filters-menu.component.d.ts +9 -4
- package/components/query-bar/src/query-bar.component.d.ts +32 -5
- package/components/query-bar/src/query-bar.model.d.ts +15 -12
- package/components/query-builder/src/query-builder.component.d.ts +76 -39
- package/components/query-builder/src/query-builder.model.d.ts +59 -52
- package/components/query-builder/src/query-builder.serializer.d.ts +15 -6
- package/components/section/src/section.component.d.ts +3 -0
- package/components/side-drawer/src/body-scroll-lock.service.d.ts +10 -0
- package/components/splitter/src/splitter-handle/splitter-handle.component.d.ts +1 -0
- package/components/tab-router/index.d.ts +2 -1
- package/components/tab-router/src/actions/tab-router.action.d.ts +2 -2
- package/components/tab-router/src/components/tab-router-item/tab-router-item.component.d.ts +2 -2
- package/components/tab-router/src/components/tab-router-nav/tab-router-nav.component.d.ts +3 -3
- package/components/tab-router/src/components/tab-router-outlet/tab-router-outlet.component.d.ts +3 -3
- package/components/tab-router/src/decorators/tab.decorator.d.ts +13 -1
- package/components/tab-router/src/events/tab-router.event.d.ts +3 -3
- package/components/tab-router/src/models/tab-router.model.d.ts +2 -2
- package/components/tab-router/src/pipes/tab-info.pipe.d.ts +2 -2
- package/components/tab-router/src/services/tab-router.service.d.ts +9 -9
- package/components/table/index.d.ts +1 -0
- package/components/table/src/components/config/config.component.d.ts +6 -1
- package/components/table/src/components/desktop-cell/view/view.component.d.ts +1 -0
- package/components/table/src/components/filter/external-filter/external-filter.component.d.ts +1 -1
- package/components/table/src/components/filter/mobile-filter/mobile-filter.component.d.ts +1 -1
- package/components/table/src/components/selector-action/action-filter.pipe.d.ts +8 -1
- package/components/table/src/components/selector-action/selector-action.component.d.ts +2 -0
- package/components/table/src/directives/index.d.ts +1 -0
- package/components/table/src/directives/sd-table-command-header-def.directive.d.ts +24 -0
- package/components/table/src/models/table-column.model.d.ts +30 -13
- package/components/table/src/models/table-item.model.d.ts +30 -1
- package/components/table/src/models/table-option-selector.model.d.ts +5 -4
- package/components/table/src/models/table-option.model.d.ts +12 -0
- package/components/table/src/pipes/sd-group.pipe.d.ts +6 -2
- package/components/table/src/services/table-export/table-export.service.d.ts +3 -1
- package/components/table/src/services/table-filter/table-filter.model.d.ts +15 -15
- package/components/table/src/services/table-filter/table-filter.service.d.ts +2 -2
- package/components/table/src/services/table-format/table-format.service.d.ts +1 -1
- package/components/table/src/services/table-selection/selection-action.util.d.ts +24 -0
- package/components/table/src/services/table-selection/table-selection.util.d.ts +31 -0
- package/components/table/src/services/tree/tree.util.d.ts +3 -2
- package/components/table/src/table.component.d.ts +52 -6
- package/components/tree/src/tree-item-def.directive.d.ts +1 -1
- package/components/tree/src/tree.component.d.ts +16 -4
- package/components/tree/src/tree.model.d.ts +31 -25
- package/components/upload-file/src/configurations/upload-file.configuration.d.ts +2 -2
- package/components/upload-file/src/upload-file.component.d.ts +4 -1
- package/configurations/src/sd-core.configuration.d.ts +1 -2
- package/fesm2022/sdcorejs-angular-components-anchor.mjs +36 -12
- package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-badge.mjs +15 -2
- package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-button.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs +1 -1
- package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-code-editor.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-code-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-data-state.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-data-state.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-editor.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs +324 -192
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-history.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-history.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs +13 -5
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-inform.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +164 -8
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal.mjs +30 -18
- package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs +60 -13
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-preview.mjs +58 -19
- package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs +192 -30
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs +187 -127
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-section.mjs +16 -2
- package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +83 -24
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-splitter.mjs +57 -21
- package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-stepper.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs +68 -20
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab.mjs +3 -2
- package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-table.mjs +556 -254
- package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tree.mjs +80 -17
- package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs +48 -13
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components.mjs +6 -1
- package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-configurations.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-directives.mjs +45 -8
- package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +40 -29
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +5 -5
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +67 -50
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip.mjs +57 -43
- package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs +233 -63
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date.mjs +208 -41
- package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs +130 -26
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs +39 -15
- package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs +16 -5
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs +24 -9
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input.mjs +58 -10
- package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-models.mjs +279 -6
- package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-radio.mjs +4 -4
- package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-select.mjs +135 -37
- package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-switch.mjs +18 -3
- package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs +51 -62
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-time-range.mjs +57 -12
- package/fesm2022/sdcorejs-angular-forms-time-range.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-time.mjs +16 -5
- package/fesm2022/sdcorejs-angular-forms-time.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-tree-select.mjs +100 -9
- package/fesm2022/sdcorejs-angular-forms-tree-select.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms.mjs +91 -46
- package/fesm2022/sdcorejs-angular-forms.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-handlers.mjs +18 -3
- package/fesm2022/sdcorejs-angular-handlers.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-i18n.mjs +510 -68
- package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-interceptors.mjs +87 -29
- package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-auth.mjs +25 -15
- package/fesm2022/sdcorejs-angular-modules-auth.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-icon.mjs +2 -2
- package/fesm2022/sdcorejs-angular-modules-icon.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +32 -3
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-layout.mjs +441 -135
- package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-permission.mjs +177 -40
- package/fesm2022/sdcorejs-angular-modules-permission.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-pipes.mjs +62 -28
- package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-api.mjs +123 -13
- package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-cache.mjs +53 -3
- package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-confirm.mjs +25 -73
- package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-excel.mjs +12 -10
- package/fesm2022/sdcorejs-angular-services-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-loading.mjs +75 -84
- package/fesm2022/sdcorejs-angular-services-loading.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-notify.mjs +46 -5
- package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-storage.mjs +4 -0
- package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services.mjs +0 -1
- package/fesm2022/sdcorejs-angular-services.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-utilities-extensions.mjs +225 -80
- package/fesm2022/sdcorejs-angular-utilities-extensions.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-utilities-models.mjs +1 -63
- package/fesm2022/sdcorejs-angular-utilities-models.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular.mjs +17 -10
- package/fesm2022/sdcorejs-angular.mjs.map +1 -1
- package/forms/autocomplete/src/autocomplete.component.d.ts +5 -2
- package/forms/chip-calendar/src/chip-calendar.component.d.ts +10 -0
- package/forms/date/src/date-input.util.d.ts +18 -0
- package/forms/date/src/date.component.d.ts +21 -3
- package/forms/date-range/src/date-range.component.d.ts +13 -2
- package/forms/datetime/src/datetime.component.d.ts +13 -2
- package/forms/entity-picker/src/entity-picker.component.d.ts +9 -3
- package/forms/input/src/input.component.d.ts +3 -0
- package/forms/input-color/src/input-color.component.d.ts +4 -0
- package/forms/input-number/src/input-number.component.d.ts +3 -0
- package/forms/models/index.d.ts +4 -0
- package/forms/models/src/sd-form-control-connector.d.ts +12 -0
- package/forms/models/src/sd-model-facing-control.d.ts +43 -0
- package/forms/models/src/sd-search.model.d.ts +1 -1
- package/forms/models/src/sd-selection-data.model.d.ts +1 -1
- package/forms/models/src/sd-strict-date-adapter.d.ts +26 -0
- package/forms/models/src/sd-temporal-transform.d.ts +31 -0
- package/forms/models/src/sd-timer-scope.d.ts +29 -0
- package/forms/select/src/select.component.d.ts +27 -4
- package/forms/src/forms.module.d.ts +22 -13
- package/forms/switch/src/switch.component.d.ts +5 -0
- package/forms/textarea/src/textarea.component.d.ts +5 -3
- package/forms/time-range/src/time-range.component.d.ts +22 -1
- package/forms/tree-select/src/tree-select.component.d.ts +36 -5
- package/i18n/src/en.d.ts +94 -10
- package/i18n/src/i18n.messages.d.ts +1 -1
- package/i18n/src/i18n.pipe.d.ts +3 -3
- package/i18n/src/i18n.service.d.ts +2 -1
- package/i18n/src/i18n.types.d.ts +0 -3
- package/interceptors/no-internet/no-internet.interceptor.d.ts +11 -1
- package/modules/auth/services/auth.model.d.ts +1 -1
- package/modules/keycloak/keycloak.service.d.ts +1 -0
- package/modules/layout/components/shared/menu-tree/menu-tree.component.d.ts +2 -0
- package/modules/layout/components/sidebar-mobile-v1/components/sidebar/sidebar.component.d.ts +3 -3
- package/modules/layout/components/sidebar-mobile-v1/main.component.d.ts +3 -3
- package/modules/layout/components/sidebar-mobile-v2/main.component.d.ts +3 -3
- package/modules/layout/components/sidebar-mobile-v3/main.component.d.ts +3 -3
- package/modules/layout/components/sidebar-v1/components/sidebar/sidebar.component.d.ts +8 -3
- package/modules/layout/components/sidebar-v1/main.component.d.ts +3 -3
- package/modules/layout/components/sidebar-v2/main.component.d.ts +3 -3
- package/modules/layout/components/sidebar-v3/main.component.d.ts +3 -3
- package/modules/layout/index.d.ts +1 -0
- package/modules/layout/modules/forbidden/pages/root/root.component.d.ts +5 -0
- package/modules/layout/modules/not-found/pages/root/root.component.d.ts +5 -0
- package/modules/layout/services/layout.service.d.ts +21 -0
- package/modules/layout/services/storage/storage.service.d.ts +52 -7
- package/modules/layout/utils/index.d.ts +1 -0
- package/modules/layout/utils/tab-name.util.d.ts +8 -0
- package/modules/permission/src/configurations/permission.configuration.d.ts +11 -0
- package/modules/permission/src/directives/permission.directive.d.ts +2 -1
- package/modules/permission/src/services/permission.service.d.ts +52 -1
- package/package.json +48 -33
- package/pipes/src/safe-html.pipe.d.ts +26 -4
- package/pipes/src/time-different.pipe.d.ts +1 -0
- package/public-api.d.ts +11 -10
- package/services/api/src/api-host.d.ts +15 -0
- package/services/api/src/api.model.d.ts +14 -0
- package/services/api/src/api.module.d.ts +6 -0
- package/services/cache/src/cache.model.d.ts +10 -0
- package/services/index.d.ts +0 -1
- package/services/notify/index.d.ts +1 -1
- package/utilities/extensions/index.d.ts +1 -5
- package/utilities/extensions/src/url-safety.d.ts +72 -0
- package/utilities/extensions/src/utility.extension.d.ts +9 -5
- package/utilities/models/index.d.ts +0 -10
- package/components/base/index.d.ts +0 -1
- package/components/base/src/base-secure.component.d.ts +0 -8
- package/components/document-builder/index.d.ts +0 -4
- package/components/document-builder/src/components/header-footer-builder/header-footer-builder.component.d.ts +0 -15
- package/components/document-builder/src/components/header-footer-builder/plugins/page-number.plugin.d.ts +0 -4
- package/components/document-builder/src/components/index.d.ts +0 -1
- package/components/document-builder/src/document-builder.component.d.ts +0 -53
- package/components/document-builder/src/document-builder.config.d.ts +0 -21
- package/components/document-builder/src/document-builder.model.d.ts +0 -41
- package/components/document-builder/src/document-builder.utils.d.ts +0 -10
- package/components/document-builder/src/plugins/block-space/block-space.plugin.d.ts +0 -9
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.d.ts +0 -44
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.model.d.ts +0 -57
- package/components/document-builder/src/plugins/heading/heading.plugin.d.ts +0 -5
- package/components/document-builder/src/plugins/highlight-range/highlight-range.plugin.d.ts +0 -4
- package/components/document-builder/src/plugins/image-custom/image-custom.plugin.d.ts +0 -31
- package/components/document-builder/src/plugins/image-upload/image-upload.plugin.d.ts +0 -5
- package/components/document-builder/src/plugins/index.d.ts +0 -11
- package/components/document-builder/src/plugins/page-orientation/page-orientation.plugin.d.ts +0 -24
- package/components/document-builder/src/plugins/paste-handler/filters/bookmark.d.ts +0 -14
- package/components/document-builder/src/plugins/paste-handler/filters/br.d.ts +0 -15
- package/components/document-builder/src/plugins/paste-handler/filters/image.d.ts +0 -25
- package/components/document-builder/src/plugins/paste-handler/filters/list.d.ts +0 -29
- package/components/document-builder/src/plugins/paste-handler/filters/parse.d.ts +0 -35
- package/components/document-builder/src/plugins/paste-handler/filters/removeboldwrapper.d.ts +0 -15
- package/components/document-builder/src/plugins/paste-handler/filters/removegooglesheetstag.d.ts +0 -15
- package/components/document-builder/src/plugins/paste-handler/filters/removeinvalidtablewidth.d.ts +0 -15
- package/components/document-builder/src/plugins/paste-handler/filters/removemsattributes.d.ts +0 -15
- package/components/document-builder/src/plugins/paste-handler/filters/removestyleblock.d.ts +0 -15
- package/components/document-builder/src/plugins/paste-handler/filters/removexmlns.d.ts +0 -15
- package/components/document-builder/src/plugins/paste-handler/filters/replacemsfootnotes.d.ts +0 -54
- package/components/document-builder/src/plugins/paste-handler/filters/space.d.ts +0 -27
- package/components/document-builder/src/plugins/paste-handler/filters/table.d.ts +0 -16
- package/components/document-builder/src/plugins/paste-handler/filters/utils.d.ts +0 -25
- package/components/document-builder/src/plugins/paste-handler/index.d.ts +0 -35
- package/components/document-builder/src/plugins/paste-handler/normalizers/googledocsnormalizer.d.ts +0 -31
- package/components/document-builder/src/plugins/paste-handler/normalizers/googlesheetsnormalizer.d.ts +0 -31
- package/components/document-builder/src/plugins/paste-handler/normalizers/mswordnormalizer.d.ts +0 -29
- package/components/document-builder/src/plugins/paste-handler/types.d.ts +0 -30
- package/components/document-builder/src/plugins/table-custom/index.d.ts +0 -34
- package/components/document-builder/src/plugins/variable/variable.plugin.d.ts +0 -51
- package/components/table/src/pipes/selection-visible-select-all.pipe.d.ts +0 -9
- package/fesm2022/sdcorejs-angular-components-base.mjs +0 -23
- package/fesm2022/sdcorejs-angular-components-base.mjs.map +0 -1
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs +0 -5038
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +0 -1
- package/fesm2022/sdcorejs-angular-models.mjs +0 -6
- package/fesm2022/sdcorejs-angular-models.mjs.map +0 -1
- package/fesm2022/sdcorejs-angular-services-docx.mjs +0 -291
- package/fesm2022/sdcorejs-angular-services-docx.mjs.map +0 -1
- package/fesm2022/sdcorejs-angular-services-license.mjs +0 -97
- package/fesm2022/sdcorejs-angular-services-license.mjs.map +0 -1
- package/models/index.d.ts +0 -1
- package/models/src/language.model.d.ts +0 -2
- package/services/docx/index.d.ts +0 -1
- package/services/docx/src/lib/docx.model.d.ts +0 -9
- package/services/docx/src/lib/docx.service.d.ts +0 -14
- package/services/docx/src/lib/pandoc-core.d.ts +0 -11
- package/services/docx/src/public-api.d.ts +0 -2
- package/services/license/index.d.ts +0 -1
- package/services/license/src/license.service.d.ts +0 -9
- package/utilities/extensions/src/array.extension.d.ts +0 -1
- package/utilities/extensions/src/color.extension.d.ts +0 -5
- package/utilities/extensions/src/date.extension.d.ts +0 -1
- package/utilities/extensions/src/number.extension.d.ts +0 -1
- package/utilities/extensions/src/string.extension.d.ts +0 -50
- package/utilities/models/src/color.model.d.ts +0 -4
- package/utilities/models/src/empty.model.d.ts +0 -4
- package/utilities/models/src/filter.model.d.ts +0 -12
- package/utilities/models/src/maybe-async.model.d.ts +0 -10
- package/utilities/models/src/nested-key-of.model.d.ts +0 -4
- package/utilities/models/src/operator.model.d.ts +0 -13
- package/utilities/models/src/order.model.d.ts +0 -4
- package/utilities/models/src/paging.model.d.ts +0 -8
- package/utilities/models/src/pattern.model.d.ts +0 -21
- package/utilities/models/src/size.model.d.ts +0 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { inject, DestroyRef, PLATFORM_ID,
|
|
3
|
+
import { inject, DestroyRef, PLATFORM_ID, Injectable } from '@angular/core';
|
|
4
4
|
|
|
5
5
|
var _a;
|
|
6
6
|
const SD_LOADING_STYLE_ATTRIBUTE = 'data-sd-loading-styles';
|
|
@@ -38,10 +38,18 @@ const CLOSED_LOADING_REF = Object.freeze({
|
|
|
38
38
|
// A closed ref deliberately has no work to release.
|
|
39
39
|
},
|
|
40
40
|
});
|
|
41
|
+
/*
|
|
42
|
+
* why: service này cố tình KHÔNG dùng Renderer2. Khi app bật animations, `RendererFactory2` trả về
|
|
43
|
+
* `AnimationRendererFactory` và `Renderer2.removeChild()` chỉ đẩy element vào hàng đợi
|
|
44
|
+
* `collectedLeaveElements` của animation engine — DOM chỉ thật sự bị gỡ ở lần flush kế tiếp (sau một
|
|
45
|
+
* chu kỳ change detection). Overlay và `style[data-sd-loading-styles]` ở đây là DOM ngoài view, được
|
|
46
|
+
* gỡ lúc destroy injector hoặc từ ngữ cảnh async ngoài Angular, tức không còn flush nào chạy sau đó →
|
|
47
|
+
* node nằm lại trong document vĩnh viễn (overlay z-index 99999 khoá cả trang). Ghi DOM trực tiếp trên
|
|
48
|
+
* `DOCUMENT` giữ append/remove đối xứng và đồng bộ; nhánh SSR đã được `isPlatformBrowser` chặn sẵn.
|
|
49
|
+
*/
|
|
41
50
|
class SdLoadingService {
|
|
42
51
|
static documentRecords = new WeakMap();
|
|
43
52
|
#document;
|
|
44
|
-
#renderer;
|
|
45
53
|
#isBrowser;
|
|
46
54
|
#destroyRef = inject(DestroyRef);
|
|
47
55
|
#handleQueue = [];
|
|
@@ -50,20 +58,17 @@ class SdLoadingService {
|
|
|
50
58
|
constructor() {
|
|
51
59
|
this.#document = inject(DOCUMENT);
|
|
52
60
|
this.#isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
53
|
-
const rendererFactory = inject(RendererFactory2);
|
|
54
|
-
this.#renderer = this.#isBrowser ? rendererFactory.createRenderer(null, null) : null;
|
|
55
61
|
this.#destroyRef.onDestroy(() => this.#destroy());
|
|
56
62
|
}
|
|
57
63
|
/** Starts loading for every current selector match and returns ownership of those exact hosts. */
|
|
58
64
|
start = (selector = 'body') => {
|
|
59
|
-
|
|
60
|
-
if (this.#destroyed || !this.#isBrowser || !renderer)
|
|
65
|
+
if (this.#destroyed || !this.#isBrowser)
|
|
61
66
|
return CLOSED_LOADING_REF;
|
|
62
67
|
const hosts = Array.from(this.#document.querySelectorAll(selector));
|
|
63
68
|
if (hosts.length === 0)
|
|
64
69
|
return CLOSED_LOADING_REF;
|
|
65
70
|
const documentRecord = this.#getOrCreateDocumentRecord();
|
|
66
|
-
this.#ensureStyles(documentRecord
|
|
71
|
+
this.#ensureStyles(documentRecord);
|
|
67
72
|
const state = { selector, contributions: [], closed: false };
|
|
68
73
|
for (const host of hosts) {
|
|
69
74
|
const contribution = {
|
|
@@ -73,14 +78,14 @@ class SdLoadingService {
|
|
|
73
78
|
released: false,
|
|
74
79
|
};
|
|
75
80
|
state.contributions.push(contribution);
|
|
76
|
-
this.#acquireHost(documentRecord, contribution
|
|
81
|
+
this.#acquireHost(documentRecord, contribution);
|
|
77
82
|
}
|
|
78
83
|
this.#handleQueue.push(state);
|
|
79
84
|
return {
|
|
80
85
|
get closed() {
|
|
81
86
|
return state.closed;
|
|
82
87
|
},
|
|
83
|
-
close: () => this.#closeHandle(state
|
|
88
|
+
close: () => this.#closeHandle(state),
|
|
84
89
|
};
|
|
85
90
|
};
|
|
86
91
|
/** Returns the first matched globally loading host, `false` for idle matches, or `null` when unavailable. */
|
|
@@ -100,12 +105,11 @@ class SdLoadingService {
|
|
|
100
105
|
};
|
|
101
106
|
/** Releases the oldest exact-selector start, with a current-host fallback for legacy cross-selector calls. */
|
|
102
107
|
stop = (selector = 'body') => {
|
|
103
|
-
|
|
104
|
-
if (this.#destroyed || !this.#isBrowser || !renderer)
|
|
108
|
+
if (this.#destroyed || !this.#isBrowser)
|
|
105
109
|
return;
|
|
106
110
|
const exactHandle = this.#handleQueue.find(state => !state.closed && state.selector === selector);
|
|
107
111
|
if (exactHandle) {
|
|
108
|
-
this.#closeHandle(exactHandle
|
|
112
|
+
this.#closeHandle(exactHandle);
|
|
109
113
|
return;
|
|
110
114
|
}
|
|
111
115
|
const documentRecord = _a.documentRecords.get(this.#document);
|
|
@@ -116,7 +120,7 @@ class SdLoadingService {
|
|
|
116
120
|
.get(host)
|
|
117
121
|
?.contributions.find(candidate => !candidate.released && candidate.service === this);
|
|
118
122
|
if (contribution)
|
|
119
|
-
this.#releaseContribution(documentRecord, contribution
|
|
123
|
+
this.#releaseContribution(documentRecord, contribution);
|
|
120
124
|
}
|
|
121
125
|
};
|
|
122
126
|
/** Runs a task inside a loading lifetime and always releases it without replacing the task result or error. */
|
|
@@ -142,37 +146,34 @@ class SdLoadingService {
|
|
|
142
146
|
}
|
|
143
147
|
return record;
|
|
144
148
|
}
|
|
145
|
-
#acquireHost(documentRecord, contribution
|
|
149
|
+
#acquireHost(documentRecord, contribution) {
|
|
146
150
|
const host = contribution.host;
|
|
147
151
|
const existing = documentRecord.hostStates.get(host);
|
|
148
152
|
if (existing) {
|
|
149
|
-
this.#repairOverlay(host, existing
|
|
153
|
+
this.#repairOverlay(host, existing);
|
|
150
154
|
existing.count += 1;
|
|
151
155
|
existing.contributions.push(contribution);
|
|
152
156
|
return;
|
|
153
157
|
}
|
|
154
158
|
const state = {
|
|
155
|
-
overlay: this.#createOverlay(
|
|
159
|
+
overlay: this.#createOverlay(),
|
|
156
160
|
previousAriaBusy: host.getAttribute('aria-busy'),
|
|
157
161
|
contributions: [contribution],
|
|
158
162
|
count: 1,
|
|
159
163
|
};
|
|
160
|
-
|
|
161
|
-
|
|
164
|
+
host.setAttribute('aria-busy', 'true');
|
|
165
|
+
host.appendChild(state.overlay);
|
|
162
166
|
documentRecord.hostStates.set(host, state);
|
|
163
167
|
documentRecord.liveHosts.add(host);
|
|
164
168
|
}
|
|
165
|
-
#repairOverlay(host, state
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
renderer.removeChild(currentParent, state.overlay);
|
|
170
|
-
renderer.appendChild(host, state.overlay);
|
|
171
|
-
}
|
|
169
|
+
#repairOverlay(host, state) {
|
|
170
|
+
// why: appendChild tự động rút overlay khỏi parent cũ, nên không cần removeChild riêng.
|
|
171
|
+
if (state.overlay.parentNode !== host)
|
|
172
|
+
host.appendChild(state.overlay);
|
|
172
173
|
if (host.getAttribute('aria-busy') !== 'true')
|
|
173
|
-
|
|
174
|
+
host.setAttribute('aria-busy', 'true');
|
|
174
175
|
}
|
|
175
|
-
#releaseContribution(documentRecord, contribution
|
|
176
|
+
#releaseContribution(documentRecord, contribution) {
|
|
176
177
|
if (contribution.released)
|
|
177
178
|
return;
|
|
178
179
|
contribution.released = true;
|
|
@@ -183,25 +184,23 @@ class SdLoadingService {
|
|
|
183
184
|
state.contributions.splice(contributionIndex, 1);
|
|
184
185
|
state.count -= 1;
|
|
185
186
|
if (state.count <= 0)
|
|
186
|
-
this.#removeHost(documentRecord, contribution.host, state
|
|
187
|
+
this.#removeHost(documentRecord, contribution.host, state);
|
|
187
188
|
}
|
|
188
189
|
contribution.service.#closeOwnerWhenReleased(contribution.owner);
|
|
189
190
|
}
|
|
190
|
-
#removeHost(documentRecord, host, state
|
|
191
|
-
|
|
192
|
-
if (parent)
|
|
193
|
-
renderer.removeChild(parent, state.overlay);
|
|
191
|
+
#removeHost(documentRecord, host, state) {
|
|
192
|
+
state.overlay.remove();
|
|
194
193
|
if (host.getAttribute('aria-busy') === 'true') {
|
|
195
194
|
if (state.previousAriaBusy === null)
|
|
196
|
-
|
|
195
|
+
host.removeAttribute('aria-busy');
|
|
197
196
|
else
|
|
198
|
-
|
|
197
|
+
host.setAttribute('aria-busy', state.previousAriaBusy);
|
|
199
198
|
}
|
|
200
199
|
documentRecord.hostStates.delete(host);
|
|
201
200
|
documentRecord.liveHosts.delete(host);
|
|
202
201
|
this.#deleteDocumentRecordWhenEmpty(documentRecord);
|
|
203
202
|
}
|
|
204
|
-
#closeHandle(state
|
|
203
|
+
#closeHandle(state) {
|
|
205
204
|
if (state.closed)
|
|
206
205
|
return;
|
|
207
206
|
state.closed = true;
|
|
@@ -209,7 +208,7 @@ class SdLoadingService {
|
|
|
209
208
|
const documentRecord = _a.documentRecords.get(this.#document);
|
|
210
209
|
if (documentRecord) {
|
|
211
210
|
for (const contribution of [...state.contributions]) {
|
|
212
|
-
this.#releaseContribution(documentRecord, contribution
|
|
211
|
+
this.#releaseContribution(documentRecord, contribution);
|
|
213
212
|
}
|
|
214
213
|
}
|
|
215
214
|
else {
|
|
@@ -230,32 +229,32 @@ class SdLoadingService {
|
|
|
230
229
|
if (handleIndex >= 0)
|
|
231
230
|
this.#handleQueue.splice(handleIndex, 1);
|
|
232
231
|
}
|
|
233
|
-
#createOverlay(
|
|
234
|
-
const container =
|
|
235
|
-
const spinner =
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
232
|
+
#createOverlay() {
|
|
233
|
+
const container = this.#document.createElement('div');
|
|
234
|
+
const spinner = this.#document.createElement('div');
|
|
235
|
+
container.classList.add('sd-loading');
|
|
236
|
+
container.setAttribute('role', 'status');
|
|
237
|
+
container.setAttribute('aria-live', 'polite');
|
|
238
|
+
container.setAttribute('aria-label', 'Loading');
|
|
239
|
+
spinner.classList.add('sd-loading-spinner');
|
|
240
|
+
spinner.setAttribute('aria-hidden', 'true');
|
|
241
|
+
container.appendChild(spinner);
|
|
243
242
|
return container;
|
|
244
243
|
}
|
|
245
|
-
#ensureStyles(documentRecord
|
|
244
|
+
#ensureStyles(documentRecord) {
|
|
246
245
|
let record = documentRecord.style;
|
|
247
246
|
if (record && !this.#isCurrentStyle(record.element)) {
|
|
248
247
|
const owners = record.owners;
|
|
249
|
-
this.#detachOwnedStyleContent(record
|
|
250
|
-
record = this.#createStyleRecord(
|
|
248
|
+
this.#detachOwnedStyleContent(record);
|
|
249
|
+
record = this.#createStyleRecord(owners);
|
|
251
250
|
documentRecord.style = record;
|
|
252
251
|
}
|
|
253
252
|
else if (!record) {
|
|
254
|
-
record = this.#createStyleRecord(
|
|
253
|
+
record = this.#createStyleRecord(new Set());
|
|
255
254
|
documentRecord.style = record;
|
|
256
255
|
}
|
|
257
256
|
else {
|
|
258
|
-
this.#ensureRequiredStyleText(record
|
|
257
|
+
this.#ensureRequiredStyleText(record);
|
|
259
258
|
}
|
|
260
259
|
record.owners.add(this);
|
|
261
260
|
this.#styleRegistered = true;
|
|
@@ -263,7 +262,7 @@ class SdLoadingService {
|
|
|
263
262
|
#isCurrentStyle(element) {
|
|
264
263
|
return element.isConnected && element.parentNode === this.#document.head && element.hasAttribute(SD_LOADING_STYLE_ATTRIBUTE);
|
|
265
264
|
}
|
|
266
|
-
#createStyleRecord(
|
|
265
|
+
#createStyleRecord(owners) {
|
|
267
266
|
const existing = this.#document.head.querySelector(`style[${SD_LOADING_STYLE_ATTRIBUTE}]`);
|
|
268
267
|
if (existing) {
|
|
269
268
|
const record = {
|
|
@@ -272,17 +271,17 @@ class SdLoadingService {
|
|
|
272
271
|
owners,
|
|
273
272
|
ownedText: null,
|
|
274
273
|
};
|
|
275
|
-
this.#ensureRequiredStyleText(record
|
|
274
|
+
this.#ensureRequiredStyleText(record);
|
|
276
275
|
return record;
|
|
277
276
|
}
|
|
278
|
-
const style =
|
|
279
|
-
const ownedText =
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
277
|
+
const style = this.#document.createElement('style');
|
|
278
|
+
const ownedText = this.#document.createTextNode(SD_LOADING_STYLES);
|
|
279
|
+
style.setAttribute(SD_LOADING_STYLE_ATTRIBUTE, '');
|
|
280
|
+
style.appendChild(ownedText);
|
|
281
|
+
this.#document.head.appendChild(style);
|
|
283
282
|
return { element: style, libraryOwned: true, owners, ownedText };
|
|
284
283
|
}
|
|
285
|
-
#ensureRequiredStyleText(record
|
|
284
|
+
#ensureRequiredStyleText(record) {
|
|
286
285
|
const currentText = record.element.textContent ?? '';
|
|
287
286
|
const hasRequiredRules = currentText.includes('.sd-loading {') &&
|
|
288
287
|
currentText.includes('.sd-loading-spinner') &&
|
|
@@ -292,42 +291,34 @@ class SdLoadingService {
|
|
|
292
291
|
if (record.ownedText && record.ownedText.parentNode !== record.element)
|
|
293
292
|
record.ownedText = null;
|
|
294
293
|
if (!record.ownedText) {
|
|
295
|
-
record.ownedText =
|
|
296
|
-
|
|
294
|
+
record.ownedText = this.#document.createTextNode(SD_LOADING_STYLES);
|
|
295
|
+
record.element.appendChild(record.ownedText);
|
|
297
296
|
}
|
|
298
297
|
}
|
|
299
|
-
#detachOwnedStyleContent(record
|
|
300
|
-
if (record.libraryOwned)
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
else if (record.ownedText) {
|
|
306
|
-
const textParent = record.ownedText.parentNode;
|
|
307
|
-
if (textParent)
|
|
308
|
-
renderer.removeChild(textParent, record.ownedText);
|
|
309
|
-
}
|
|
298
|
+
#detachOwnedStyleContent(record) {
|
|
299
|
+
if (record.libraryOwned)
|
|
300
|
+
record.element.remove();
|
|
301
|
+
else
|
|
302
|
+
record.ownedText?.remove();
|
|
310
303
|
record.ownedText = null;
|
|
311
304
|
}
|
|
312
305
|
#destroy() {
|
|
313
306
|
if (this.#destroyed)
|
|
314
307
|
return;
|
|
315
308
|
this.#destroyed = true;
|
|
316
|
-
|
|
317
|
-
if (renderer) {
|
|
309
|
+
if (this.#isBrowser) {
|
|
318
310
|
for (const state of [...this.#handleQueue])
|
|
319
|
-
this.#closeHandle(state
|
|
320
|
-
this.#unregisterStyles(
|
|
311
|
+
this.#closeHandle(state);
|
|
312
|
+
this.#unregisterStyles();
|
|
313
|
+
return;
|
|
321
314
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
state.contributions.length = 0;
|
|
326
|
-
}
|
|
327
|
-
this.#handleQueue.length = 0;
|
|
315
|
+
for (const state of this.#handleQueue) {
|
|
316
|
+
state.closed = true;
|
|
317
|
+
state.contributions.length = 0;
|
|
328
318
|
}
|
|
319
|
+
this.#handleQueue.length = 0;
|
|
329
320
|
}
|
|
330
|
-
#unregisterStyles(
|
|
321
|
+
#unregisterStyles() {
|
|
331
322
|
if (!this.#styleRegistered)
|
|
332
323
|
return;
|
|
333
324
|
this.#styleRegistered = false;
|
|
@@ -337,7 +328,7 @@ class SdLoadingService {
|
|
|
337
328
|
return;
|
|
338
329
|
record.owners.delete(this);
|
|
339
330
|
if (record.owners.size === 0) {
|
|
340
|
-
this.#detachOwnedStyleContent(record
|
|
331
|
+
this.#detachOwnedStyleContent(record);
|
|
341
332
|
documentRecord.style = undefined;
|
|
342
333
|
}
|
|
343
334
|
this.#deleteDocumentRecordWhenEmpty(documentRecord);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdcorejs-angular-services-loading.mjs","sources":["../../../projects/sdcorejs-angular/services/loading/src/loading.service.ts","../../../projects/sdcorejs-angular/services/loading/sdcorejs-angular-services-loading.ts"],"sourcesContent":["import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, Injectable, PLATFORM_ID, Renderer2, RendererFactory2, inject } from '@angular/core';\n\nexport interface SdLoadingRef {\n readonly closed: boolean;\n close(): void;\n}\n\ninterface SdLoadingDocumentRecord {\n readonly hostStates: WeakMap<Element, SdLoadingHostState>;\n readonly liveHosts: Set<Element>;\n style: SdLoadingStyleRecord | undefined;\n}\n\ninterface SdLoadingHostState {\n readonly overlay: HTMLElement;\n readonly previousAriaBusy: string | null;\n readonly contributions: SdLoadingContribution[];\n count: number;\n}\n\ninterface SdLoadingHandleState {\n readonly selector: string;\n readonly contributions: SdLoadingContribution[];\n closed: boolean;\n}\n\ninterface SdLoadingContribution {\n readonly host: Element;\n readonly owner: SdLoadingHandleState;\n readonly service: SdLoadingService;\n released: boolean;\n}\n\ninterface SdLoadingStyleRecord {\n readonly element: HTMLStyleElement;\n readonly libraryOwned: boolean;\n readonly owners: Set<SdLoadingService>;\n ownedText: Text | null;\n}\n\nconst SD_LOADING_STYLE_ATTRIBUTE = 'data-sd-loading-styles';\nconst SD_LOADING_STYLES = `\n.sd-loading {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n opacity: 0.6;\n background: #fff;\n z-index: 99999;\n}\n\n.sd-loading-spinner {\n position: absolute;\n top: calc(50% - 2.5rem);\n left: calc(50% - 2.5rem);\n width: 5rem;\n height: 5rem;\n border: 0.5rem solid var(--sd-primary);\n border-top-color: var(--sd-border);\n border-radius: 50%;\n animation: sd-loading-spin 1s linear infinite;\n}\n\n@keyframes sd-loading-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n`;\n\nconst CLOSED_LOADING_REF: SdLoadingRef = Object.freeze({\n closed: true,\n close(): void {\n // A closed ref deliberately has no work to release.\n },\n});\n\n@Injectable({\n providedIn: 'root',\n})\nexport class SdLoadingService {\n private static readonly documentRecords = new WeakMap<Document, SdLoadingDocumentRecord>();\n\n readonly #document: Document;\n readonly #renderer: Renderer2 | null;\n readonly #isBrowser: boolean;\n readonly #destroyRef = inject(DestroyRef);\n readonly #handleQueue: SdLoadingHandleState[] = [];\n\n #styleRegistered = false;\n #destroyed = false;\n\n /** Inserted by Angular inject() migration for backwards compatibility. */\n constructor(...args: unknown[]);\n constructor() {\n this.#document = inject(DOCUMENT);\n this.#isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n const rendererFactory = inject(RendererFactory2);\n this.#renderer = this.#isBrowser ? rendererFactory.createRenderer(null, null) : null;\n this.#destroyRef.onDestroy(() => this.#destroy());\n }\n\n /** Starts loading for every current selector match and returns ownership of those exact hosts. */\n start = (selector = 'body'): SdLoadingRef => {\n const renderer = this.#renderer;\n if (this.#destroyed || !this.#isBrowser || !renderer) return CLOSED_LOADING_REF;\n\n const hosts = Array.from(this.#document.querySelectorAll(selector));\n if (hosts.length === 0) return CLOSED_LOADING_REF;\n\n const documentRecord = this.#getOrCreateDocumentRecord();\n this.#ensureStyles(documentRecord, renderer);\n const state: SdLoadingHandleState = { selector, contributions: [], closed: false };\n for (const host of hosts) {\n const contribution: SdLoadingContribution = {\n host,\n owner: state,\n service: this,\n released: false,\n };\n state.contributions.push(contribution);\n this.#acquireHost(documentRecord, contribution, renderer);\n }\n this.#handleQueue.push(state);\n\n return {\n get closed(): boolean {\n return state.closed;\n },\n close: () => this.#closeHandle(state, renderer),\n };\n };\n\n /** Returns the first matched globally loading host, `false` for idle matches, or `null` when unavailable. */\n isLoading = (selector = 'body'): Element | false | null => {\n if (this.#destroyed || !this.#isBrowser) return null;\n\n const hosts = this.#document.querySelectorAll(selector);\n if (hosts.length === 0) return null;\n\n const documentRecord = SdLoadingService.documentRecords.get(this.#document);\n for (const host of Array.from(hosts)) {\n const state = documentRecord?.hostStates.get(host);\n if (state && state.count > 0 && state.overlay.parentNode === host) return host;\n }\n return false;\n };\n\n /** Releases the oldest exact-selector start, with a current-host fallback for legacy cross-selector calls. */\n stop = (selector = 'body'): void => {\n const renderer = this.#renderer;\n if (this.#destroyed || !this.#isBrowser || !renderer) return;\n\n const exactHandle = this.#handleQueue.find(state => !state.closed && state.selector === selector);\n if (exactHandle) {\n this.#closeHandle(exactHandle, renderer);\n return;\n }\n\n const documentRecord = SdLoadingService.documentRecords.get(this.#document);\n if (!documentRecord) return;\n\n for (const host of Array.from(this.#document.querySelectorAll(selector))) {\n const contribution = documentRecord.hostStates\n .get(host)\n ?.contributions.find(candidate => !candidate.released && candidate.service === this);\n if (contribution) this.#releaseContribution(documentRecord, contribution, renderer);\n }\n };\n\n run<T>(task: () => T | PromiseLike<T>, selector?: string): Promise<T>;\n run<T>(task: PromiseLike<T>, selector?: string): Promise<T>;\n /** Runs a task inside a loading lifetime and always releases it without replacing the task result or error. */\n async run<T>(task: (() => T | PromiseLike<T>) | PromiseLike<T>, selector = 'body'): Promise<T> {\n const ref = this.start(selector);\n try {\n const result = typeof task === 'function' ? task() : task;\n return await result;\n } finally {\n ref.close();\n }\n }\n\n #getOrCreateDocumentRecord(): SdLoadingDocumentRecord {\n let record = SdLoadingService.documentRecords.get(this.#document);\n if (!record) {\n record = {\n hostStates: new WeakMap<Element, SdLoadingHostState>(),\n liveHosts: new Set<Element>(),\n style: undefined,\n };\n SdLoadingService.documentRecords.set(this.#document, record);\n }\n return record;\n }\n\n #acquireHost(documentRecord: SdLoadingDocumentRecord, contribution: SdLoadingContribution, renderer: Renderer2): void {\n const host = contribution.host;\n const existing = documentRecord.hostStates.get(host);\n if (existing) {\n this.#repairOverlay(host, existing, renderer);\n existing.count += 1;\n existing.contributions.push(contribution);\n return;\n }\n\n const state: SdLoadingHostState = {\n overlay: this.#createOverlay(renderer),\n previousAriaBusy: host.getAttribute('aria-busy'),\n contributions: [contribution],\n count: 1,\n };\n renderer.setAttribute(host, 'aria-busy', 'true');\n renderer.appendChild(host, state.overlay);\n documentRecord.hostStates.set(host, state);\n documentRecord.liveHosts.add(host);\n }\n\n #repairOverlay(host: Element, state: SdLoadingHostState, renderer: Renderer2): void {\n const currentParent = state.overlay.parentNode;\n if (currentParent !== host) {\n if (currentParent) renderer.removeChild(currentParent, state.overlay);\n renderer.appendChild(host, state.overlay);\n }\n if (host.getAttribute('aria-busy') !== 'true') renderer.setAttribute(host, 'aria-busy', 'true');\n }\n\n #releaseContribution(documentRecord: SdLoadingDocumentRecord, contribution: SdLoadingContribution, renderer: Renderer2): void {\n if (contribution.released) return;\n contribution.released = true;\n\n const state = documentRecord.hostStates.get(contribution.host);\n if (state) {\n const contributionIndex = state.contributions.indexOf(contribution);\n if (contributionIndex >= 0) state.contributions.splice(contributionIndex, 1);\n state.count -= 1;\n\n if (state.count <= 0) this.#removeHost(documentRecord, contribution.host, state, renderer);\n }\n\n contribution.service.#closeOwnerWhenReleased(contribution.owner);\n }\n\n #removeHost(documentRecord: SdLoadingDocumentRecord, host: Element, state: SdLoadingHostState, renderer: Renderer2): void {\n const parent = state.overlay.parentNode;\n if (parent) renderer.removeChild(parent, state.overlay);\n\n if (host.getAttribute('aria-busy') === 'true') {\n if (state.previousAriaBusy === null) renderer.removeAttribute(host, 'aria-busy');\n else renderer.setAttribute(host, 'aria-busy', state.previousAriaBusy);\n }\n\n documentRecord.hostStates.delete(host);\n documentRecord.liveHosts.delete(host);\n this.#deleteDocumentRecordWhenEmpty(documentRecord);\n }\n\n #closeHandle(state: SdLoadingHandleState, renderer: Renderer2): void {\n if (state.closed) return;\n\n state.closed = true;\n this.#dequeueHandle(state);\n const documentRecord = SdLoadingService.documentRecords.get(this.#document);\n if (documentRecord) {\n for (const contribution of [...state.contributions]) {\n this.#releaseContribution(documentRecord, contribution, renderer);\n }\n } else {\n for (const contribution of state.contributions) contribution.released = true;\n }\n state.contributions.length = 0;\n }\n\n #closeOwnerWhenReleased(state: SdLoadingHandleState): void {\n if (state.closed || state.contributions.some(contribution => !contribution.released)) return;\n\n state.closed = true;\n this.#dequeueHandle(state);\n state.contributions.length = 0;\n }\n\n #dequeueHandle(state: SdLoadingHandleState): void {\n const handleIndex = this.#handleQueue.indexOf(state);\n if (handleIndex >= 0) this.#handleQueue.splice(handleIndex, 1);\n }\n\n #createOverlay(renderer: Renderer2): HTMLElement {\n const container: HTMLElement = renderer.createElement('div');\n const spinner: HTMLElement = renderer.createElement('div');\n\n renderer.addClass(container, 'sd-loading');\n renderer.setAttribute(container, 'role', 'status');\n renderer.setAttribute(container, 'aria-live', 'polite');\n renderer.setAttribute(container, 'aria-label', 'Loading');\n\n renderer.addClass(spinner, 'sd-loading-spinner');\n renderer.setAttribute(spinner, 'aria-hidden', 'true');\n renderer.appendChild(container, spinner);\n return container;\n }\n\n #ensureStyles(documentRecord: SdLoadingDocumentRecord, renderer: Renderer2): void {\n let record = documentRecord.style;\n if (record && !this.#isCurrentStyle(record.element)) {\n const owners = record.owners;\n this.#detachOwnedStyleContent(record, renderer);\n record = this.#createStyleRecord(renderer, owners);\n documentRecord.style = record;\n } else if (!record) {\n record = this.#createStyleRecord(renderer, new Set<SdLoadingService>());\n documentRecord.style = record;\n } else {\n this.#ensureRequiredStyleText(record, renderer);\n }\n\n record.owners.add(this);\n this.#styleRegistered = true;\n }\n\n #isCurrentStyle(element: HTMLStyleElement): boolean {\n return element.isConnected && element.parentNode === this.#document.head && element.hasAttribute(SD_LOADING_STYLE_ATTRIBUTE);\n }\n\n #createStyleRecord(renderer: Renderer2, owners: Set<SdLoadingService>): SdLoadingStyleRecord {\n const existing = this.#document.head.querySelector<HTMLStyleElement>(`style[${SD_LOADING_STYLE_ATTRIBUTE}]`);\n if (existing) {\n const record: SdLoadingStyleRecord = {\n element: existing,\n libraryOwned: false,\n owners,\n ownedText: null,\n };\n this.#ensureRequiredStyleText(record, renderer);\n return record;\n }\n\n const style: HTMLStyleElement = renderer.createElement('style');\n const ownedText: Text = renderer.createText(SD_LOADING_STYLES);\n renderer.setAttribute(style, SD_LOADING_STYLE_ATTRIBUTE, '');\n renderer.appendChild(style, ownedText);\n renderer.appendChild(this.#document.head, style);\n return { element: style, libraryOwned: true, owners, ownedText };\n }\n\n #ensureRequiredStyleText(record: SdLoadingStyleRecord, renderer: Renderer2): void {\n const currentText = record.element.textContent ?? '';\n const hasRequiredRules =\n currentText.includes('.sd-loading {') &&\n currentText.includes('.sd-loading-spinner') &&\n currentText.includes('@keyframes sd-loading-spin');\n if (hasRequiredRules) return;\n\n if (record.ownedText && record.ownedText.parentNode !== record.element) record.ownedText = null;\n if (!record.ownedText) {\n record.ownedText = renderer.createText(SD_LOADING_STYLES);\n renderer.appendChild(record.element, record.ownedText);\n }\n }\n\n #detachOwnedStyleContent(record: SdLoadingStyleRecord, renderer: Renderer2): void {\n if (record.libraryOwned) {\n const parent = record.element.parentNode;\n if (parent) renderer.removeChild(parent, record.element);\n } else if (record.ownedText) {\n const textParent = record.ownedText.parentNode;\n if (textParent) renderer.removeChild(textParent, record.ownedText);\n }\n record.ownedText = null;\n }\n\n #destroy(): void {\n if (this.#destroyed) return;\n this.#destroyed = true;\n\n const renderer = this.#renderer;\n if (renderer) {\n for (const state of [...this.#handleQueue]) this.#closeHandle(state, renderer);\n this.#unregisterStyles(renderer);\n } else {\n for (const state of this.#handleQueue) {\n state.closed = true;\n state.contributions.length = 0;\n }\n this.#handleQueue.length = 0;\n }\n }\n\n #unregisterStyles(renderer: Renderer2): void {\n if (!this.#styleRegistered) return;\n this.#styleRegistered = false;\n\n const documentRecord = SdLoadingService.documentRecords.get(this.#document);\n const record = documentRecord?.style;\n if (!documentRecord || !record) return;\n\n record.owners.delete(this);\n if (record.owners.size === 0) {\n this.#detachOwnedStyleContent(record, renderer);\n documentRecord.style = undefined;\n }\n this.#deleteDocumentRecordWhenEmpty(documentRecord);\n }\n\n #deleteDocumentRecordWhenEmpty(documentRecord: SdLoadingDocumentRecord): void {\n if (documentRecord.liveHosts.size === 0 && !documentRecord.style) {\n SdLoadingService.documentRecords.delete(this.#document);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sdcorejs-angular-services-loading.mjs","sources":["../../../projects/sdcorejs-angular/services/loading/src/loading.service.ts","../../../projects/sdcorejs-angular/services/loading/sdcorejs-angular-services-loading.ts"],"sourcesContent":["import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, Injectable, PLATFORM_ID, inject } from '@angular/core';\n\nexport interface SdLoadingRef {\n readonly closed: boolean;\n close(): void;\n}\n\ninterface SdLoadingDocumentRecord {\n readonly hostStates: WeakMap<Element, SdLoadingHostState>;\n readonly liveHosts: Set<Element>;\n style: SdLoadingStyleRecord | undefined;\n}\n\ninterface SdLoadingHostState {\n readonly overlay: HTMLElement;\n readonly previousAriaBusy: string | null;\n readonly contributions: SdLoadingContribution[];\n count: number;\n}\n\ninterface SdLoadingHandleState {\n readonly selector: string;\n readonly contributions: SdLoadingContribution[];\n closed: boolean;\n}\n\ninterface SdLoadingContribution {\n readonly host: Element;\n readonly owner: SdLoadingHandleState;\n readonly service: SdLoadingService;\n released: boolean;\n}\n\ninterface SdLoadingStyleRecord {\n readonly element: HTMLStyleElement;\n readonly libraryOwned: boolean;\n readonly owners: Set<SdLoadingService>;\n ownedText: Text | null;\n}\n\nconst SD_LOADING_STYLE_ATTRIBUTE = 'data-sd-loading-styles';\nconst SD_LOADING_STYLES = `\n.sd-loading {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n opacity: 0.6;\n background: #fff;\n z-index: 99999;\n}\n\n.sd-loading-spinner {\n position: absolute;\n top: calc(50% - 2.5rem);\n left: calc(50% - 2.5rem);\n width: 5rem;\n height: 5rem;\n border: 0.5rem solid var(--sd-primary);\n border-top-color: var(--sd-border);\n border-radius: 50%;\n animation: sd-loading-spin 1s linear infinite;\n}\n\n@keyframes sd-loading-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n`;\n\nconst CLOSED_LOADING_REF: SdLoadingRef = Object.freeze({\n closed: true,\n close(): void {\n // A closed ref deliberately has no work to release.\n },\n});\n\n/*\n * why: service này cố tình KHÔNG dùng Renderer2. Khi app bật animations, `RendererFactory2` trả về\n * `AnimationRendererFactory` và `Renderer2.removeChild()` chỉ đẩy element vào hàng đợi\n * `collectedLeaveElements` của animation engine — DOM chỉ thật sự bị gỡ ở lần flush kế tiếp (sau một\n * chu kỳ change detection). Overlay và `style[data-sd-loading-styles]` ở đây là DOM ngoài view, được\n * gỡ lúc destroy injector hoặc từ ngữ cảnh async ngoài Angular, tức không còn flush nào chạy sau đó →\n * node nằm lại trong document vĩnh viễn (overlay z-index 99999 khoá cả trang). Ghi DOM trực tiếp trên\n * `DOCUMENT` giữ append/remove đối xứng và đồng bộ; nhánh SSR đã được `isPlatformBrowser` chặn sẵn.\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class SdLoadingService {\n private static readonly documentRecords = new WeakMap<Document, SdLoadingDocumentRecord>();\n\n readonly #document: Document;\n readonly #isBrowser: boolean;\n readonly #destroyRef = inject(DestroyRef);\n readonly #handleQueue: SdLoadingHandleState[] = [];\n\n #styleRegistered = false;\n #destroyed = false;\n\n /** Inserted by Angular inject() migration for backwards compatibility. */\n constructor(...args: unknown[]);\n constructor() {\n this.#document = inject(DOCUMENT);\n this.#isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n this.#destroyRef.onDestroy(() => this.#destroy());\n }\n\n /** Starts loading for every current selector match and returns ownership of those exact hosts. */\n start = (selector = 'body'): SdLoadingRef => {\n if (this.#destroyed || !this.#isBrowser) return CLOSED_LOADING_REF;\n\n const hosts = Array.from(this.#document.querySelectorAll(selector));\n if (hosts.length === 0) return CLOSED_LOADING_REF;\n\n const documentRecord = this.#getOrCreateDocumentRecord();\n this.#ensureStyles(documentRecord);\n const state: SdLoadingHandleState = { selector, contributions: [], closed: false };\n for (const host of hosts) {\n const contribution: SdLoadingContribution = {\n host,\n owner: state,\n service: this,\n released: false,\n };\n state.contributions.push(contribution);\n this.#acquireHost(documentRecord, contribution);\n }\n this.#handleQueue.push(state);\n\n return {\n get closed(): boolean {\n return state.closed;\n },\n close: () => this.#closeHandle(state),\n };\n };\n\n /** Returns the first matched globally loading host, `false` for idle matches, or `null` when unavailable. */\n isLoading = (selector = 'body'): Element | false | null => {\n if (this.#destroyed || !this.#isBrowser) return null;\n\n const hosts = this.#document.querySelectorAll(selector);\n if (hosts.length === 0) return null;\n\n const documentRecord = SdLoadingService.documentRecords.get(this.#document);\n for (const host of Array.from(hosts)) {\n const state = documentRecord?.hostStates.get(host);\n if (state && state.count > 0 && state.overlay.parentNode === host) return host;\n }\n return false;\n };\n\n /** Releases the oldest exact-selector start, with a current-host fallback for legacy cross-selector calls. */\n stop = (selector = 'body'): void => {\n if (this.#destroyed || !this.#isBrowser) return;\n\n const exactHandle = this.#handleQueue.find(state => !state.closed && state.selector === selector);\n if (exactHandle) {\n this.#closeHandle(exactHandle);\n return;\n }\n\n const documentRecord = SdLoadingService.documentRecords.get(this.#document);\n if (!documentRecord) return;\n\n for (const host of Array.from(this.#document.querySelectorAll(selector))) {\n const contribution = documentRecord.hostStates\n .get(host)\n ?.contributions.find(candidate => !candidate.released && candidate.service === this);\n if (contribution) this.#releaseContribution(documentRecord, contribution);\n }\n };\n\n run<T>(task: () => T | PromiseLike<T>, selector?: string): Promise<T>;\n run<T>(task: PromiseLike<T>, selector?: string): Promise<T>;\n /** Runs a task inside a loading lifetime and always releases it without replacing the task result or error. */\n async run<T>(task: (() => T | PromiseLike<T>) | PromiseLike<T>, selector = 'body'): Promise<T> {\n const ref = this.start(selector);\n try {\n const result = typeof task === 'function' ? task() : task;\n return await result;\n } finally {\n ref.close();\n }\n }\n\n #getOrCreateDocumentRecord(): SdLoadingDocumentRecord {\n let record = SdLoadingService.documentRecords.get(this.#document);\n if (!record) {\n record = {\n hostStates: new WeakMap<Element, SdLoadingHostState>(),\n liveHosts: new Set<Element>(),\n style: undefined,\n };\n SdLoadingService.documentRecords.set(this.#document, record);\n }\n return record;\n }\n\n #acquireHost(documentRecord: SdLoadingDocumentRecord, contribution: SdLoadingContribution): void {\n const host = contribution.host;\n const existing = documentRecord.hostStates.get(host);\n if (existing) {\n this.#repairOverlay(host, existing);\n existing.count += 1;\n existing.contributions.push(contribution);\n return;\n }\n\n const state: SdLoadingHostState = {\n overlay: this.#createOverlay(),\n previousAriaBusy: host.getAttribute('aria-busy'),\n contributions: [contribution],\n count: 1,\n };\n host.setAttribute('aria-busy', 'true');\n host.appendChild(state.overlay);\n documentRecord.hostStates.set(host, state);\n documentRecord.liveHosts.add(host);\n }\n\n #repairOverlay(host: Element, state: SdLoadingHostState): void {\n // why: appendChild tự động rút overlay khỏi parent cũ, nên không cần removeChild riêng.\n if (state.overlay.parentNode !== host) host.appendChild(state.overlay);\n if (host.getAttribute('aria-busy') !== 'true') host.setAttribute('aria-busy', 'true');\n }\n\n #releaseContribution(documentRecord: SdLoadingDocumentRecord, contribution: SdLoadingContribution): void {\n if (contribution.released) return;\n contribution.released = true;\n\n const state = documentRecord.hostStates.get(contribution.host);\n if (state) {\n const contributionIndex = state.contributions.indexOf(contribution);\n if (contributionIndex >= 0) state.contributions.splice(contributionIndex, 1);\n state.count -= 1;\n\n if (state.count <= 0) this.#removeHost(documentRecord, contribution.host, state);\n }\n\n contribution.service.#closeOwnerWhenReleased(contribution.owner);\n }\n\n #removeHost(documentRecord: SdLoadingDocumentRecord, host: Element, state: SdLoadingHostState): void {\n state.overlay.remove();\n\n if (host.getAttribute('aria-busy') === 'true') {\n if (state.previousAriaBusy === null) host.removeAttribute('aria-busy');\n else host.setAttribute('aria-busy', state.previousAriaBusy);\n }\n\n documentRecord.hostStates.delete(host);\n documentRecord.liveHosts.delete(host);\n this.#deleteDocumentRecordWhenEmpty(documentRecord);\n }\n\n #closeHandle(state: SdLoadingHandleState): void {\n if (state.closed) return;\n\n state.closed = true;\n this.#dequeueHandle(state);\n const documentRecord = SdLoadingService.documentRecords.get(this.#document);\n if (documentRecord) {\n for (const contribution of [...state.contributions]) {\n this.#releaseContribution(documentRecord, contribution);\n }\n } else {\n for (const contribution of state.contributions) contribution.released = true;\n }\n state.contributions.length = 0;\n }\n\n #closeOwnerWhenReleased(state: SdLoadingHandleState): void {\n if (state.closed || state.contributions.some(contribution => !contribution.released)) return;\n\n state.closed = true;\n this.#dequeueHandle(state);\n state.contributions.length = 0;\n }\n\n #dequeueHandle(state: SdLoadingHandleState): void {\n const handleIndex = this.#handleQueue.indexOf(state);\n if (handleIndex >= 0) this.#handleQueue.splice(handleIndex, 1);\n }\n\n #createOverlay(): HTMLElement {\n const container = this.#document.createElement('div');\n const spinner = this.#document.createElement('div');\n\n container.classList.add('sd-loading');\n container.setAttribute('role', 'status');\n container.setAttribute('aria-live', 'polite');\n container.setAttribute('aria-label', 'Loading');\n\n spinner.classList.add('sd-loading-spinner');\n spinner.setAttribute('aria-hidden', 'true');\n container.appendChild(spinner);\n return container;\n }\n\n #ensureStyles(documentRecord: SdLoadingDocumentRecord): void {\n let record = documentRecord.style;\n if (record && !this.#isCurrentStyle(record.element)) {\n const owners = record.owners;\n this.#detachOwnedStyleContent(record);\n record = this.#createStyleRecord(owners);\n documentRecord.style = record;\n } else if (!record) {\n record = this.#createStyleRecord(new Set<SdLoadingService>());\n documentRecord.style = record;\n } else {\n this.#ensureRequiredStyleText(record);\n }\n\n record.owners.add(this);\n this.#styleRegistered = true;\n }\n\n #isCurrentStyle(element: HTMLStyleElement): boolean {\n return element.isConnected && element.parentNode === this.#document.head && element.hasAttribute(SD_LOADING_STYLE_ATTRIBUTE);\n }\n\n #createStyleRecord(owners: Set<SdLoadingService>): SdLoadingStyleRecord {\n const existing = this.#document.head.querySelector<HTMLStyleElement>(`style[${SD_LOADING_STYLE_ATTRIBUTE}]`);\n if (existing) {\n const record: SdLoadingStyleRecord = {\n element: existing,\n libraryOwned: false,\n owners,\n ownedText: null,\n };\n this.#ensureRequiredStyleText(record);\n return record;\n }\n\n const style = this.#document.createElement('style');\n const ownedText = this.#document.createTextNode(SD_LOADING_STYLES);\n style.setAttribute(SD_LOADING_STYLE_ATTRIBUTE, '');\n style.appendChild(ownedText);\n this.#document.head.appendChild(style);\n return { element: style, libraryOwned: true, owners, ownedText };\n }\n\n #ensureRequiredStyleText(record: SdLoadingStyleRecord): void {\n const currentText = record.element.textContent ?? '';\n const hasRequiredRules =\n currentText.includes('.sd-loading {') &&\n currentText.includes('.sd-loading-spinner') &&\n currentText.includes('@keyframes sd-loading-spin');\n if (hasRequiredRules) return;\n\n if (record.ownedText && record.ownedText.parentNode !== record.element) record.ownedText = null;\n if (!record.ownedText) {\n record.ownedText = this.#document.createTextNode(SD_LOADING_STYLES);\n record.element.appendChild(record.ownedText);\n }\n }\n\n #detachOwnedStyleContent(record: SdLoadingStyleRecord): void {\n if (record.libraryOwned) record.element.remove();\n else record.ownedText?.remove();\n record.ownedText = null;\n }\n\n #destroy(): void {\n if (this.#destroyed) return;\n this.#destroyed = true;\n\n if (this.#isBrowser) {\n for (const state of [...this.#handleQueue]) this.#closeHandle(state);\n this.#unregisterStyles();\n return;\n }\n\n for (const state of this.#handleQueue) {\n state.closed = true;\n state.contributions.length = 0;\n }\n this.#handleQueue.length = 0;\n }\n\n #unregisterStyles(): void {\n if (!this.#styleRegistered) return;\n this.#styleRegistered = false;\n\n const documentRecord = SdLoadingService.documentRecords.get(this.#document);\n const record = documentRecord?.style;\n if (!documentRecord || !record) return;\n\n record.owners.delete(this);\n if (record.owners.size === 0) {\n this.#detachOwnedStyleContent(record);\n documentRecord.style = undefined;\n }\n this.#deleteDocumentRecordWhenEmpty(documentRecord);\n }\n\n #deleteDocumentRecordWhenEmpty(documentRecord: SdLoadingDocumentRecord): void {\n if (documentRecord.liveHosts.size === 0 && !documentRecord.style) {\n SdLoadingService.documentRecords.delete(this.#document);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CommonModule, DOCUMENT } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { inject, signal, computed, SecurityContext, HostListener, Input, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, Injectable } from '@angular/core';
|
|
3
|
+
import { inject, signal, computed, SecurityContext, HostListener, Input, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, DestroyRef, createComponent, Injectable } from '@angular/core';
|
|
4
4
|
import { Utilities } from '@sdcorejs/utils/fns';
|
|
5
|
-
import {
|
|
5
|
+
import { SdTranslatePipe, I18nService } from '@sdcorejs/angular/i18n';
|
|
6
6
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
7
7
|
|
|
8
8
|
const TOAST_EXIT_ANIMATION_MS = 200;
|
|
@@ -106,17 +106,17 @@ class ToastComponent {
|
|
|
106
106
|
this.closeTimer = null;
|
|
107
107
|
}
|
|
108
108
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
109
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ToastComponent, isStandalone: true, selector: "toast", inputs: { data: "data" }, host: { listeners: { "mouseenter": "pauseTimer()", "mouseleave": "resumeTimer()" }, properties: { "class": "hostClasses()", "attr.data-autoid": "autoId", "attr.data-type": "data.type", "attr.data-title": "data.title ?? null", "attr.data-message": "dataMessage" } }, ngImport: i0, template: "<div class=\"sd-toast__bar\" [class]=\"'bg-' + data.type\"></div>\n\n<div class=\"sd-toast__icon\" [class]=\"'text-' + data.type\">\n @switch (data.type) {\n @case ('success') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>\n }\n @case ('info') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\"/></svg>\n }\n @case ('warning') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z\"/></svg>\n }\n @case ('error') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"/></svg>\n }\n }\n</div>\n\n<div class=\"sd-toast__content\">\n <div class=\"sd-toast__header\">\n <strong class=\"sd-toast__title\">{{ data.title || ('core.notify.type.' + data.type |
|
|
109
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ToastComponent, isStandalone: true, selector: "toast", inputs: { data: "data" }, host: { listeners: { "mouseenter": "pauseTimer()", "mouseleave": "resumeTimer()" }, properties: { "class": "hostClasses()", "attr.data-autoid": "autoId", "attr.data-type": "data.type", "attr.data-title": "data.title ?? null", "attr.data-message": "dataMessage" } }, ngImport: i0, template: "<div class=\"sd-toast__bar\" [class]=\"'bg-' + data.type\"></div>\n\n<div class=\"sd-toast__icon\" [class]=\"'text-' + data.type\">\n @switch (data.type) {\n @case ('success') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>\n }\n @case ('info') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\"/></svg>\n }\n @case ('warning') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z\"/></svg>\n }\n @case ('error') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"/></svg>\n }\n }\n</div>\n\n<div class=\"sd-toast__content\">\n <div class=\"sd-toast__header\">\n <strong class=\"sd-toast__title\">{{ data.title || ('core.notify.type.' + data.type | sdTranslate) }}</strong>\n <button class=\"sd-toast__close\" (click)=\"close()\">×</button>\n </div>\n\n <div class=\"sd-toast__body\">\n @if (!isMultiMessage) {\n <!-- Text rendering is the default safe path; HTML is opt-in and sanitized. -->\n @if (data.html) {\n <div [innerHTML]=\"sanitizeHtml(singleMessage)\"></div>\n } @else {\n <div>{{ singleMessage }}</div>\n }\n } @else {\n <ul class=\"msg-list\">\n @for (msg of displayMessages; track msg) {\n @if (data.html) {\n <li [innerHTML]=\"sanitizeHtml('- ' + msg)\"></li>\n } @else {\n <li>{{ '- ' + msg }}</li>\n }\n }\n </ul>\n\n @if (hasMore) {\n <button\n type=\"button\"\n class=\"toggle-more btn-link\"\n [class]=\"'text-' + data.type\"\n (click)=\"toggleExpand()\">\n {{ isExpanded() ? ('core.notify.show-less' | sdTranslate) : ('core.notify.show-more' | sdTranslate: { count: restCount }) }}\n </button>\n }\n }\n </div>\n\n @if (data.actionLabel) {\n <div class=\"sd-toast__actions\">\n <button\n class=\"btn-action\"\n [class]=\"'bg-' + data.type + '-light text-' + data.type\"\n (click)=\"onActionClick()\">\n {{ data.actionLabel }}\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:flex;width:350px;border-radius:8px;box-shadow:0 4px 12px #00000026;margin-bottom:12px;overflow:hidden;position:relative;font-family:Roboto,sans-serif;pointer-events:auto;animation:sd-toast-enter .3s ease-out}:host(.sd-toast--closing){pointer-events:none;animation:sd-toast-leave .2s ease-in forwards}@keyframes sd-toast-enter{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes sd-toast-leave{0%{transform:translate(0);opacity:1}to{transform:translate(100%);opacity:0}}@media(prefers-reduced-motion:reduce){:host,:host(.sd-toast--closing){animation:none}}.sd-toast__bar{width:6px;flex-shrink:0}.sd-toast__icon{padding:12px 0 0 12px;flex-shrink:0}.sd-toast__icon svg{width:24px;height:24px}.sd-toast__content{flex-grow:1;padding:12px;display:flex;flex-direction:column}.sd-toast__header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:4px}.sd-toast__title{font-size:16px;font-weight:600}.sd-toast__close{background:none;border:none;font-size:16px;cursor:pointer;line-height:1;padding:0;opacity:.5;transition:opacity .2s}.sd-toast__close:hover{opacity:1}.sd-toast__body{font-size:14px;line-height:1.4;word-break:break-word}.sd-toast__actions{display:flex;justify-content:flex-end;margin-top:8px}.msg-list{padding-left:0;list-style:none;margin:0}.toggle-more{background:none;border:none;padding:0;font:inherit;cursor:pointer;font-size:13px;margin-top:4px;font-weight:500;text-align:left}.toggle-more:hover{text-decoration:underline}.toggle-more:focus-visible{outline:2px solid currentColor;outline-offset:2px}.btn-action{border:none;padding:6px 12px;border-radius:4px;font-weight:600;cursor:pointer;font-size:13px;transition:filter .2s}.btn-action:hover{filter:brightness(.95)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: SdTranslatePipe, name: "sdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
110
110
|
}
|
|
111
111
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ToastComponent, decorators: [{
|
|
112
112
|
type: Component,
|
|
113
|
-
args: [{ selector: 'toast', standalone: true, imports: [CommonModule,
|
|
113
|
+
args: [{ selector: 'toast', standalone: true, imports: [CommonModule, SdTranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
114
114
|
'[class]': 'hostClasses()',
|
|
115
115
|
'[attr.data-autoid]': 'autoId',
|
|
116
116
|
'[attr.data-type]': 'data.type',
|
|
117
117
|
'[attr.data-title]': 'data.title ?? null',
|
|
118
118
|
'[attr.data-message]': 'dataMessage',
|
|
119
|
-
}, template: "<div class=\"sd-toast__bar\" [class]=\"'bg-' + data.type\"></div>\n\n<div class=\"sd-toast__icon\" [class]=\"'text-' + data.type\">\n @switch (data.type) {\n @case ('success') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>\n }\n @case ('info') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\"/></svg>\n }\n @case ('warning') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z\"/></svg>\n }\n @case ('error') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"/></svg>\n }\n }\n</div>\n\n<div class=\"sd-toast__content\">\n <div class=\"sd-toast__header\">\n <strong class=\"sd-toast__title\">{{ data.title || ('core.notify.type.' + data.type |
|
|
119
|
+
}, template: "<div class=\"sd-toast__bar\" [class]=\"'bg-' + data.type\"></div>\n\n<div class=\"sd-toast__icon\" [class]=\"'text-' + data.type\">\n @switch (data.type) {\n @case ('success') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>\n }\n @case ('info') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\"/></svg>\n }\n @case ('warning') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z\"/></svg>\n }\n @case ('error') {\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"/></svg>\n }\n }\n</div>\n\n<div class=\"sd-toast__content\">\n <div class=\"sd-toast__header\">\n <strong class=\"sd-toast__title\">{{ data.title || ('core.notify.type.' + data.type | sdTranslate) }}</strong>\n <button class=\"sd-toast__close\" (click)=\"close()\">×</button>\n </div>\n\n <div class=\"sd-toast__body\">\n @if (!isMultiMessage) {\n <!-- Text rendering is the default safe path; HTML is opt-in and sanitized. -->\n @if (data.html) {\n <div [innerHTML]=\"sanitizeHtml(singleMessage)\"></div>\n } @else {\n <div>{{ singleMessage }}</div>\n }\n } @else {\n <ul class=\"msg-list\">\n @for (msg of displayMessages; track msg) {\n @if (data.html) {\n <li [innerHTML]=\"sanitizeHtml('- ' + msg)\"></li>\n } @else {\n <li>{{ '- ' + msg }}</li>\n }\n }\n </ul>\n\n @if (hasMore) {\n <button\n type=\"button\"\n class=\"toggle-more btn-link\"\n [class]=\"'text-' + data.type\"\n (click)=\"toggleExpand()\">\n {{ isExpanded() ? ('core.notify.show-less' | sdTranslate) : ('core.notify.show-more' | sdTranslate: { count: restCount }) }}\n </button>\n }\n }\n </div>\n\n @if (data.actionLabel) {\n <div class=\"sd-toast__actions\">\n <button\n class=\"btn-action\"\n [class]=\"'bg-' + data.type + '-light text-' + data.type\"\n (click)=\"onActionClick()\">\n {{ data.actionLabel }}\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:flex;width:350px;border-radius:8px;box-shadow:0 4px 12px #00000026;margin-bottom:12px;overflow:hidden;position:relative;font-family:Roboto,sans-serif;pointer-events:auto;animation:sd-toast-enter .3s ease-out}:host(.sd-toast--closing){pointer-events:none;animation:sd-toast-leave .2s ease-in forwards}@keyframes sd-toast-enter{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes sd-toast-leave{0%{transform:translate(0);opacity:1}to{transform:translate(100%);opacity:0}}@media(prefers-reduced-motion:reduce){:host,:host(.sd-toast--closing){animation:none}}.sd-toast__bar{width:6px;flex-shrink:0}.sd-toast__icon{padding:12px 0 0 12px;flex-shrink:0}.sd-toast__icon svg{width:24px;height:24px}.sd-toast__content{flex-grow:1;padding:12px;display:flex;flex-direction:column}.sd-toast__header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:4px}.sd-toast__title{font-size:16px;font-weight:600}.sd-toast__close{background:none;border:none;font-size:16px;cursor:pointer;line-height:1;padding:0;opacity:.5;transition:opacity .2s}.sd-toast__close:hover{opacity:1}.sd-toast__body{font-size:14px;line-height:1.4;word-break:break-word}.sd-toast__actions{display:flex;justify-content:flex-end;margin-top:8px}.msg-list{padding-left:0;list-style:none;margin:0}.toggle-more{background:none;border:none;padding:0;font:inherit;cursor:pointer;font-size:13px;margin-top:4px;font-weight:500;text-align:left}.toggle-more:hover{text-decoration:underline}.toggle-more:focus-visible{outline:2px solid currentColor;outline-offset:2px}.btn-action{border:none;padding:6px 12px;border-radius:4px;font-weight:600;cursor:pointer;font-size:13px;transition:filter .2s}.btn-action:hover{filter:brightness(.95)}\n"] }]
|
|
120
120
|
}], ctorParameters: () => [], propDecorators: { data: [{
|
|
121
121
|
type: Input,
|
|
122
122
|
args: [{ required: true }]
|
|
@@ -160,12 +160,22 @@ class SdNotifyService {
|
|
|
160
160
|
// State
|
|
161
161
|
#buffer = {};
|
|
162
162
|
#timers = {};
|
|
163
|
+
#containerRef;
|
|
164
|
+
#containerElement;
|
|
163
165
|
appRef = inject(ApplicationRef);
|
|
164
166
|
injector = inject(EnvironmentInjector);
|
|
165
167
|
document = inject(DOCUMENT);
|
|
168
|
+
#destroyRef = inject(DestroyRef);
|
|
166
169
|
#i18n = inject(I18nService);
|
|
170
|
+
/** Đặt trong `#teardown()` — mọi API public trở thành no-op sau khi injector bị destroy. */
|
|
171
|
+
#destroyed = false;
|
|
167
172
|
constructor() {
|
|
168
173
|
this.#initContainer();
|
|
174
|
+
// why: providedIn:'root' KHÔNG có nghĩa là sống mãi — root injector vẫn bị destroy
|
|
175
|
+
// (TestBed reset, mỗi request khi SSR, micro-frontend unmount). Không có hook teardown thì
|
|
176
|
+
// ComponentRef + node <body> ở lại vĩnh viễn và timer debounce đang chờ sẽ flush vào signal
|
|
177
|
+
// của service đã chết → toast ma + leak view/DOM tích luỹ theo từng lần bootstrap.
|
|
178
|
+
this.#destroyRef.onDestroy(() => this.#teardown());
|
|
169
179
|
}
|
|
170
180
|
#initContainer() {
|
|
171
181
|
const componentRef = createComponent(ToastContainerComponent, {
|
|
@@ -175,6 +185,33 @@ class SdNotifyService {
|
|
|
175
185
|
this.appRef.attachView(componentRef.hostView);
|
|
176
186
|
const domElem = componentRef.hostView.rootNodes[0];
|
|
177
187
|
this.document.body.appendChild(domElem);
|
|
188
|
+
this.#containerRef = componentRef;
|
|
189
|
+
this.#containerElement = domElem;
|
|
190
|
+
}
|
|
191
|
+
#teardown() {
|
|
192
|
+
// why: cờ này chặn MỌI lời gọi sau teardown. Chỉ dọn timer đang chờ là chưa đủ: một
|
|
193
|
+
// `error()`/`warning()` gọi sau khi injector đã destroy vẫn chạy `#addToBuffer` và hẹn một
|
|
194
|
+
// timer 500ms MỚI mà không còn ai clear — nó flush vào signal của service đã chết.
|
|
195
|
+
this.#destroyed = true;
|
|
196
|
+
// why: dọn timer TRƯỚC khi huỷ view — flush chạy sau khi container đã destroy sẽ
|
|
197
|
+
// update signal mà không còn ai render, thuần tuý là công vô ích trên state đã chết.
|
|
198
|
+
this.#clearAllTimers();
|
|
199
|
+
this.#buffer = {};
|
|
200
|
+
const componentRef = this.#containerRef;
|
|
201
|
+
const containerElement = this.#containerElement;
|
|
202
|
+
this.#containerRef = undefined;
|
|
203
|
+
this.#containerElement = undefined;
|
|
204
|
+
// why: hook destroy của service chạy SAU ApplicationRef.destroy() khi root injector bị tháo
|
|
205
|
+
// (hook đăng ký theo thứ tự khởi tạo, mà appRef luôn có trước). Lúc đó view đã bị huỷ và
|
|
206
|
+
// detachView chỉ log NG0406 — nên chỉ detach khi appRef còn sống.
|
|
207
|
+
if (componentRef && !this.appRef.destroyed && !componentRef.hostView.destroyed) {
|
|
208
|
+
this.appRef.detachView(componentRef.hostView);
|
|
209
|
+
componentRef.destroy();
|
|
210
|
+
}
|
|
211
|
+
// why: createComponent() tạo host node rời rồi ta tự appendChild, nên destroy() không
|
|
212
|
+
// bảo đảm gỡ node khỏi <body> — gỡ tay để không để lại rác DOM. remove() an toàn khi
|
|
213
|
+
// node đã bị tách.
|
|
214
|
+
containerElement?.remove();
|
|
178
215
|
}
|
|
179
216
|
// Public API
|
|
180
217
|
success(message, option) {
|
|
@@ -201,6 +238,8 @@ class SdNotifyService {
|
|
|
201
238
|
}
|
|
202
239
|
// Private helpers
|
|
203
240
|
#addImmediate(type, message, option) {
|
|
241
|
+
if (this.#destroyed)
|
|
242
|
+
return;
|
|
204
243
|
const newToast = {
|
|
205
244
|
id: Utilities.generateUuid(),
|
|
206
245
|
type,
|
|
@@ -217,6 +256,8 @@ class SdNotifyService {
|
|
|
217
256
|
});
|
|
218
257
|
}
|
|
219
258
|
#addToBuffer(type, message, option) {
|
|
259
|
+
if (this.#destroyed)
|
|
260
|
+
return;
|
|
220
261
|
if (!this.#buffer[type]) {
|
|
221
262
|
this.#buffer[type] = [];
|
|
222
263
|
}
|