@sd-angular/core 19.0.0-beta.8 → 19.0.0-beta.80
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 +686 -33
- package/assets/scss/ckeditor5.scss +61 -4
- package/assets/scss/core/bootstrap.scss +17 -0
- package/assets/scss/core/form.scss +32 -6
- package/assets/scss/core/grid.scss +40 -0
- package/assets/scss/sd-core.scss +5 -0
- package/assets/scss/themes/material-theme.scss +82 -40
- package/components/anchor-v2/src/components/anchor-item-v2/anchor-item-v2.component.d.ts +5 -5
- package/components/anchor-v2/src/components/anchor-v2/anchor-v2.component.d.ts +12 -18
- package/components/anchor-v2/src/components/anchor-vertical-v2/anchor-vertical-list-v2.component.d.ts +9 -10
- package/components/anchor-v2/src/models/sd-anchor-v2.model.d.ts +3 -3
- package/components/avatar/index.d.ts +1 -0
- package/components/avatar/src/avatar.component.d.ts +19 -0
- package/components/badge/src/badge.component.d.ts +77 -19
- package/components/button/src/button.component.d.ts +30 -28
- package/components/chart/index.d.ts +4 -0
- package/components/chart/src/bar-chart.component.d.ts +18 -0
- package/components/chart/src/doughnut-chart.component.d.ts +16 -0
- package/components/chart/src/line-chart.component.d.ts +18 -0
- package/components/chart/src/pie-chart.component.d.ts +16 -0
- package/components/code-editor/index.d.ts +1 -0
- package/components/code-editor/src/code-editor.component.d.ts +25 -0
- package/components/document-builder/index.d.ts +1 -0
- package/components/document-builder/src/document-builder.component.d.ts +12 -41
- package/components/document-builder/src/document-builder.model.d.ts +14 -11
- package/components/document-builder/src/plugins/block-space/block-space.plugin.d.ts +9 -0
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.d.ts +44 -0
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.model.d.ts +57 -0
- package/components/document-builder/src/plugins/heading/heading.plugin.d.ts +1 -0
- package/components/document-builder/src/plugins/highlight-range/highlight-range.plugin.d.ts +4 -0
- package/components/document-builder/src/plugins/image-custom/image-custom.plugin.d.ts +31 -0
- package/components/document-builder/src/plugins/index.d.ts +7 -2
- package/components/document-builder/src/plugins/page-orientation/page-orientation.plugin.d.ts +2 -2
- package/components/document-builder/src/plugins/paste-handler/filters/bookmark.d.ts +14 -0
- package/components/document-builder/src/plugins/paste-handler/filters/br.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/image.d.ts +25 -0
- package/components/document-builder/src/plugins/paste-handler/filters/list.d.ts +29 -0
- package/components/document-builder/src/plugins/paste-handler/filters/parse.d.ts +35 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removeboldwrapper.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removegooglesheetstag.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removeinvalidtablewidth.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removemsattributes.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removestyleblock.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removexmlns.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/replacemsfootnotes.d.ts +54 -0
- package/components/document-builder/src/plugins/paste-handler/filters/replacetabswithinprewithspaces.d.ts +24 -0
- package/components/document-builder/src/plugins/paste-handler/filters/space.d.ts +27 -0
- package/components/document-builder/src/plugins/paste-handler/filters/table.d.ts +16 -0
- package/components/document-builder/src/plugins/paste-handler/filters/utils.d.ts +25 -0
- package/components/document-builder/src/plugins/paste-handler/index.d.ts +35 -0
- package/components/document-builder/src/plugins/paste-handler/normalizers/googledocsnormalizer.d.ts +31 -0
- package/components/document-builder/src/plugins/paste-handler/normalizers/googlesheetsnormalizer.d.ts +31 -0
- package/components/document-builder/src/plugins/paste-handler/normalizers/mswordnormalizer.d.ts +29 -0
- package/components/document-builder/src/plugins/paste-handler/types.d.ts +30 -0
- package/components/document-builder/src/plugins/table-custom/index.d.ts +34 -0
- package/components/document-builder/src/plugins/variable/variable.plugin.d.ts +39 -0
- package/components/index.d.ts +5 -0
- package/components/mini-editor/index.d.ts +2 -0
- package/components/mini-editor/src/mini-editor.component.d.ts +91 -0
- package/components/mini-editor/src/mini-editor.model.d.ts +44 -0
- package/components/modal/index.d.ts +1 -1
- package/components/modal/src/modal.component.d.ts +26 -0
- package/components/section/index.d.ts +1 -0
- package/components/section/src/section-item/section-item.component.d.ts +7 -0
- package/components/section/src/section.component.d.ts +11 -11
- package/components/side-drawer/src/side-drawer.component.d.ts +11 -24
- package/components/tab-router/src/components/tab-router-item/tab-router-item.component.d.ts +4 -1
- package/components/tab-router/src/components/tab-router-outlet/tab-router-outlet.component.d.ts +3 -15
- package/components/table/index.d.ts +2 -0
- package/components/table/src/components/column-filter/column-filter.component.d.ts +3 -3
- package/components/table/src/components/column-title/column-title.component.d.ts +10 -0
- package/components/table/src/components/desktop-cell/desktop-cell.component.d.ts +18 -11
- package/components/table/src/components/desktop-cell/view/view.component.d.ts +24 -0
- package/components/table/src/components/external-filter/external-filter.component.d.ts +1 -1
- package/components/table/src/components/index.d.ts +1 -0
- package/components/table/src/components/selector-action/action-filter.pipe.d.ts +11 -10
- package/components/table/src/components/selector-action/selector-action.component.d.ts +5 -3
- package/components/table/src/directives/index.d.ts +4 -0
- package/components/table/src/directives/sd-table-cell-def.directive.d.ts +2 -3
- package/components/table/src/directives/sd-table-column-filter-def.directive.d.ts +8 -0
- package/components/table/src/directives/sd-table-expand-def.directive.d.ts +0 -1
- package/components/table/src/directives/sd-table-filter-def.directive.d.ts +4 -6
- package/components/table/src/directives/sd-table-footer-def.directive.d.ts +2 -3
- package/components/table/src/directives/sd-table-title-def.directive.d.ts +8 -0
- package/components/table/src/directives/sticky-shadow.directive.d.ts +17 -0
- package/components/table/src/models/table-column.model.d.ts +49 -40
- package/components/table/src/models/table-command.model.d.ts +7 -3
- package/components/table/src/models/table-item.model.d.ts +5 -4
- package/components/table/src/models/table-option-config.model.d.ts +3 -0
- package/components/table/src/models/table-option-export.model.d.ts +3 -2
- package/components/table/src/models/table-option-selector.model.d.ts +17 -10
- package/components/table/src/models/table-option.model.d.ts +15 -8
- package/components/table/src/services/index.d.ts +3 -0
- package/components/table/src/services/table-export/table-export.service.d.ts +26 -0
- package/components/table/src/services/table-filter/table-filter.model.d.ts +6 -5
- package/components/table/src/services/table-format/table-format.service.d.ts +16 -0
- package/components/table/src/table.component.d.ts +46 -53
- package/components/upload-file/src/configurations/upload-file.configuration.d.ts +34 -1
- package/components/upload-file/src/services/upload-file.service.d.ts +0 -1
- package/components/upload-file/src/upload-file.component.d.ts +52 -54
- package/components/view/index.d.ts +1 -0
- package/components/view/src/view.component.d.ts +16 -0
- package/components/workflow/src/models/form-generic-component.model.d.ts +5 -4
- package/components/workflow/src/models/form-generic-expression.model.d.ts +1 -0
- package/components/workflow/src/models/index.d.ts +1 -0
- package/components/workflow/src/pipes/html.pipe.d.ts +4 -4
- package/directives/index.d.ts +2 -0
- package/directives/src/sd-href.directive.d.ts +9 -0
- package/directives/src/sd-tooltip.directive.d.ts +26 -0
- package/fesm2022/sd-angular-core-components-anchor-v2.mjs +79 -154
- package/fesm2022/sd-angular-core-components-anchor-v2.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-avatar.mjs +103 -0
- package/fesm2022/sd-angular-core-components-avatar.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-badge.mjs +101 -91
- package/fesm2022/sd-angular-core-components-badge.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-button.mjs +70 -96
- package/fesm2022/sd-angular-core-components-button.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-chart.mjs +290 -0
- package/fesm2022/sd-angular-core-components-chart.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-code-editor.mjs +127 -0
- package/fesm2022/sd-angular-core-components-code-editor.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-document-builder.mjs +4006 -611
- package/fesm2022/sd-angular-core-components-document-builder.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-history.mjs +1 -1
- package/fesm2022/sd-angular-core-components-history.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-import-excel.mjs +1 -1
- package/fesm2022/sd-angular-core-components-import-excel.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-mini-editor.mjs +332 -0
- package/fesm2022/sd-angular-core-components-mini-editor.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-modal.mjs +63 -92
- package/fesm2022/sd-angular-core-components-modal.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-preview.mjs +1 -1
- package/fesm2022/sd-angular-core-components-preview.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-quick-action.mjs +2 -2
- package/fesm2022/sd-angular-core-components-quick-action.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-section.mjs +41 -43
- package/fesm2022/sd-angular-core-components-section.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-side-drawer.mjs +78 -84
- package/fesm2022/sd-angular-core-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-tab-router.mjs +151 -241
- package/fesm2022/sd-angular-core-components-tab-router.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-table.mjs +1394 -1254
- package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-upload-file.mjs +390 -443
- package/fesm2022/sd-angular-core-components-upload-file.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-view.mjs +45 -0
- package/fesm2022/sd-angular-core-components-view.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-workflow.mjs +165 -168
- package/fesm2022/sd-angular-core-components-workflow.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components.mjs +5 -0
- package/fesm2022/sd-angular-core-components.mjs.map +1 -1
- package/fesm2022/sd-angular-core-directives.mjs +286 -27
- package/fesm2022/sd-angular-core-directives.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-autocomplete.mjs +289 -363
- package/fesm2022/sd-angular-core-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-chip-calendar.mjs +170 -189
- package/fesm2022/sd-angular-core-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-chip.mjs +184 -194
- package/fesm2022/sd-angular-core-forms-chip.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-date-range.mjs +180 -242
- package/fesm2022/sd-angular-core-forms-date-range.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-date.mjs +178 -270
- package/fesm2022/sd-angular-core-forms-date.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-datetime.mjs +177 -285
- package/fesm2022/sd-angular-core-forms-datetime.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-input-number.mjs +210 -337
- package/fesm2022/sd-angular-core-forms-input-number.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-input.mjs +169 -286
- package/fesm2022/sd-angular-core-forms-input.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-radio.mjs +3 -2
- package/fesm2022/sd-angular-core-forms-radio.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-select.mjs +390 -447
- package/fesm2022/sd-angular-core-forms-select.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-textarea.mjs +167 -226
- package/fesm2022/sd-angular-core-forms-textarea.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules-authom.mjs +359 -0
- package/fesm2022/sd-angular-core-modules-authom.mjs.map +1 -0
- package/fesm2022/sd-angular-core-modules-keycloak.mjs +126 -0
- package/fesm2022/sd-angular-core-modules-keycloak.mjs.map +1 -0
- package/fesm2022/sd-angular-core-modules-layout.mjs +709 -456
- package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules-permission.mjs +160 -74
- package/fesm2022/sd-angular-core-modules-permission.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules.mjs +2 -1
- package/fesm2022/sd-angular-core-modules.mjs.map +1 -1
- package/fesm2022/sd-angular-core-services-api.mjs +5 -10
- package/fesm2022/sd-angular-core-services-api.mjs.map +1 -1
- package/fesm2022/sd-angular-core-services-confirm.mjs +9 -7
- package/fesm2022/sd-angular-core-services-confirm.mjs.map +1 -1
- package/fesm2022/sd-angular-core-services-docx.mjs +173 -0
- package/fesm2022/sd-angular-core-services-docx.mjs.map +1 -0
- package/fesm2022/sd-angular-core-services-notify.mjs +2 -2
- package/fesm2022/sd-angular-core-services-notify.mjs.map +1 -1
- package/fesm2022/sd-angular-core-services.mjs +1 -0
- package/fesm2022/sd-angular-core-services.mjs.map +1 -1
- package/fesm2022/sd-angular-core-utilities-extensions.mjs +58 -80
- package/fesm2022/sd-angular-core-utilities-extensions.mjs.map +1 -1
- package/fesm2022/sd-angular-core-utilities-models.mjs +15 -1
- package/fesm2022/sd-angular-core-utilities-models.mjs.map +1 -1
- package/fesm2022/sd-angular-core.mjs +0 -1
- package/fesm2022/sd-angular-core.mjs.map +1 -1
- package/forms/autocomplete/src/autocomplete.component.d.ts +55 -55
- package/forms/chip/src/chip.component.d.ts +37 -40
- package/forms/chip-calendar/src/chip-calendar.component.d.ts +37 -38
- package/forms/date/src/date.component.d.ts +48 -46
- package/forms/date-range/src/date-range.component.d.ts +35 -34
- package/forms/datetime/src/datetime.component.d.ts +48 -49
- package/forms/input/src/input.component.d.ts +54 -57
- package/forms/input-number/src/input-number.component.d.ts +53 -54
- package/forms/select/src/select.component.d.ts +67 -64
- package/forms/textarea/src/textarea.component.d.ts +40 -43
- package/modules/authom/authom.configuration.d.ts +17 -0
- package/modules/authom/authom.interceptor.d.ts +3 -0
- package/modules/authom/authom.module.d.ts +16 -0
- package/modules/authom/authom.service.d.ts +32 -0
- package/modules/authom/index.d.ts +35 -0
- package/modules/index.d.ts +2 -1
- package/modules/keycloak/index.d.ts +4 -0
- package/modules/keycloak/keycloak.configuration.d.ts +11 -0
- package/modules/keycloak/keycloak.interceptor.d.ts +2 -0
- package/modules/keycloak/keycloak.module.d.ts +18 -0
- package/modules/keycloak/keycloak.service.d.ts +14 -0
- package/modules/layout/components/index.d.ts +2 -0
- package/modules/layout/components/layout-main/layout-main.component.d.ts +8 -12
- package/modules/layout/components/page/page.component.d.ts +5 -7
- package/modules/layout/components/sidebar-mobile-v1/components/sidebar/sidebar.component.d.ts +35 -0
- package/modules/layout/components/sidebar-mobile-v1/components/user/user.component.d.ts +24 -0
- package/modules/layout/components/sidebar-mobile-v1/main.component.d.ts +21 -0
- package/modules/layout/components/sidebar-v1/components/sidebar/sidebar.component.d.ts +22 -29
- package/modules/layout/components/sidebar-v1/components/user/user.component.d.ts +11 -17
- package/modules/layout/components/sidebar-v1/main.component.d.ts +14 -14
- package/modules/layout/configurations/layout.configuration.d.ts +46 -3
- package/modules/layout/modules/forbidden/pages/root/root.component.d.ts +3 -8
- package/modules/layout/modules/home/components/home-page/home-page.component.d.ts +2 -5
- package/modules/layout/modules/not-found/pages/root/root.component.d.ts +3 -8
- package/modules/layout/pipes/high-light-search.pipe.d.ts +1 -1
- package/modules/layout/services/index.d.ts +1 -0
- package/modules/layout/services/layout.service.d.ts +10 -0
- package/modules/layout/services/menu/menu.model.d.ts +4 -1
- package/modules/layout/services/storage/storage.service.d.ts +0 -3
- package/modules/permission/src/configurations/permission.configuration.d.ts +56 -2
- package/modules/permission/src/directives/permission.directive.d.ts +5 -8
- package/modules/permission/src/guards/permission.guard.d.ts +2 -1
- package/modules/permission/src/services/permission.service.d.ts +6 -9
- package/package.json +93 -69
- package/public-api.d.ts +0 -1
- package/sd-angular-core-19.0.0-beta.80.tgz +0 -0
- package/services/api/src/api.model.d.ts +6 -1
- package/services/confirm/src/lib/confirm.service.d.ts +5 -0
- package/services/docx/index.d.ts +1 -0
- package/services/docx/src/lib/docx.model.d.ts +9 -0
- package/services/docx/src/lib/docx.service.d.ts +13 -0
- package/services/docx/src/public-api.d.ts +2 -0
- package/services/index.d.ts +1 -0
- package/services/notify/index.d.ts +1 -0
- package/services/notify/src/notify.model.d.ts +1 -1
- package/services/notify/src/notify.service.d.ts +5 -5
- package/utilities/extensions/src/string.extension.d.ts +3 -0
- package/utilities/extensions/src/utility.extension.d.ts +1 -0
- package/utilities/models/index.d.ts +3 -0
- package/utilities/models/src/filter.model.d.ts +17 -4
- package/utilities/models/src/icon.model.d.ts +2 -0
- package/utilities/models/src/nested-key-of.model.d.ts +5 -0
- package/utilities/models/src/order.model.d.ts +2 -1
- package/utilities/models/src/paging.model.d.ts +2 -1
- package/utilities/models/src/pattern.model.d.ts +1 -1
- package/utilities/models/src/unwrap-signal.model.d.ts +6 -0
- package/components/document-builder/src/plugins/comment/comment.plugin.d.ts +0 -4
- package/components/document-builder/src/plugins/table-fit/table-fit.plugin.d.ts +0 -4
- package/components/modal/src/modal/modal.component.d.ts +0 -31
- package/components/table/src/components/desktop-cell-view/desktop-cell-view.component.d.ts +0 -14
- package/fesm2022/sd-angular-core-guards-permission.mjs +0 -155
- package/fesm2022/sd-angular-core-guards-permission.mjs.map +0 -1
- package/fesm2022/sd-angular-core-guards.mjs +0 -6
- package/fesm2022/sd-angular-core-guards.mjs.map +0 -1
- package/fesm2022/sd-angular-core-modules-oidc.mjs +0 -127
- package/fesm2022/sd-angular-core-modules-oidc.mjs.map +0 -1
- package/guards/index.d.ts +0 -1
- package/guards/permission/index.d.ts +0 -4
- package/guards/permission/src/configurations/index.d.ts +0 -1
- package/guards/permission/src/configurations/permission.configuration.d.ts +0 -8
- package/guards/permission/src/directives/index.d.ts +0 -1
- package/guards/permission/src/directives/permission.directive.d.ts +0 -12
- package/guards/permission/src/guards/index.d.ts +0 -1
- package/guards/permission/src/guards/permission.guard.d.ts +0 -13
- package/guards/permission/src/services/index.d.ts +0 -1
- package/guards/permission/src/services/permission.service.d.ts +0 -15
- package/modules/oidc/dynamic-sts.loader.d.ts +0 -11
- package/modules/oidc/index.d.ts +0 -2
- package/modules/oidc/oidc.configuration.d.ts +0 -11
- package/modules/oidc/oidc.module.d.ts +0 -14
- package/sd-angular-core-19.0.0-beta.8.tgz +0 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { EventEmitter, forwardRef, Input, Output, HostBinding, Component } from '@angular/core';
|
|
4
|
+
import * as i1 from '@ckeditor/ckeditor5-angular';
|
|
5
|
+
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
|
|
6
|
+
import { ClassicEditor, Essentials, FontColor, Paragraph, Bold, Italic, Underline, Link, List, Undo, Widget, Markdown, Mention } from 'ckeditor5';
|
|
7
|
+
import { Subscription, Subject } from 'rxjs';
|
|
8
|
+
import { throttleTime } from 'rxjs/operators';
|
|
9
|
+
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Component sd-mini-editor - Editor đơn giản cho comment input
|
|
13
|
+
* Sử dụng CKEditor với chế độ đơn giản (bold, italic, link)
|
|
14
|
+
* Hỗ trợ mention và output format (html/markdown)
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```html
|
|
18
|
+
* <sd-mini-editor
|
|
19
|
+
* [option]="editorOption"
|
|
20
|
+
* [(ngModel)]="content"
|
|
21
|
+
* (contentChange)="onContentChange($event)"
|
|
22
|
+
* >
|
|
23
|
+
* </sd-mini-editor>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
class SdMiniEditor {
|
|
27
|
+
/** Cấu hình option cho editor */
|
|
28
|
+
option;
|
|
29
|
+
get maxEditorHeight() {
|
|
30
|
+
return this.option?.maxHeight;
|
|
31
|
+
}
|
|
32
|
+
/** NgModel binding - nội dung HTML/Markdown */
|
|
33
|
+
value = '';
|
|
34
|
+
valueChange = new EventEmitter();
|
|
35
|
+
/** Event emitter khi content thay đổi */
|
|
36
|
+
contentChange = new EventEmitter();
|
|
37
|
+
/** Event emitter khi blur */
|
|
38
|
+
blur = new EventEmitter();
|
|
39
|
+
/** Event emitter khi focus */
|
|
40
|
+
focus = new EventEmitter();
|
|
41
|
+
/** Disabled state */
|
|
42
|
+
disabled = false;
|
|
43
|
+
Editor = ClassicEditor;
|
|
44
|
+
#editor;
|
|
45
|
+
#subscription = new Subscription();
|
|
46
|
+
#contentChangeSubject = new Subject();
|
|
47
|
+
// Build editor config dynamically
|
|
48
|
+
get editorConfig() {
|
|
49
|
+
const enableMention = this.option?.enableMention ?? false;
|
|
50
|
+
const useMarkdown = this.option?.outputFormat === 'markdown';
|
|
51
|
+
const plugins = [Essentials, FontColor, Paragraph, Bold, Italic, Underline, Link, List, Undo, Widget];
|
|
52
|
+
// Add Markdown plugin if outputFormat is markdown
|
|
53
|
+
if (useMarkdown) {
|
|
54
|
+
plugins.push(Markdown);
|
|
55
|
+
}
|
|
56
|
+
// Add Mention plugin if enabled
|
|
57
|
+
if (enableMention) {
|
|
58
|
+
plugins.push(Mention);
|
|
59
|
+
}
|
|
60
|
+
// Build base config
|
|
61
|
+
const config = {
|
|
62
|
+
licenseKey: 'GPL',
|
|
63
|
+
getOption: () => this.option,
|
|
64
|
+
plugins,
|
|
65
|
+
toolbar: {
|
|
66
|
+
items: ['bold', 'italic', 'underline', '|', 'fontColor', '|', 'bulletedList', 'numberedList', '|', 'link'],
|
|
67
|
+
shouldNotGroupWhenFull: true,
|
|
68
|
+
},
|
|
69
|
+
placeholder: this.option?.placeholder,
|
|
70
|
+
link: {
|
|
71
|
+
addTargetToExternalLinks: true,
|
|
72
|
+
defaultProtocol: 'https://',
|
|
73
|
+
},
|
|
74
|
+
fontColor: {
|
|
75
|
+
columns: 5,
|
|
76
|
+
documentColors: 10,
|
|
77
|
+
colorPicker: { format: 'hex' },
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
// Add mention configuration if enabled
|
|
81
|
+
if (enableMention && this.option?.mentionConfig?.feeds) {
|
|
82
|
+
config.mention = {
|
|
83
|
+
feeds: this.option.mentionConfig.feeds,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return config;
|
|
87
|
+
}
|
|
88
|
+
constructor() {
|
|
89
|
+
// Setup debounce cho content change
|
|
90
|
+
this.#subscription.add(this.#contentChangeSubject.pipe(throttleTime(500, undefined, { leading: true, trailing: true })).subscribe(content => {
|
|
91
|
+
const output = this.#convertOutput(content);
|
|
92
|
+
this.value = output;
|
|
93
|
+
this.#onChange(output);
|
|
94
|
+
this.valueChange.emit(output);
|
|
95
|
+
this.contentChange.emit(output);
|
|
96
|
+
this.option?.onChange?.(output);
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
ngOnDestroy() {
|
|
100
|
+
this.#subscription.unsubscribe();
|
|
101
|
+
this.#editor?.destroy?.();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Kiểm tra có nên enable mention plugin không
|
|
105
|
+
*/
|
|
106
|
+
#shouldEnableMention() {
|
|
107
|
+
return this.option?.enableMention ?? false;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Xử lý khi editor ready
|
|
111
|
+
*/
|
|
112
|
+
onReady(editor) {
|
|
113
|
+
this.#editor = editor;
|
|
114
|
+
// Set initial content
|
|
115
|
+
if (this.value) {
|
|
116
|
+
this.setContent(this.value);
|
|
117
|
+
}
|
|
118
|
+
// Lắng nghe sự kiện thay đổi nội dung
|
|
119
|
+
editor.model.document.on('change:data', () => {
|
|
120
|
+
const content = editor.getData();
|
|
121
|
+
this.#contentChangeSubject.next(content);
|
|
122
|
+
});
|
|
123
|
+
// Lắng nghe focus/blur events
|
|
124
|
+
editor.editing.view.document.on('focus', evt => {
|
|
125
|
+
const domEvent = evt.domEvent;
|
|
126
|
+
this.focus.emit(domEvent);
|
|
127
|
+
this.option?.onFocus?.(domEvent);
|
|
128
|
+
});
|
|
129
|
+
editor.editing.view.document.on('blur', evt => {
|
|
130
|
+
const domEvent = evt.domEvent;
|
|
131
|
+
this.blur.emit(domEvent);
|
|
132
|
+
this.option?.onBlur?.(domEvent);
|
|
133
|
+
});
|
|
134
|
+
// Lắng nghe sự kiện mention được chọn
|
|
135
|
+
if (this.#shouldEnableMention()) {
|
|
136
|
+
editor.commands.get('mention')?.on('execute', (_evt, data) => {
|
|
137
|
+
const mentionData = data[0];
|
|
138
|
+
this.option?.onMentionSelect?.(mentionData.mention);
|
|
139
|
+
// Trigger content change sau khi insert mention
|
|
140
|
+
const content = editor.getData();
|
|
141
|
+
this.#contentChangeSubject.next(content);
|
|
142
|
+
});
|
|
143
|
+
// Custom downcast converter để thay đổi cấu trúc mention HTML
|
|
144
|
+
editor.conversion.for('downcast').attributeToElement({
|
|
145
|
+
model: 'mention',
|
|
146
|
+
view: (mentionData, { writer }) => {
|
|
147
|
+
const data = mentionData;
|
|
148
|
+
const rawId = data?.id || '';
|
|
149
|
+
const marker = rawId[0];
|
|
150
|
+
const cleanId = rawId.slice(1);
|
|
151
|
+
return writer.createAttributeElement('span', {
|
|
152
|
+
class: 'ck-custom-mention',
|
|
153
|
+
'data-id': cleanId,
|
|
154
|
+
'data-marker': marker,
|
|
155
|
+
contenteditable: 'false',
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
converterPriority: 'highest',
|
|
159
|
+
});
|
|
160
|
+
// Xử lý keyboard để xóa mention 1 lần
|
|
161
|
+
editor.editing.view.document.on('keydown', (evt, data) => {
|
|
162
|
+
const keyEvent = data;
|
|
163
|
+
// Delete (46) hoặc Backspace (8)
|
|
164
|
+
if (keyEvent.keyCode === 46 || keyEvent.keyCode === 8) {
|
|
165
|
+
const model = editor.model;
|
|
166
|
+
const selection = model.document.selection;
|
|
167
|
+
const position = selection.getFirstPosition();
|
|
168
|
+
if (!position)
|
|
169
|
+
return;
|
|
170
|
+
// Tìm text node có mention attribute
|
|
171
|
+
const node = position.textNode || position.nodeBefore || position.nodeAfter;
|
|
172
|
+
if (node && node.is('$text')) {
|
|
173
|
+
const mentionAttr = node.getAttribute('mention');
|
|
174
|
+
if (mentionAttr) {
|
|
175
|
+
// Xóa toàn bộ text node chứa mention
|
|
176
|
+
model.change(writer => {
|
|
177
|
+
writer.remove(node);
|
|
178
|
+
});
|
|
179
|
+
evt.stop();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Convert output theo format (html hoặc markdown)
|
|
188
|
+
* Khi sử dụng CKEditor Markdown plugin, getData() tự động trả về Markdown
|
|
189
|
+
*/
|
|
190
|
+
#convertOutput(content) {
|
|
191
|
+
// CKEditor Markdown plugin tự động xử lý conversion
|
|
192
|
+
// Không cần manual conversion nữa
|
|
193
|
+
return content;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Set nội dung cho editor
|
|
197
|
+
*/
|
|
198
|
+
setContent(content) {
|
|
199
|
+
this.#editor?.setData?.(content);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Get nội dung từ editor
|
|
203
|
+
*/
|
|
204
|
+
getContent() {
|
|
205
|
+
if (this.#editor) {
|
|
206
|
+
const html = this.#editor.getData();
|
|
207
|
+
return this.#convertOutput(html);
|
|
208
|
+
}
|
|
209
|
+
return '';
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Get nội dung HTML gốc (không convert)
|
|
213
|
+
*/
|
|
214
|
+
getHtmlContent() {
|
|
215
|
+
return this.#editor?.getData?.() || '';
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Focus vào editor
|
|
219
|
+
*/
|
|
220
|
+
focusEditor() {
|
|
221
|
+
this.#editor?.editing?.view?.focus?.();
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Insert mention vào vị trí con trỏ hiện tại
|
|
225
|
+
*/
|
|
226
|
+
insertMention(item) {
|
|
227
|
+
if (!this.#editor)
|
|
228
|
+
return;
|
|
229
|
+
const firstFeed = this.option?.mentionConfig?.feeds?.[0];
|
|
230
|
+
const marker = item.marker || firstFeed?.marker || '@';
|
|
231
|
+
// Sử dụng CKEditor mention command
|
|
232
|
+
this.#editor.execute('mention', {
|
|
233
|
+
marker,
|
|
234
|
+
mention: {
|
|
235
|
+
id: item.id,
|
|
236
|
+
text: `${marker}${item.name}`,
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get danh sách mentions trong nội dung
|
|
242
|
+
*/
|
|
243
|
+
getMentions() {
|
|
244
|
+
if (!this.#editor)
|
|
245
|
+
return [];
|
|
246
|
+
const mentions = [];
|
|
247
|
+
const root = this.#editor.model.document.getRoot();
|
|
248
|
+
if (!root)
|
|
249
|
+
return mentions;
|
|
250
|
+
const range = this.#editor.model.createRangeIn(root);
|
|
251
|
+
for (const item of range.getItems()) {
|
|
252
|
+
if (item.is('$text')) {
|
|
253
|
+
const mentionAttr = item.getAttribute('mention');
|
|
254
|
+
if (mentionAttr) {
|
|
255
|
+
const text = item.data;
|
|
256
|
+
const marker = text.charAt(0);
|
|
257
|
+
const name = text.substring(1);
|
|
258
|
+
const id = item.getAttribute('data-user-id');
|
|
259
|
+
mentions.push({ id, name, marker });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return mentions;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* ControlValueAccessor: Write value
|
|
267
|
+
*/
|
|
268
|
+
writeValue(value) {
|
|
269
|
+
this.value = value || '';
|
|
270
|
+
if (this.#editor) {
|
|
271
|
+
this.setContent(this.value);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* ControlValueAccessor: Register change callback
|
|
276
|
+
*/
|
|
277
|
+
registerOnChange(fn) {
|
|
278
|
+
this.#onChange = fn;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* ControlValueAccessor: Register touched callback
|
|
282
|
+
*/
|
|
283
|
+
registerOnTouched(fn) {
|
|
284
|
+
this.#onTouched = fn;
|
|
285
|
+
}
|
|
286
|
+
/** ControlValueAccessor callbacks */
|
|
287
|
+
#onChange = () => { };
|
|
288
|
+
#onTouched = () => { };
|
|
289
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdMiniEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
290
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: SdMiniEditor, isStandalone: true, selector: "sd-mini-editor", inputs: { option: "option", value: "value", disabled: "disabled" }, outputs: { valueChange: "valueChange", contentChange: "contentChange", blur: "blur", focus: "focus" }, host: { properties: { "style.--sd-mini-editor-max-height": "this.maxEditorHeight" } }, providers: [
|
|
291
|
+
{
|
|
292
|
+
provide: NG_VALUE_ACCESSOR,
|
|
293
|
+
useExisting: forwardRef(() => SdMiniEditor),
|
|
294
|
+
multi: true,
|
|
295
|
+
},
|
|
296
|
+
], ngImport: i0, template: "<ckeditor class=\"sd-mini-editor\" [editor]=\"Editor\" [config]=\"editorConfig\" [disabled]=\"disabled\" (ready)=\"onReady($event)\"> </ckeditor>\r\n", styles: [".sd-mini-editor{display:block}::ng-deep .ck-powered-by-balloon{display:none!important}::ng-deep .ck-mentions .ck-button.ck-on{background:var(--sd-primary)!important;color:#fff!important}::ng-deep .ck-mentions .ck-button.ck-on *{color:#fff!important}:host ::ng-deep .ck-editor{--ck-content-font-size: 14px;--ck-content-line-height: 1.5}:host ::ng-deep .ck-editor__editable_inline{border:var(--ck-focus-ring);border-top-left-radius:0!important;border-top-right-radius:0!important;max-height:var(--sd-mini-editor-max-height);overflow:auto}:host ::ng-deep .ck-toolbar{border-radius:0;border:0!important}:host ::ng-deep .ck-content img{max-width:100%!important;height:auto!important;object-fit:contain}:host ::ng-deep .ck-content p{margin-bottom:var(--ck-spacing-large);text-indent:0}:host ::ng-deep .ck-content ul,:host ::ng-deep .ck-content ol{padding-left:20px!important;margin-left:0!important}:host ::ng-deep .ck-custom-mention{font-weight:600;padding:0 2px;display:inline-block;pointer-events:none;-webkit-user-select:none;user-select:none;color:#2962ff}:host ::ng-deep .ck-custom-mention:before{content:attr(data-marker)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i1.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableWatchdog", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }] });
|
|
297
|
+
}
|
|
298
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdMiniEditor, decorators: [{
|
|
299
|
+
type: Component,
|
|
300
|
+
args: [{ selector: 'sd-mini-editor', standalone: true, imports: [CommonModule, CKEditorModule], providers: [
|
|
301
|
+
{
|
|
302
|
+
provide: NG_VALUE_ACCESSOR,
|
|
303
|
+
useExisting: forwardRef(() => SdMiniEditor),
|
|
304
|
+
multi: true,
|
|
305
|
+
},
|
|
306
|
+
], template: "<ckeditor class=\"sd-mini-editor\" [editor]=\"Editor\" [config]=\"editorConfig\" [disabled]=\"disabled\" (ready)=\"onReady($event)\"> </ckeditor>\r\n", styles: [".sd-mini-editor{display:block}::ng-deep .ck-powered-by-balloon{display:none!important}::ng-deep .ck-mentions .ck-button.ck-on{background:var(--sd-primary)!important;color:#fff!important}::ng-deep .ck-mentions .ck-button.ck-on *{color:#fff!important}:host ::ng-deep .ck-editor{--ck-content-font-size: 14px;--ck-content-line-height: 1.5}:host ::ng-deep .ck-editor__editable_inline{border:var(--ck-focus-ring);border-top-left-radius:0!important;border-top-right-radius:0!important;max-height:var(--sd-mini-editor-max-height);overflow:auto}:host ::ng-deep .ck-toolbar{border-radius:0;border:0!important}:host ::ng-deep .ck-content img{max-width:100%!important;height:auto!important;object-fit:contain}:host ::ng-deep .ck-content p{margin-bottom:var(--ck-spacing-large);text-indent:0}:host ::ng-deep .ck-content ul,:host ::ng-deep .ck-content ol{padding-left:20px!important;margin-left:0!important}:host ::ng-deep .ck-custom-mention{font-weight:600;padding:0 2px;display:inline-block;pointer-events:none;-webkit-user-select:none;user-select:none;color:#2962ff}:host ::ng-deep .ck-custom-mention:before{content:attr(data-marker)}\n"] }]
|
|
307
|
+
}], ctorParameters: () => [], propDecorators: { option: [{
|
|
308
|
+
type: Input,
|
|
309
|
+
args: [{ required: true }]
|
|
310
|
+
}], maxEditorHeight: [{
|
|
311
|
+
type: HostBinding,
|
|
312
|
+
args: ['style.--sd-mini-editor-max-height']
|
|
313
|
+
}], value: [{
|
|
314
|
+
type: Input
|
|
315
|
+
}], valueChange: [{
|
|
316
|
+
type: Output
|
|
317
|
+
}], contentChange: [{
|
|
318
|
+
type: Output
|
|
319
|
+
}], blur: [{
|
|
320
|
+
type: Output
|
|
321
|
+
}], focus: [{
|
|
322
|
+
type: Output
|
|
323
|
+
}], disabled: [{
|
|
324
|
+
type: Input
|
|
325
|
+
}] } });
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Generated bundle index. Do not edit.
|
|
329
|
+
*/
|
|
330
|
+
|
|
331
|
+
export { SdMiniEditor };
|
|
332
|
+
//# sourceMappingURL=sd-angular-core-components-mini-editor.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sd-angular-core-components-mini-editor.mjs","sources":["../../../projects/sd-angular/components/mini-editor/src/mini-editor.component.ts","../../../projects/sd-angular/components/mini-editor/src/mini-editor.component.html","../../../projects/sd-angular/components/mini-editor/sd-angular-core-components-mini-editor.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\r\nimport { Component, EventEmitter, HostBinding, Input, Output, forwardRef } from '@angular/core';\r\nimport { CKEditorModule } from '@ckeditor/ckeditor5-angular';\r\nimport {\r\n Bold,\r\n ClassicEditor,\r\n Essentials,\r\n Italic,\r\n Link,\r\n List,\r\n FontColor,\r\n Markdown,\r\n Mention,\r\n Paragraph,\r\n Underline,\r\n Undo,\r\n Widget,\r\n} from 'ckeditor5';\r\nimport { Subject, Subscription } from 'rxjs';\r\nimport { throttleTime } from 'rxjs/operators';\r\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\r\n\r\nimport { SdMiniEditorOption, SdMiniEditorConfig, SdMiniEditorMentionItem } from './mini-editor.model';\r\n\r\n/**\r\n * Component sd-mini-editor - Editor đơn giản cho comment input\r\n * Sử dụng CKEditor với chế độ đơn giản (bold, italic, link)\r\n * Hỗ trợ mention và output format (html/markdown)\r\n *\r\n * @example\r\n * ```html\r\n * <sd-mini-editor\r\n * [option]=\"editorOption\"\r\n * [(ngModel)]=\"content\"\r\n * (contentChange)=\"onContentChange($event)\"\r\n * >\r\n * </sd-mini-editor>\r\n * ```\r\n */\r\n@Component({\r\n selector: 'sd-mini-editor',\r\n standalone: true,\r\n imports: [CommonModule, CKEditorModule],\r\n templateUrl: './mini-editor.component.html',\r\n styleUrls: ['./mini-editor.component.scss'],\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => SdMiniEditor),\r\n multi: true,\r\n },\r\n ],\r\n})\r\nexport class SdMiniEditor implements ControlValueAccessor {\r\n /** Cấu hình option cho editor */\r\n @Input({ required: true }) option!: SdMiniEditorOption;\r\n\r\n @HostBinding('style.--sd-mini-editor-max-height')\r\n get maxEditorHeight(): string | undefined {\r\n return this.option?.maxHeight;\r\n }\r\n\r\n /** NgModel binding - nội dung HTML/Markdown */\r\n @Input() value = '';\r\n @Output() valueChange = new EventEmitter<string>();\r\n\r\n /** Event emitter khi content thay đổi */\r\n @Output() contentChange = new EventEmitter<string>();\r\n\r\n /** Event emitter khi blur */\r\n @Output() blur = new EventEmitter<FocusEvent>();\r\n\r\n /** Event emitter khi focus */\r\n @Output() focus = new EventEmitter<FocusEvent>();\r\n\r\n /** Disabled state */\r\n @Input() disabled = false;\r\n\r\n Editor = ClassicEditor;\r\n #editor!: ClassicEditor;\r\n #subscription = new Subscription();\r\n #contentChangeSubject = new Subject<string>();\r\n\r\n // Build editor config dynamically\r\n get editorConfig(): SdMiniEditorConfig {\r\n const enableMention = this.option?.enableMention ?? false;\r\n const useMarkdown = this.option?.outputFormat === 'markdown';\r\n const plugins: any[] = [Essentials, FontColor, Paragraph, Bold, Italic, Underline, Link, List, Undo, Widget];\r\n\r\n // Add Markdown plugin if outputFormat is markdown\r\n if (useMarkdown) {\r\n plugins.push(Markdown);\r\n }\r\n\r\n // Add Mention plugin if enabled\r\n if (enableMention) {\r\n plugins.push(Mention);\r\n }\r\n\r\n // Build base config\r\n const config: SdMiniEditorConfig = {\r\n licenseKey: 'GPL',\r\n getOption: () => this.option,\r\n plugins,\r\n toolbar: {\r\n items: ['bold', 'italic', 'underline', '|', 'fontColor', '|', 'bulletedList', 'numberedList', '|', 'link'],\r\n shouldNotGroupWhenFull: true,\r\n },\r\n placeholder: this.option?.placeholder,\r\n link: {\r\n addTargetToExternalLinks: true,\r\n defaultProtocol: 'https://',\r\n },\r\n fontColor: {\r\n columns: 5,\r\n documentColors: 10,\r\n colorPicker: { format: 'hex' },\r\n },\r\n };\r\n\r\n // Add mention configuration if enabled\r\n if (enableMention && this.option?.mentionConfig?.feeds) {\r\n config.mention = {\r\n feeds: this.option.mentionConfig.feeds,\r\n };\r\n }\r\n\r\n return config;\r\n }\r\n\r\n constructor() {\r\n // Setup debounce cho content change\r\n this.#subscription.add(\r\n this.#contentChangeSubject.pipe(throttleTime(500, undefined, { leading: true, trailing: true })).subscribe(content => {\r\n const output = this.#convertOutput(content);\r\n this.value = output;\r\n this.#onChange(output);\r\n this.valueChange.emit(output);\r\n this.contentChange.emit(output);\r\n this.option?.onChange?.(output);\r\n })\r\n );\r\n }\r\n\r\n ngOnDestroy() {\r\n this.#subscription.unsubscribe();\r\n this.#editor?.destroy?.();\r\n }\r\n\r\n /**\r\n * Kiểm tra có nên enable mention plugin không\r\n */\r\n #shouldEnableMention(): boolean {\r\n return this.option?.enableMention ?? false;\r\n }\r\n\r\n /**\r\n * Xử lý khi editor ready\r\n */\r\n onReady(editor: ClassicEditor) {\r\n this.#editor = editor;\r\n\r\n // Set initial content\r\n if (this.value) {\r\n this.setContent(this.value);\r\n }\r\n\r\n // Lắng nghe sự kiện thay đổi nội dung\r\n editor.model.document.on('change:data', () => {\r\n const content = editor.getData();\r\n this.#contentChangeSubject.next(content);\r\n });\r\n\r\n // Lắng nghe focus/blur events\r\n editor.editing.view.document.on('focus', evt => {\r\n const domEvent = (evt as any).domEvent as FocusEvent;\r\n this.focus.emit(domEvent);\r\n this.option?.onFocus?.(domEvent);\r\n });\r\n\r\n editor.editing.view.document.on('blur', evt => {\r\n const domEvent = (evt as any).domEvent as FocusEvent;\r\n this.blur.emit(domEvent);\r\n this.option?.onBlur?.(domEvent);\r\n });\r\n\r\n // Lắng nghe sự kiện mention được chọn\r\n if (this.#shouldEnableMention()) {\r\n editor.commands.get('mention')?.on('execute', (_evt, data: any) => {\r\n const mentionData = data[0];\r\n this.option?.onMentionSelect?.(mentionData.mention);\r\n // Trigger content change sau khi insert mention\r\n const content = editor.getData();\r\n this.#contentChangeSubject.next(content);\r\n });\r\n\r\n // Custom downcast converter để thay đổi cấu trúc mention HTML\r\n editor.conversion.for('downcast').attributeToElement({\r\n model: 'mention',\r\n view: (mentionData, { writer }) => {\r\n const data = mentionData as SdMiniEditorMentionItem;\r\n const rawId = data?.id || '';\r\n const marker = rawId[0];\r\n const cleanId = rawId.slice(1);\r\n\r\n return writer.createAttributeElement('span', {\r\n class: 'ck-custom-mention',\r\n 'data-id': cleanId,\r\n 'data-marker': marker,\r\n contenteditable: 'false',\r\n });\r\n },\r\n converterPriority: 'highest',\r\n });\r\n\r\n // Xử lý keyboard để xóa mention 1 lần\r\n editor.editing.view.document.on('keydown', (evt, data) => {\r\n const keyEvent = data as { keyCode: number; domEvent: KeyboardEvent };\r\n // Delete (46) hoặc Backspace (8)\r\n if (keyEvent.keyCode === 46 || keyEvent.keyCode === 8) {\r\n const model = editor.model;\r\n const selection = model.document.selection;\r\n const position = selection.getFirstPosition();\r\n if (!position) return;\r\n\r\n // Tìm text node có mention attribute\r\n const node = position.textNode || position.nodeBefore || position.nodeAfter;\r\n if (node && node.is('$text')) {\r\n const mentionAttr = node.getAttribute('mention');\r\n if (mentionAttr) {\r\n // Xóa toàn bộ text node chứa mention\r\n model.change(writer => {\r\n writer.remove(node);\r\n });\r\n evt.stop();\r\n }\r\n }\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Convert output theo format (html hoặc markdown)\r\n * Khi sử dụng CKEditor Markdown plugin, getData() tự động trả về Markdown\r\n */\r\n #convertOutput(content: string): string {\r\n // CKEditor Markdown plugin tự động xử lý conversion\r\n // Không cần manual conversion nữa\r\n return content;\r\n }\r\n\r\n /**\r\n * Set nội dung cho editor\r\n */\r\n setContent(content: string) {\r\n this.#editor?.setData?.(content);\r\n }\r\n\r\n /**\r\n * Get nội dung từ editor\r\n */\r\n getContent(): string {\r\n if (this.#editor) {\r\n const html = this.#editor.getData();\r\n return this.#convertOutput(html);\r\n }\r\n return '';\r\n }\r\n\r\n /**\r\n * Get nội dung HTML gốc (không convert)\r\n */\r\n getHtmlContent(): string {\r\n return this.#editor?.getData?.() || '';\r\n }\r\n\r\n /**\r\n * Focus vào editor\r\n */\r\n focusEditor() {\r\n this.#editor?.editing?.view?.focus?.();\r\n }\r\n\r\n /**\r\n * Insert mention vào vị trí con trỏ hiện tại\r\n */\r\n insertMention(item: { id: string; name: string; marker?: string }) {\r\n if (!this.#editor) return;\r\n\r\n const firstFeed = this.option?.mentionConfig?.feeds?.[0];\r\n const marker = item.marker || (firstFeed as any)?.marker || '@';\r\n\r\n // Sử dụng CKEditor mention command\r\n this.#editor.execute('mention', {\r\n marker,\r\n mention: {\r\n id: item.id,\r\n text: `${marker}${item.name}`,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Get danh sách mentions trong nội dung\r\n */\r\n getMentions(): Array<{ id: string; name: string; marker: string }> {\r\n if (!this.#editor) return [];\r\n\r\n const mentions: Array<{ id: string; name: string; marker: string }> = [];\r\n const root = this.#editor.model.document.getRoot();\r\n if (!root) return mentions;\r\n\r\n const range = this.#editor.model.createRangeIn(root);\r\n\r\n for (const item of range.getItems()) {\r\n if (item.is('$text')) {\r\n const mentionAttr = item.getAttribute('mention');\r\n if (mentionAttr) {\r\n const text = (item as any).data as string;\r\n const marker = text.charAt(0);\r\n const name = text.substring(1);\r\n const id = item.getAttribute('data-user-id') as string;\r\n\r\n mentions.push({ id, name, marker });\r\n }\r\n }\r\n }\r\n\r\n return mentions;\r\n }\r\n\r\n /**\r\n * ControlValueAccessor: Write value\r\n */\r\n writeValue(value: string): void {\r\n this.value = value || '';\r\n if (this.#editor) {\r\n this.setContent(this.value);\r\n }\r\n }\r\n\r\n /**\r\n * ControlValueAccessor: Register change callback\r\n */\r\n registerOnChange(fn: (value: string) => void): void {\r\n this.#onChange = fn;\r\n }\r\n\r\n /**\r\n * ControlValueAccessor: Register touched callback\r\n */\r\n registerOnTouched(fn: () => void): void {\r\n this.#onTouched = fn;\r\n }\r\n\r\n /** ControlValueAccessor callbacks */\r\n #onChange: (value: string) => void = () => {};\r\n #onTouched: () => void = () => {};\r\n}\r\n","<ckeditor class=\"sd-mini-editor\" [editor]=\"Editor\" [config]=\"editorConfig\" [disabled]=\"disabled\" (ready)=\"onReady($event)\"> </ckeditor>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,127 +1,98 @@
|
|
|
1
1
|
import { CommonModule } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
|
3
|
+
import { signal, viewChild, input, booleanAttribute, output, inject, DestroyRef, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
4
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
+
import { MatBottomSheet, MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
|
6
6
|
import { MatButtonModule } from '@angular/material/button';
|
|
7
|
-
import
|
|
8
|
-
import { MatDialogModule } from '@angular/material/dialog';
|
|
7
|
+
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
|
9
8
|
import { MatDividerModule } from '@angular/material/divider';
|
|
10
|
-
import * as
|
|
9
|
+
import * as i1 from '@angular/material/icon';
|
|
11
10
|
import { MatIconModule } from '@angular/material/icon';
|
|
12
11
|
import { SdUtilities } from '@sd-angular/core/utilities';
|
|
13
|
-
import { Subscription } from 'rxjs';
|
|
14
12
|
|
|
15
13
|
class SdModal {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
isOpened = false;
|
|
30
|
-
alreadyOpened = false;
|
|
14
|
+
static index = signal(0);
|
|
15
|
+
templateRef = viewChild.required('templateRef');
|
|
16
|
+
modal = viewChild('modal');
|
|
17
|
+
title = input('', { transform: (v) => v ?? '' });
|
|
18
|
+
color = input('primary', { transform: (v) => v ?? 'primary' });
|
|
19
|
+
width = input('md', { transform: (v) => v ?? 'md' });
|
|
20
|
+
height = input('auto', { transform: (v) => v ?? 'auto' });
|
|
21
|
+
view = input(undefined, { transform: (v) => v ?? undefined });
|
|
22
|
+
modalClass = input('', { transform: (v) => v ?? '' });
|
|
23
|
+
lazyLoadContent = input(true, { transform: booleanAttribute });
|
|
24
|
+
hideClose = input(false, { transform: booleanAttribute });
|
|
25
|
+
disableBackdropClose = input(true, { transform: booleanAttribute }); // default to true to keep backward compatibility
|
|
26
|
+
sdClosed = output();
|
|
27
|
+
isOpened = signal(false);
|
|
28
|
+
alreadyOpened = signal(false);
|
|
31
29
|
#isMobile = false;
|
|
30
|
+
#resolvedWidth = 'md';
|
|
32
31
|
#bottomSheetRef;
|
|
33
32
|
#dialogRef;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
this.bottomSheet = bottomSheet;
|
|
33
|
+
#dialog = inject(MatDialog);
|
|
34
|
+
#bottomSheet = inject(MatBottomSheet);
|
|
35
|
+
#destroyRef = inject(DestroyRef);
|
|
36
|
+
constructor() {
|
|
39
37
|
this.#isMobile = SdUtilities.isMobile();
|
|
40
38
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
case 'sm':
|
|
52
|
-
this.width = '40vw';
|
|
53
|
-
break;
|
|
54
|
-
case 'sx':
|
|
55
|
-
this.width = '20vw';
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
39
|
+
#resolveWidth() {
|
|
40
|
+
const w = this.width() || '80vw';
|
|
41
|
+
if (this.#isMobile)
|
|
42
|
+
return w;
|
|
43
|
+
switch (w) {
|
|
44
|
+
case 'lg': return '80vw';
|
|
45
|
+
case 'md': return '60vw';
|
|
46
|
+
case 'sm': return '40vw';
|
|
47
|
+
case 'sx': return '20vw';
|
|
48
|
+
default: return w;
|
|
58
49
|
}
|
|
59
50
|
}
|
|
60
|
-
ngOnDestroy() {
|
|
61
|
-
this.subcription.unsubscribe();
|
|
62
|
-
}
|
|
63
51
|
open = () => {
|
|
64
|
-
if (this.isOpened) {
|
|
52
|
+
if (this.isOpened()) {
|
|
65
53
|
return;
|
|
66
54
|
}
|
|
67
|
-
this.
|
|
68
|
-
this.
|
|
69
|
-
this
|
|
70
|
-
if ((!this.view && this.#isMobile) || this.view === 'bottom-sheet') {
|
|
71
|
-
this.#bottomSheetRef = this
|
|
72
|
-
|
|
73
|
-
this.
|
|
55
|
+
this.alreadyOpened.set(true);
|
|
56
|
+
this.isOpened.set(true);
|
|
57
|
+
this.#resolvedWidth = this.#resolveWidth();
|
|
58
|
+
if ((!this.view() && this.#isMobile) || this.view() === 'bottom-sheet') {
|
|
59
|
+
this.#bottomSheetRef = this.#bottomSheet.open(this.templateRef(), {
|
|
60
|
+
panelClass: this.modalClass(),
|
|
61
|
+
disableClose: this.disableBackdropClose()
|
|
62
|
+
});
|
|
63
|
+
this.#bottomSheetRef.afterDismissed()
|
|
64
|
+
.pipe(takeUntilDestroyed(this.#destroyRef))
|
|
65
|
+
.subscribe(() => {
|
|
66
|
+
this.isOpened.set(false);
|
|
74
67
|
this.sdClosed.emit();
|
|
75
|
-
})
|
|
68
|
+
});
|
|
76
69
|
}
|
|
77
70
|
else {
|
|
78
|
-
this.#dialogRef = this
|
|
79
|
-
width: this
|
|
80
|
-
maxWidth: this
|
|
81
|
-
|
|
71
|
+
this.#dialogRef = this.#dialog.open(this.templateRef(), {
|
|
72
|
+
width: this.#resolvedWidth,
|
|
73
|
+
maxWidth: this.#resolvedWidth,
|
|
74
|
+
panelClass: this.modalClass(),
|
|
75
|
+
disableClose: this.disableBackdropClose(),
|
|
82
76
|
});
|
|
83
|
-
this
|
|
84
|
-
this
|
|
77
|
+
this.#dialogRef.afterClosed()
|
|
78
|
+
.pipe(takeUntilDestroyed(this.#destroyRef))
|
|
79
|
+
.subscribe(() => {
|
|
80
|
+
this.isOpened.set(false);
|
|
85
81
|
this.sdClosed.emit();
|
|
86
|
-
})
|
|
82
|
+
});
|
|
87
83
|
}
|
|
88
84
|
};
|
|
89
85
|
close = () => {
|
|
90
|
-
this.ref.markForCheck();
|
|
91
86
|
this.#bottomSheetRef?.dismiss();
|
|
92
87
|
this.#dialogRef?.close();
|
|
93
88
|
};
|
|
94
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdModal, deps: [
|
|
95
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdModal, isStandalone: true, selector: "sd-modal", inputs: { title: "title", color: "color", width: "width", height: "height", view: "view", lazyLoadContent: "lazyLoadContent" }, outputs: { sdClosed: "sdClosed" }, viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["templateRef"], descendants: true }, { propertyName: "modal", first: true, predicate: ["modal"], descendants: true }], ngImport: i0, template: "<ng-template #templateRef>\r\n @if (!lazyLoadContent || alreadyOpened) {\r\n <!-- Header -->\r\n <!-- D\u00F9ng scss thu\u1EA7n -->\r\n @if (title) {\r\n <div class=\"d-flex align-items-center p-16\">\r\n <div class=\"T18M\">{{ title }}</div>\r\n <div class=\"d-flex align-items-center ml-auto\">\r\n <ng-content select=\"[sdHeader]\"></ng-content>\r\n <mat-icon class=\"text-secondary pointer\" fontIcon=\"close\" (click)=\"close()\"></mat-icon>\r\n </div>\r\n </div>\r\n }\r\n <!-- <mat-divider></mat-divider> -->\r\n <!-- Body -->\r\n <div class=\"overflow-auto w-full px-16\" style=\"max-height: 80vh
|
|
89
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdModal, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
90
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdModal, isStandalone: true, selector: "sd-modal", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, modalClass: { classPropertyName: "modalClass", publicName: "modalClass", isSignal: true, isRequired: false, transformFunction: null }, lazyLoadContent: { classPropertyName: "lazyLoadContent", publicName: "lazyLoadContent", isSignal: true, isRequired: false, transformFunction: null }, hideClose: { classPropertyName: "hideClose", publicName: "hideClose", isSignal: true, isRequired: false, transformFunction: null }, disableBackdropClose: { classPropertyName: "disableBackdropClose", publicName: "disableBackdropClose", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sdClosed: "sdClosed" }, viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["templateRef"], descendants: true, isSignal: true }, { propertyName: "modal", first: true, predicate: ["modal"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #templateRef>\r\n @if (!lazyLoadContent() || alreadyOpened()) {\r\n <!-- Header -->\r\n <!-- D\u00F9ng scss thu\u1EA7n -->\r\n @if (title()) {\r\n <div class=\"d-flex align-items-center p-16\">\r\n <ng-content select=\"[sdHeaderLeft]\">\r\n <div class=\"T18M\">{{ title() }}</div>\r\n </ng-content>\r\n <div class=\"d-flex align-items-center ml-auto\">\r\n <ng-content select=\"[sdHeaderRight]\"></ng-content>\r\n <ng-content select=\"[sdHeader]\"></ng-content>\r\n @if (!hideClose()) {\r\n <mat-icon class=\"text-secondary pointer\" fontIcon=\"close\" (click)=\"close()\"></mat-icon>\r\n }\r\n </div>\r\n </div>\r\n }\r\n <!-- <mat-divider></mat-divider> -->\r\n <!-- Body -->\r\n <div class=\"overflow-auto w-full px-16\" style=\"max-height: 80vh\">\r\n <ng-content></ng-content>\r\n </div>\r\n <!-- Footer -->\r\n <!-- <mat-divider></mat-divider> -->\r\n <div class=\"d-flex align-items-center p-8\" #footer>\r\n <ng-content select=\"[sdFooterLeft]\"></ng-content>\r\n <div class=\"ml-auto\">\r\n <ng-content select=\"[sdFooterRight]\"></ng-content>\r\n <ng-content select=\"[sdFooter]\"></ng-content>\r\n </div>\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n<!-- <ng-template #templateRef>\r\n @if(!lazyLoadContent || alreadyOpened) {\r\n <sd-modal-header *ngIf=\"title\">\r\n <span [innerHtml]=\"title\"></span>\r\n <div class=\"d-flex align-items-center\">\r\n <ng-content select=\"[sdModalHeaderRight]\"></ng-content>\r\n <button type=\"button\" (click)=\"close()\" mat-icon-button>\r\n <mat-icon fontIcon=\"close\"></mat-icon>\r\n </button>\r\n </div>\r\n </sd-modal-header>\r\n }\r\n <ng-container *ngIf=\"!lazyLoadContent || alreadyOpened\">\r\n <sd-modal-header *ngIf=\"title\">\r\n <span [innerHtml]=\"title\"></span>\r\n <div class=\"d-flex align-items-center\">\r\n <ng-content select=\"[sdModalHeaderRight]\"></ng-content>\r\n <button type=\"button\" (click)=\"close()\" mat-icon-button>\r\n <mat-icon fontIcon=\"close\"></mat-icon>\r\n </button>\r\n </div>\r\n </sd-modal-header>\r\n <div class=\"d-flex flex-column px-12 px-md-24 pb-6 overflow-auto w-full mh-full\">\r\n <ng-content></ng-content>\r\n </div>\r\n </ng-container>\r\n</ng-template> -->\r\n", styles: ["button:focus{outline:none!important}.mat-dialog-container{padding:0!important}.mat-dialog-container .mat-dialog-content{max-height:80vh}.mat-dialog-container .mat-dialog-actions{min-height:auto;margin-bottom:0;padding:0}.mat-bottom-sheet-container{max-height:\"inherit\"}sd-modal-header{padding:12px 24px;display:block;width:100%}@media(max-width:640px){sd-modal-header{padding:12px}}.cdk-global-overlay-wrapper .mat-bottom-sheet-container{padding:0;min-width:100vw;box-sizing:border-box;outline:0;max-height:80vh;overflow:hidden;border-top-left-radius:4px;border-top-right-radius:4px;display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatBottomSheetModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatButtonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
96
91
|
}
|
|
97
92
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdModal, decorators: [{
|
|
98
93
|
type: Component,
|
|
99
|
-
args: [{ selector: 'sd-modal', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, MatIconModule, MatBottomSheetModule, MatDialogModule, MatDividerModule, MatButtonModule], template: "<ng-template #templateRef>\r\n @if (!lazyLoadContent || alreadyOpened) {\r\n <!-- Header -->\r\n <!-- D\u00F9ng scss thu\u1EA7n -->\r\n @if (title) {\r\n <div class=\"d-flex align-items-center p-16\">\r\n <div class=\"T18M\">{{ title }}</div>\r\n <div class=\"d-flex align-items-center ml-auto\">\r\n <ng-content select=\"[sdHeader]\"></ng-content>\r\n <mat-icon class=\"text-secondary pointer\" fontIcon=\"close\" (click)=\"close()\"></mat-icon>\r\n </div>\r\n </div>\r\n }\r\n <!-- <mat-divider></mat-divider> -->\r\n <!-- Body -->\r\n <div class=\"overflow-auto w-full px-16\" style=\"max-height: 80vh
|
|
100
|
-
}], ctorParameters: () => [
|
|
101
|
-
type: ViewChild,
|
|
102
|
-
args: ['templateRef']
|
|
103
|
-
}], title: [{
|
|
104
|
-
type: Input
|
|
105
|
-
}], color: [{
|
|
106
|
-
type: Input
|
|
107
|
-
}], width: [{
|
|
108
|
-
type: Input
|
|
109
|
-
}], height: [{
|
|
110
|
-
type: Input
|
|
111
|
-
}], view: [{
|
|
112
|
-
type: Input
|
|
113
|
-
}], lazyLoadContent: [{
|
|
114
|
-
type: Input
|
|
115
|
-
}], sdClosed: [{
|
|
116
|
-
type: Output
|
|
117
|
-
}], modal: [{
|
|
118
|
-
type: ViewChild,
|
|
119
|
-
args: ['modal']
|
|
120
|
-
}] } });
|
|
121
|
-
|
|
122
|
-
// export * from './src/modal/modal-header/modal-header.component';
|
|
123
|
-
// export * from './src/modal/modal-body/modal-body.component';
|
|
124
|
-
// export * from './src/modal/modal-footer/modal-footer.component';
|
|
94
|
+
args: [{ selector: 'sd-modal', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, MatIconModule, MatBottomSheetModule, MatDialogModule, MatDividerModule, MatButtonModule], template: "<ng-template #templateRef>\r\n @if (!lazyLoadContent() || alreadyOpened()) {\r\n <!-- Header -->\r\n <!-- D\u00F9ng scss thu\u1EA7n -->\r\n @if (title()) {\r\n <div class=\"d-flex align-items-center p-16\">\r\n <ng-content select=\"[sdHeaderLeft]\">\r\n <div class=\"T18M\">{{ title() }}</div>\r\n </ng-content>\r\n <div class=\"d-flex align-items-center ml-auto\">\r\n <ng-content select=\"[sdHeaderRight]\"></ng-content>\r\n <ng-content select=\"[sdHeader]\"></ng-content>\r\n @if (!hideClose()) {\r\n <mat-icon class=\"text-secondary pointer\" fontIcon=\"close\" (click)=\"close()\"></mat-icon>\r\n }\r\n </div>\r\n </div>\r\n }\r\n <!-- <mat-divider></mat-divider> -->\r\n <!-- Body -->\r\n <div class=\"overflow-auto w-full px-16\" style=\"max-height: 80vh\">\r\n <ng-content></ng-content>\r\n </div>\r\n <!-- Footer -->\r\n <!-- <mat-divider></mat-divider> -->\r\n <div class=\"d-flex align-items-center p-8\" #footer>\r\n <ng-content select=\"[sdFooterLeft]\"></ng-content>\r\n <div class=\"ml-auto\">\r\n <ng-content select=\"[sdFooterRight]\"></ng-content>\r\n <ng-content select=\"[sdFooter]\"></ng-content>\r\n </div>\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n<!-- <ng-template #templateRef>\r\n @if(!lazyLoadContent || alreadyOpened) {\r\n <sd-modal-header *ngIf=\"title\">\r\n <span [innerHtml]=\"title\"></span>\r\n <div class=\"d-flex align-items-center\">\r\n <ng-content select=\"[sdModalHeaderRight]\"></ng-content>\r\n <button type=\"button\" (click)=\"close()\" mat-icon-button>\r\n <mat-icon fontIcon=\"close\"></mat-icon>\r\n </button>\r\n </div>\r\n </sd-modal-header>\r\n }\r\n <ng-container *ngIf=\"!lazyLoadContent || alreadyOpened\">\r\n <sd-modal-header *ngIf=\"title\">\r\n <span [innerHtml]=\"title\"></span>\r\n <div class=\"d-flex align-items-center\">\r\n <ng-content select=\"[sdModalHeaderRight]\"></ng-content>\r\n <button type=\"button\" (click)=\"close()\" mat-icon-button>\r\n <mat-icon fontIcon=\"close\"></mat-icon>\r\n </button>\r\n </div>\r\n </sd-modal-header>\r\n <div class=\"d-flex flex-column px-12 px-md-24 pb-6 overflow-auto w-full mh-full\">\r\n <ng-content></ng-content>\r\n </div>\r\n </ng-container>\r\n</ng-template> -->\r\n", styles: ["button:focus{outline:none!important}.mat-dialog-container{padding:0!important}.mat-dialog-container .mat-dialog-content{max-height:80vh}.mat-dialog-container .mat-dialog-actions{min-height:auto;margin-bottom:0;padding:0}.mat-bottom-sheet-container{max-height:\"inherit\"}sd-modal-header{padding:12px 24px;display:block;width:100%}@media(max-width:640px){sd-modal-header{padding:12px}}.cdk-global-overlay-wrapper .mat-bottom-sheet-container{padding:0;min-width:100vw;box-sizing:border-box;outline:0;max-height:80vh;overflow:hidden;border-top-left-radius:4px;border-top-right-radius:4px;display:flex;flex-direction:column}\n"] }]
|
|
95
|
+
}], ctorParameters: () => [] });
|
|
125
96
|
|
|
126
97
|
/**
|
|
127
98
|
* Generated bundle index. Do not edit.
|