From c997e0ff2e2e379eae9d8a6e1dce78e79f2db43b Mon Sep 17 00:00:00 2001 From: wangyaju Date: Tue, 12 Apr 2022 11:50:53 +0800 Subject: [PATCH] chore(release): release 13.1.0 (#214) Co-authored-by: huaweidevcloud --- README.md | 2 +- README_zh_CN.md | 2 +- angular.json | 3 +- .../language-switch.component.ts | 7 +- devui/accordion/accordion-list.component.ts | 27 +- devui/accordion/accordion-menu.component.ts | 4 +- devui/accordion/accordion.component.scss | 1 - devui/accordion/accordion.component.ts | 15 +- .../demo/accordion-demo.component.html | 4 +- devui/accordion/doc/api-cn.md | 1 + devui/accordion/doc/api-en.md | 1 + devui/accordion/public-api.ts | 7 +- devui/alert/alert.component.scss | 1 - devui/alert/alert.component.ts | 3 + .../auto-complete-popup.component.scss | 1 - .../auto-complete-popup.component.theme.scss | 1 - .../auto-complete-popup.component.ts | 3 + .../auto-complete/auto-complete.directive.ts | 15 + devui/auto-complete/doc/api-cn.md | 13 +- devui/auto-complete/doc/api-en.md | 15 +- devui/badge/badge.component.html | 10 +- devui/badge/badge.component.scss | 12 +- devui/badge/badge.component.ts | 28 +- devui/badge/badge.types.ts | 2 +- devui/badge/demo/badge-demo.component.html | 16 +- devui/badge/demo/badge-demo.component.ts | 2 +- devui/badge/demo/count/count.component.html | 4 +- devui/badge/demo/count/count.component.scss | 17 +- devui/badge/demo/custom/custom.component.html | 2 +- .../demo/position/position.component.html | 4 +- devui/badge/doc/api-cn.md | 10 +- devui/badge/doc/api-en.md | 10 +- devui/breadcrumb/breadcrumb.component.scss | 1 + devui/breadcrumb/breadcrumb.component.ts | 13 +- devui/breadcrumb/public-api.ts | 1 + devui/button/button.component.scss | 3 +- devui/button/button.component.ts | 7 + devui/button/demo/button-demo.component.html | 6 - devui/button/demo/button-demo.component.ts | 6 - devui/button/demo/button-demo.module.ts | 2 - .../combination/combination.component.html | 6 +- .../demo/left-right/left-right.component.html | 2 - .../demo/left-right/left-right.component.scss | 15 - .../demo/left-right/left-right.component.ts | 8 - devui/button/demo/size/size.component.html | 10 +- devui/button/demo/text/text.component.html | 1 - devui/button/doc/api-cn.md | 6 +- devui/button/doc/api-en.md | 6 +- devui/cascader/cascader-li.component.scss | 4 +- devui/cascader/cascader.component.html | 10 +- devui/cascader/cascader.component.ts | 5 +- devui/cascader/cascader.spec.ts | 3 + .../cascader/demo/basic/basic.component.html | 2 +- .../search-cascader.component.ts | 2 +- .../template-cascader.component.html | 2 +- .../category-search.component.html | 155 ++-- .../category-search.component.scss | 26 +- .../category-search.component.ts | 205 ++++- .../category-search/category-search.module.ts | 8 +- devui/category-search/category-search.type.ts | 121 ++- .../content-template.directive.ts | 11 + .../default-template.directive.ts | 11 + .../demo/basic/basic.component.html | 1 + .../demo/basic/basic.component.ts | 20 +- .../demo/category-search-demo.component.html | 1 + .../demo/category-search-demo.component.ts | 75 +- .../demo/category-search-demo.module.ts | 63 +- devui/category-search/demo/demo-data.ts | 4 +- devui/category-search/doc/api-cn.md | 21 +- devui/category-search/doc/api-en.md | 15 +- devui/category-search/public-api.ts | 4 +- devui/checkbox/checkbox-group.component.scss | 2 +- devui/checkbox/checkbox.component.html | 16 +- devui/checkbox/checkbox.component.scss | 10 +- devui/checkbox/checkbox.component.ts | 2 +- .../group/checkbox-group-basic.component.html | 4 +- devui/checkbox/doc/api-cn.md | 2 +- devui/checkbox/doc/api-en.md | 2 +- .../demo/clipboard/clipboard.component.scss | 3 +- .../demo/lazy-load/lazy-load.component.ts | 2 +- devui/common/doc/api-cn.md | 19 +- devui/common/doc/api-en.md | 12 +- devui/common/helper-utils.ts | 50 +- devui/dashboard/dashboard.component.ts | 203 +++-- devui/dashboard/demo/dashboard-demo.module.ts | 6 +- .../more-config/more-config.component.scss | 13 +- devui/dashboard/doc/api-cn.md | 2 +- devui/dashboard/doc/api-en.md | 2 +- devui/dashboard/grid-stack.config.ts | 10 +- devui/dashboard/grid-stack.service.ts | 286 +++---- devui/dashboard/package.json | 2 +- devui/dashboard/polyfill.ts | 2 +- .../library-widget.directive.ts | 30 +- devui/dashboard/widget/widget.component.scss | 11 +- devui/dashboard/widget/widget.component.ts | 104 ++- devui/data-table/data-table-head.component.ts | 16 +- devui/data-table/data-table-row.component.ts | 23 +- devui/data-table/data-table.component.html | 6 +- devui/data-table/data-table.component.scss | 15 + devui/data-table/data-table.component.ts | 89 +- devui/data-table/data-table.module.ts | 7 +- devui/data-table/data-table.spec.ts | 3 +- .../dataTableProperties.interface.ts | 29 - .../check-options/check-options.component.ts | 1 - .../demo/data-table-demo.component.html | 174 ++-- .../demo/data-table-demo.component.ts | 2 +- .../data-table/demo/data-table-demo.module.ts | 6 +- .../interaction-column.component.html | 1 - .../interaction/interaction.component.html | 2 +- .../demo/interaction/interaction.component.ts | 51 +- .../mutil-styles/mutil-styles.component.html | 15 +- .../mutil-styles/mutil-styles.component.ts | 8 + devui/data-table/doc/api-cn.md | 45 +- devui/data-table/doc/api-en.md | 283 +------ devui/data-table/public-api.ts | 6 +- .../data-table/table/body/td/td.component.ts | 5 +- .../head/th/filter/filter.component.html | 1 - .../head/th/filter/filter.component.scss | 2 +- .../table/head/th/filter/filter.component.ts | 19 +- .../data-table/table/head/th/th.component.ts | 19 +- .../tmpl/data-table-column-tmpl.component.ts | 1 - devui/data-table/utils/utils.ts | 37 +- .../utils/virtualScrollTreeTable.factory.ts | 720 ---------------- .../virtualScrollTreeTable.component.html | 17 - .../virtualScrollTreeTable.component.scss | 17 - .../virtualScrollTreeTable.component.ts | 779 ------------------ .../datepicker-pro-calendar.component.html | 2 +- .../datepicker-pro-calendar.component.ts | 10 + .../datepicker-pro.component.html | 2 +- .../datepicker-pro.component.ts | 13 +- devui/datepicker-pro/datepicker-pro.module.ts | 4 +- .../datepicker-pro/datepicker-pro.service.ts | 36 +- .../demo/datepicker-pro-demo.component.html | 7 + .../demo/datepicker-pro-demo.component.ts | 6 + .../demo/datepicker-pro-demo.module.ts | 4 +- .../marked-type/marked-type.component.html | 16 + .../demo/marked-type/marked-type.component.ts | 22 + ...datepicker-pro-static-panel.component.html | 2 +- .../datepicker-pro-tab-type.component.html | 54 +- devui/datepicker-pro/doc/api-cn.md | 7 + devui/datepicker-pro/doc/api-en.md | 7 + .../lib/calendar-panel.component.html | 10 +- .../lib/calendar-panel.component.scss | 24 + .../lib/calendar-panel.component.ts | 57 +- .../lib/year-panel.component.scss | 4 +- .../range-datepicker-pro.component.html | 2 +- .../range-datepicker-pro.component.ts | 13 +- devui/datepicker/dateRangePicker.spec.ts | 3 - .../datepicker-cdk-overlay.component.ts | 2 +- devui/datepicker/datepicker.component.ts | 20 +- devui/datepicker/datepicker.directive.ts | 6 +- devui/datepicker/datepicker.spec.ts | 3 +- .../demo/set-mode/set-mode.component.html | 1 + .../demo/set-mode/set-mode.component.ts | 1 + devui/datepicker/doc/api-cn.md | 4 +- devui/datepicker/doc/api-en.md | 4 +- .../single-date-range-picker.component.ts | 2 +- .../two-datepicker-single.component.ts | 2 +- devui/datepicker/twoDatePicker.spec.ts | 2 +- .../color/demo/color/color.component.html | 156 +++- .../color/demo/color/color.component.scss | 213 +++++ .../color/demo/color/color.component.ts | 217 +++-- .../font/demo/font/font.component.html | 94 +-- .../shadow/demo/shadow/shadow.component.html | 146 ++-- .../shadow/demo/shadow/shadow.component.scss | 19 + .../shadow/demo/shadow/shadow.component.ts | 27 +- .../demo/design-z-index-demo.component.html | 30 + .../demo/design-z-index-demo.component.ts | 46 ++ .../demo/design-z-index-demo.module.ts | 33 + .../demo/z-index/z-index.component.html | 16 + .../z-index/demo/z-index/z-index.component.ts | 54 ++ devui/design-token/z-index/doc/api-cn.md | 1 + devui/design-token/z-index/doc/api-en.md | 1 + .../demo/batch-drag/batch-drag.component.ts | 12 +- devui/dragdrop/doc/api-cn.md | 6 +- devui/dragdrop/doc/api-en.md | 6 +- devui/dragdrop/shared/utils.ts | 2 +- .../dragdrop/touch-support/dragdrop-touch.ts | 2 - devui/drawer/doc/api-cn.md | 1 + devui/drawer/doc/api-en.md | 1 + devui/drawer/drawer.component.scss | 2 - devui/drawer/drawer.component.ts | 8 +- devui/dropdown/doc/api-cn.md | 16 +- devui/dropdown/doc/api-en.md | 25 +- devui/dropdown/dropdown.directive.ts | 2 +- .../demo/basic/with-source.component.html | 1 + .../demo/basic/with-source.component.ts | 36 +- devui/editable-select/doc/api-cn.md | 7 +- devui/editable-select/doc/api-en.md | 9 +- .../editable-select.component.html | 5 +- .../editable-select.component.ts | 14 +- devui/form/doc/api-cn.md | 1 + devui/form/doc/api-en.md | 1 + .../form-control-rules.directive.ts | 2 +- .../demo/fullscreen-demo.component.ts | 60 +- .../fullscreen/demo/fullscreen-demo.module.ts | 64 +- devui/fullscreen/fullscreen.component.ts | 3 + devui/fullscreen/fullscreen.spec.ts | 1 - devui/gantt/demo/basic/basic.component.html | 2 +- devui/gantt/demo/basic/basic.component.ts | 1 - devui/gantt/demo/table/table.component.html | 2 +- devui/gantt/doc/api-cn.md | 12 + devui/gantt/doc/api-en.md | 12 + devui/gantt/gantt-bar/gantt-bar.component.ts | 4 +- .../gantt-scale/gantt-scale.component.ts | 2 +- .../gantt-tools/gantt-tools.component.html | 2 +- .../gantt-tools/gantt-tools.component.ts | 45 +- devui/gantt/resize-handle.directive.ts | 2 - devui/i18n/en-us.ts | 5 +- devui/i18n/i18n.model.ts | 3 + devui/i18n/i18n.service.ts | 17 +- devui/i18n/zh-cn.ts | 5 +- .../basic/input-number-basic.component.css | 5 + .../basic/input-number-basic.component.html | 28 +- devui/input-number/input-number.component.ts | 2 +- devui/layout/public-api.ts | 2 +- .../loading/demo/custom/custom.component.scss | 6 +- devui/loading/doc/api-cn.md | 3 +- devui/loading/doc/api-en.md | 3 +- devui/loading/loading.component.scss | 3 +- devui/loading/loading.directive.ts | 33 +- devui/mention/assets/common.scss | 1 - devui/mention/mention.component.scss | 1 + devui/mention/mention.directive.ts | 2 +- devui/modal/demo/modal-demo.component.ts | 9 +- devui/modal/dialog.service.ts | 3 + devui/modal/doc/api-cn.md | 13 +- devui/modal/doc/api-en.md | 5 +- devui/modal/modal-container.component.ts | 2 +- devui/modal/modal-header.component.scss | 2 - devui/modal/modal.component.scss | 2 - devui/modal/modal.service.ts | 3 + devui/modal/movable.directive.ts | 2 +- devui/multi-auto-complete/doc/api-cn.md | 1 + devui/multi-auto-complete/doc/api-en.md | 1 + .../multi-auto-complete.component.scss | 2 +- .../multi-auto-complete.component.ts | 10 +- .../demo/nav-sprite-demo.component.html | 1 + .../demo/nav-sprite-demo.component.ts | 77 +- .../nav-sprite/demo/nav-sprite-demo.module.ts | 49 +- devui/nav-sprite/nav-sprite.component.scss | 2 +- devui/nav-sprite/nav-sprite.component.ts | 8 +- devui/ng-package.json | 11 +- devui/package.json | 4 +- devui/pagination/pagination.component.ts | 6 + devui/panel/demo/basic/basic.component.html | 2 + devui/panel/demo/panel-demo.component.ts | 2 + devui/panel/demo/type/type.component.html | 10 +- devui/panel/demo/type/type.component.scss | 12 + devui/panel/demo/type/type.component.ts | 1 + devui/panel/doc/api-cn.md | 2 +- devui/panel/doc/api-en.md | 2 +- devui/panel/panel-body.component.ts | 6 +- devui/panel/panel.component.html | 15 +- devui/panel/panel.component.scss | 42 +- devui/panel/panel.component.ts | 2 + devui/panel/panel.types.ts | 2 +- devui/polyfills.ts | 1 - devui/popover/demo/basic/basic.component.html | 10 +- devui/popover/popover.component.scss | 2 - devui/popover/popover.component.ts | 1 + devui/popover/popover.directive.ts | 15 +- devui/popover/popover.spec.ts | 9 +- .../progress/demo/basic/basic.component.html | 2 +- .../demo/circle/circle.component.html | 7 +- .../demo/circle/circle.component.scss | 2 - devui/progress/doc/api-cn.md | 7 +- devui/progress/doc/api-en.md | 12 +- devui/progress/progress.component.html | 11 +- devui/progress/progress.component.scss | 7 +- devui/progress/progress.component.ts | 35 +- .../demo/basic/basic.component.scss | 2 +- .../quadrant-label.component.scss | 4 +- .../demo/onlyread/onlyread.component.html | 2 +- devui/rate/demo/rate-demo.component.html | 7 + devui/rate/demo/rate-demo.component.ts | 6 + devui/rate/demo/rate-demo.module.ts | 2 + .../demo/template/template.component.html | 5 + .../rate/demo/template/template.component.ts | 10 + devui/rate/demo/type/type.component.html | 6 +- devui/rate/doc/api-cn.md | 8 +- devui/rate/doc/api-en.md | 8 +- devui/rate/rate.component.html | 18 +- devui/rate/rate.component.scss | 28 +- devui/rate/rate.component.ts | 40 +- devui/read-tip/read-tip.component.scss | 2 - devui/read-tip/read-tip.component.ts | 2 +- devui/read-tip/read-tip.directive.ts | 6 +- devui/search/search.component.scss | 2 - .../custom-search/custom-search.component.ts | 13 +- devui/select/doc/api-cn.md | 7 +- devui/select/doc/api-en.md | 7 +- devui/select/select.component.scss | 6 +- devui/select/select.component.ts | 9 +- devui/select/select.spec.ts | 16 +- .../shared/devui-api/devui-api.component.html | 2 +- devui/shared/devui-api/devui-api.component.ts | 11 +- devui/shared/devui-api/devui-api.module.ts | 3 +- .../devui-codebox.component.html | 92 +-- devui/slider/slider.component.html | 2 +- devui/slider/slider.component.scss | 5 +- devui/slider/slider.component.ts | 4 +- devui/splitter/splitter-bar.component.html | 2 +- devui/status/doc/api-cn.md | 15 +- devui/status/doc/api-en.md | 9 +- devui/status/status.component.scss | 2 - devui/steps-guide/doc/api-cn.md | 1 - devui/steps-guide/doc/api-en.md | 1 - devui/steps-guide/steps-guide.directive.ts | 3 +- devui/steps-guide/steps-guide.spec.ts | 2 +- devui/style/core/_dropdown.scss | 2 +- devui/style/core/_font.scss | 34 + devui/style/core/_form.scss | 1 - devui/style/core/_imagePreview.scss | 2 - devui/style/core/_normalize.scss | 2 + devui/style/core/_reset.scss | 4 +- devui/style/core/_temp.scss | 6 - devui/style/devui.css | 13 +- devui/style/devui.scss | 9 +- devui/style/theme/_animation.scss | 2 + devui/style/theme/_basic.scss | 243 ++++++ devui/style/theme/_color.scss | 163 ++-- devui/style/theme/_corner.scss | 3 +- devui/styles-var/devui-var.less | 1 + devui/styles-var/devui-var.scss | 3 +- devui/tabs/demo/basic/basic.component.html | 18 +- .../before-change.component.html | 4 +- .../configurable-tabs.component.html | 1 - .../configurable-tabs.component.ts | 2 +- devui/tabs/demo/custom/custom.component.html | 10 +- .../type-options/type-options.component.html | 4 +- .../demo/type-pills/type-pills.component.html | 4 +- .../type-slider/type-slider.component.html | 4 +- .../without-content.component.html | 6 +- devui/tabs/doc/api-cn.md | 7 +- devui/tabs/doc/api-en.md | 6 +- devui/tabs/tab.component.ts | 20 +- devui/tabs/tabs.component.html | 4 +- devui/tabs/tabs.component.scss | 5 +- devui/tabs/tabs.component.ts | 10 +- devui/tabs/tabs.spec.ts | 44 +- devui/tags-input/doc/api-cn.md | 3 + devui/tags-input/doc/api-en.md | 3 + devui/tags-input/tags.input.component.ts | 8 +- devui/test.ts | 4 +- devui/text-input/doc/api-cn.md | 3 - devui/text-input/doc/api-en.md | 3 - devui/textarea/doc/api-cn.md | 3 - devui/textarea/doc/api-en.md | 3 - devui/time-picker/time-picker.component.ts | 14 +- devui/toast/doc/api-cn.md | 2 + devui/toast/doc/api-en.md | 2 + devui/toast/toast.component.scss | 2 +- devui/toast/toast.component.ts | 8 +- devui/toast/toast.module.ts | 4 +- devui/toast/toast.service.ts | 7 +- .../toggle-menu-container.component.scss | 2 +- .../toggle-menu-container.component.ts | 1 - devui/toggle/toggle.component.html | 13 +- devui/toggle/toggle.component.scss | 7 +- devui/toggle/toggle.component.ts | 24 +- devui/toggle/toggle.module.ts | 15 +- devui/tooltip/demo/basic/basic.component.html | 2 +- devui/tooltip/tooltip.directive.ts | 43 +- devui/transfer/transfer.component.ts | 8 +- .../demo/basic/tree-select-basic.component.ts | 2 +- .../custom-template.component.ts | 4 +- devui/tree-select/tree-select.component.ts | 9 +- .../demo/merge-node/merge-node.component.ts | 4 +- devui/tree/doc/api-cn.md | 6 +- devui/tree/doc/api-en.md | 6 +- devui/tree/operable-tree.component.html | 4 +- devui/tree/operable-tree.component.scss | 2 - devui/tree/operable-tree.component.ts | 12 +- devui/tree/tree-factory.class.ts | 32 +- devui/tree/tree.component.scss | 2 - devui/tree/tree.component.ts | 4 +- devui/tree/tree.spec.ts | 1 - devui/tsconfig.lib.json | 11 +- .../demo/slice/upload-slice.component.html | 73 ++ .../demo/slice/upload-slice.component.scss | 3 + .../demo/slice/upload-slice.component.ts | 111 +++ devui/upload/demo/upload-demo.component.html | 7 + devui/upload/demo/upload-demo.component.ts | 6 + devui/upload/demo/upload-demo.module.ts | 4 +- devui/upload/doc/api-cn.md | 5 + devui/upload/doc/api-en.md | 5 + devui/upload/file-uploader.types.ts | 4 + devui/upload/single-upload.component.ts | 139 +++- devui/upload/upload-view.component.scss | 2 - devui/utils/animations/scrollAnimation.ts | 2 +- devui/utils/lazy-load/lazy-load.directive.ts | 2 +- devui/utils/tree-utils.ts | 2 +- devui/version.ts | 2 +- package.json | 20 +- .../themeable/utils/generate-styles-var.js | 17 +- src/app/app.component.scss | 13 +- src/app/component/app-content.component.ts | 2 +- src/app/component/component.route.ts | 387 +++++++-- .../component/example-panel.component.html | 4 +- src/app/component/example-panel.component.ts | 2 +- src/app/component/get-started.component.ts | 7 +- src/app/component/global-config.component.ts | 7 +- src/app/component/scope-list.ts | 29 +- src/app/component/theme-guide.component.ts | 7 +- .../customize-theme.component.html | 6 - .../theme-picker/theme-picker.component.html | 147 ++-- .../theme-picker/theme-picker.component.scss | 3 + src/assets/i18n/en-us.json | 133 ++- src/assets/i18n/zh-cn.json | 130 ++- src/environments/environment.ts | 9 - src/polyfills.ts | 17 +- src/test.ts | 7 +- tsconfig.base.json | 24 +- 414 files changed, 4981 insertions(+), 4273 deletions(-) delete mode 100644 devui/button/demo/left-right/left-right.component.html delete mode 100644 devui/button/demo/left-right/left-right.component.scss delete mode 100644 devui/button/demo/left-right/left-right.component.ts create mode 100644 devui/category-search/content-template.directive.ts create mode 100644 devui/category-search/default-template.directive.ts delete mode 100644 devui/data-table/dataTableProperties.interface.ts delete mode 100644 devui/data-table/utils/virtualScrollTreeTable.factory.ts delete mode 100644 devui/data-table/virtualScrollTreeTable.component.html delete mode 100644 devui/data-table/virtualScrollTreeTable.component.scss delete mode 100644 devui/data-table/virtualScrollTreeTable.component.ts create mode 100644 devui/datepicker-pro/demo/marked-type/marked-type.component.html create mode 100644 devui/datepicker-pro/demo/marked-type/marked-type.component.ts create mode 100644 devui/design-token/z-index/demo/design-z-index-demo.component.html create mode 100644 devui/design-token/z-index/demo/design-z-index-demo.component.ts create mode 100644 devui/design-token/z-index/demo/design-z-index-demo.module.ts create mode 100644 devui/design-token/z-index/demo/z-index/z-index.component.html create mode 100644 devui/design-token/z-index/demo/z-index/z-index.component.ts create mode 100644 devui/design-token/z-index/doc/api-cn.md create mode 100644 devui/design-token/z-index/doc/api-en.md create mode 100644 devui/panel/demo/type/type.component.scss create mode 100644 devui/rate/demo/template/template.component.html create mode 100644 devui/rate/demo/template/template.component.ts create mode 100644 devui/style/theme/_basic.scss create mode 100644 devui/upload/demo/slice/upload-slice.component.html create mode 100644 devui/upload/demo/slice/upload-slice.component.scss create mode 100644 devui/upload/demo/slice/upload-slice.component.ts diff --git a/README.md b/README.md index 4601568b..62f8bd1c 100755 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Modern browsers and Internet Explorer 11+. | [IE / Edge](http://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | | --------- | --------- | --------- | --------- | --------- | -| Edge | last 2 versions| last 2 versions| last 2 versions| last 2 versions +| Edge| last 2 versions| last 2 versions| last 2 versions| last 2 versions ## Who use it diff --git a/README_zh_CN.md b/README_zh_CN.md index 4d4ac8db..8d3f0666 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -99,7 +99,7 @@ ng serve --open | [IE / Edge](http://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | | --------- | --------- | --------- | --------- | --------- | -| Edge | last 2 versions| last 2 versions| last 2 versions| last 2 versions +| Edge| last 2 versions| last 2 versions| last 2 versions| last 2 versions ## 谁在使用 diff --git a/angular.json b/angular.json index e6953ac5..03a367d7 100755 --- a/angular.json +++ b/angular.json @@ -18,7 +18,8 @@ "highlight.js", "codemirror", "xss", - "enquire.js" + "enquire.js", + "color" ], "customWebpackConfig": { "path": "scripts/extra-webpack.config.js" diff --git a/devui-commons/src/header/language-switch/language-switch.component.ts b/devui-commons/src/header/language-switch/language-switch.component.ts index 006dac55..4745da18 100644 --- a/devui-commons/src/header/language-switch/language-switch.component.ts +++ b/devui-commons/src/header/language-switch/language-switch.component.ts @@ -1,3 +1,4 @@ +import { I18nService } from 'ng-devui/i18n'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { DevuiCommonsService } from '../../devui-commons.service'; import { I18nUtil } from '../../i18n/i18n.util'; @@ -12,7 +13,10 @@ export class LanguageSwitchComponent implements OnInit { @Output() languageEvent = new EventEmitter(); currentLang: string; - constructor(private commonsService: DevuiCommonsService) { } + constructor( + private commonsService: DevuiCommonsService, + private i18n: I18nService + ) { } ngOnInit(): void { this.currentLang = I18nUtil.getCurrentLanguage(); @@ -22,6 +26,7 @@ export class LanguageSwitchComponent implements OnInit { this.currentLang = this.currentLang === 'zh-cn' ? 'en-us' : 'zh-cn'; localStorage.setItem('lang', this.currentLang); this.languageEvent.emit(this.currentLang); + this.i18n.toggleLang(this.currentLang); this.commonsService.broadcast('languageEvent', this.currentLang); } } \ No newline at end of file diff --git a/devui/accordion/accordion-list.component.ts b/devui/accordion/accordion-list.component.ts index 19e8fb21..c2e62d74 100644 --- a/devui/accordion/accordion-list.component.ts +++ b/devui/accordion/accordion-list.component.ts @@ -1,5 +1,6 @@ import { - Component, Host, HostBinding, Inject, Input, OnDestroy, OnInit, + Component, + forwardRef, Host, HostBinding, Inject, Input, OnDestroy, OnInit, Optional, QueryList, SkipSelf, ViewChildren, ViewEncapsulation } from '@angular/core'; import { expandCollapse, expandCollapseForDomDestroy } from 'ng-devui/utils'; @@ -17,31 +18,11 @@ import { AccordionMenuItem } from './accordion.type'; preserveWhitespaces: false, providers: [{ provide: ACCORDION_LIST, - useExisting: AccordionListComponent + useExisting: forwardRef(() => AccordionListComponent) }] }) export class AccordionListComponent implements OnInit, OnDestroy { - // @HostBinding('class.open') - // get open() { - // return (this.keyOpen === undefined && this.accordion.autoOpenActiveMenu) - // ? this.childActived - // : this.keyOpen; - // } - // get keyOpen() { - // return this.data && this.data[this.accordion.openKey]; - // } - - // get children() { - // return this.data && this.data[this.accordion.childrenKey]; - // } - // get childActived() { - // return this.routerLinkActived || this.hasActiveChildren; - // } - - // get showAnimate() { - // return this.accordion.showAnimation; - // } constructor(@Optional() @Host() @SkipSelf() @Inject(ACCORDION_MENU) private parentComponent: any, @Inject(ACCORDION) private accordion: any) {} @HostBinding('class.devui-accordion-show-animate') get animateState() { @@ -113,7 +94,7 @@ export class AccordionListComponent implements OnInit, OnDestroy { @Input() parent: AccordionMenuItem; @ViewChildren(ACCORDION_MENU) accordionMenuQueryList: QueryList; @ViewChildren(AccordionItemRouterlinkComponent) accordionItemRouterlinkQueryList: QueryList; -6; + 6; ngOnInit(): void { if (this.parentComponent) { setTimeout(() => {this.parentComponent.accordionListFromView = this; }); diff --git a/devui/accordion/accordion-menu.component.ts b/devui/accordion/accordion-menu.component.ts index b78eb154..2dcddb53 100644 --- a/devui/accordion/accordion-menu.component.ts +++ b/devui/accordion/accordion-menu.component.ts @@ -1,4 +1,4 @@ -import { Component, HostBinding, Inject, ViewEncapsulation } from '@angular/core'; +import { Component, forwardRef, HostBinding, Inject, ViewEncapsulation } from '@angular/core'; import { AccordionBaseComponent } from './accordion-base-component.class'; import { ACCORDION_MENU } from './accordion-menu-token'; import { ACCORDION } from './accordion-token'; @@ -10,7 +10,7 @@ import { AccordionBaseMenu, AccordionMenuItem } from './accordion.type'; preserveWhitespaces: false, providers: [{ provide: ACCORDION_MENU, - useExisting: AccordionMenuComponent + useExisting: forwardRef(() => AccordionMenuComponent) }] }) export class AccordionMenuComponent extends AccordionBaseComponent> { diff --git a/devui/accordion/accordion.component.scss b/devui/accordion/accordion.component.scss index d84f66a5..5af09ae2 100755 --- a/devui/accordion/accordion.component.scss +++ b/devui/accordion/accordion.component.scss @@ -1,4 +1,3 @@ -@import '../style/mixins/index'; @import '../style/theme/color'; @import '../style/theme/shadow'; @import '../style/theme/corner'; diff --git a/devui/accordion/accordion.component.ts b/devui/accordion/accordion.component.ts index b643dce9..24673cbd 100755 --- a/devui/accordion/accordion.component.ts +++ b/devui/accordion/accordion.component.ts @@ -1,4 +1,15 @@ -import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, TemplateRef } from '@angular/core'; +import { + Component, + EventEmitter, + forwardRef, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + SimpleChanges, + TemplateRef +} from '@angular/core'; import { I18nInterface, I18nService } from 'ng-devui/i18n'; import { DevConfigService, WithConfig } from 'ng-devui/utils/globalConfig'; import { Subscription } from 'rxjs'; @@ -11,7 +22,7 @@ import { AccordionItemClickEvent, AccordionMenuToggleEvent, AccordionMenuType, A preserveWhitespaces: false, providers: [{ provide: ACCORDION, - useExisting: AccordionComponent + useExisting: forwardRef(() => AccordionComponent) }] }) export class AccordionComponent implements AccordionOptions, OnChanges, OnInit, OnDestroy { diff --git a/devui/accordion/demo/accordion-demo.component.html b/devui/accordion/demo/accordion-demo.component.html index 658a2d5c..811bc56f 100755 --- a/devui/accordion/demo/accordion-demo.component.html +++ b/devui/accordion/demo/accordion-demo.component.html @@ -1,4 +1,4 @@ -
+
{{ 'components.accordion.basicDemo.title' | translate }}
@@ -24,7 +24,7 @@ -
{{ 'components.accordion.innerListTemplateDemo.description' | translate }}
+
{{ 'components.accordion.innerListTemplateDemo.description' | translate }}
diff --git a/devui/accordion/doc/api-cn.md b/devui/accordion/doc/api-cn.md index 28720db1..19c197f6 100644 --- a/devui/accordion/doc/api-cn.md +++ b/devui/accordion/doc/api-cn.md @@ -39,6 +39,7 @@ import { AccordionModule } from 'ng-devui/accordion'; | autoOpenActiveMenu | `boolean` | false | 可选,是否自动展开带有活跃子项的菜单 | [复合层级和自动展开](demo#compound-level-and-auto-expand) | | accordionType | `'normal'\|'embed'` | 'normal' | 可选,菜单形式是普通(带阴影)还是内嵌(不带阴影) | [基本用法](demo#basic-usage) | | showAnimation | `boolean` | true | 可选,是否展示动画 | [内置路由和链接类型](demo#use-built-in-routing-and-link-types) | ✔ | +| showNoContent | `boolean` | true | 可选,没有内容的时候是否显示没有数据 | | | ### d-accordion 事件 diff --git a/devui/accordion/doc/api-en.md b/devui/accordion/doc/api-en.md index dba8ce67..a8b1b5df 100644 --- a/devui/accordion/doc/api-en.md +++ b/devui/accordion/doc/api-en.md @@ -39,6 +39,7 @@ On the page: | autoOpenActiveMenu | `boolean` | false | Optional. Whether to automatically expand menus with active subitems | [Composite Hierarchy and Auto Expand](demo#compound-level-and-auto-expand) | | accordionType | `normal ' \| 'embed'` | 'normal' | Optional. The menu format is common (with shadow) or embedded (without shadow). | [Basic usage](demo#basic-usage) | | showAnimation | `boolean` | true | Optional. Indicating whether to display animations. | [Built-in route and link type](demo#use-built-in-routing-and-link-types) | ✔ | +| showNoContent | `boolean` | true | Optional. Whether to display no data when there is no content. | | | ### d-accordion event diff --git a/devui/accordion/public-api.ts b/devui/accordion/public-api.ts index 4a2c249f..003abed3 100755 --- a/devui/accordion/public-api.ts +++ b/devui/accordion/public-api.ts @@ -1,11 +1,14 @@ -export * from './accordion.module'; -export * from './accordion.component'; export * from './accordion-base-component.class'; export * from './accordion-base-item-component.class'; export * from './accordion-base-link-component.class'; export * from './accordion-item-hreflink.component'; export * from './accordion-item-routerlink.component'; export * from './accordion-item.component'; +export * from './accordion-list-token'; export * from './accordion-list.component'; +export * from './accordion-menu-token'; export * from './accordion-menu.component'; +export * from './accordion-token'; +export * from './accordion.component'; +export * from './accordion.module'; export * from './accordion.type'; diff --git a/devui/alert/alert.component.scss b/devui/alert/alert.component.scss index f4bf59b8..c7e2787b 100755 --- a/devui/alert/alert.component.scss +++ b/devui/alert/alert.component.scss @@ -1,4 +1,3 @@ -@import '../style/mixins/index'; @import '../style/theme/color'; @import '../style/theme/shadow'; @import '../style/theme/corner'; diff --git a/devui/alert/alert.component.ts b/devui/alert/alert.component.ts index 9d62334f..6e0551a4 100755 --- a/devui/alert/alert.component.ts +++ b/devui/alert/alert.component.ts @@ -17,6 +17,9 @@ export class AlertComponent { @Input() type: AlertType = 'info'; @Input() cssClass: string; @Input() closeable = true; + /** + * @deprecated + */ @Input() content: HTMLElement | string; @Input() showIcon = true; @Output() closeEvent = new EventEmitter(); diff --git a/devui/auto-complete/auto-complete-popup.component.scss b/devui/auto-complete/auto-complete-popup.component.scss index b55fe9c5..5aa32e0f 100755 --- a/devui/auto-complete/auto-complete-popup.component.scss +++ b/devui/auto-complete/auto-complete-popup.component.scss @@ -1,4 +1,3 @@ -@import '../style/mixins/index'; @import '../style/theme/color'; .devui-dropdown-menu { diff --git a/devui/auto-complete/auto-complete-popup.component.theme.scss b/devui/auto-complete/auto-complete-popup.component.theme.scss index bd4fe1f3..44d2f35f 100755 --- a/devui/auto-complete/auto-complete-popup.component.theme.scss +++ b/devui/auto-complete/auto-complete-popup.component.theme.scss @@ -1,5 +1,4 @@ @import '../style/theme/color'; -@import '../style/mixins/index'; .active { background: $devui-list-item-hover-bg; diff --git a/devui/auto-complete/auto-complete-popup.component.ts b/devui/auto-complete/auto-complete-popup.component.ts index fb602c68..162c71d2 100755 --- a/devui/auto-complete/auto-complete-popup.component.ts +++ b/devui/auto-complete/auto-complete-popup.component.ts @@ -28,6 +28,9 @@ export class AutoCompletePopupComponent implements ControlValueAccessor { @Input() isOpen: boolean; @Input() term: string; @Input() popTipsText: string; + /** + * @deprecated + */ @Input() overview: string; @Input() itemTemplate: TemplateRef; @Input() noResultItemTemplate: TemplateRef; diff --git a/devui/auto-complete/auto-complete.directive.ts b/devui/auto-complete/auto-complete.directive.ts index 83fa7ea5..2164488a 100755 --- a/devui/auto-complete/auto-complete.directive.ts +++ b/devui/auto-complete/auto-complete.directive.ts @@ -46,8 +46,14 @@ export class AutoCompleteDirective implements OnInit, OnDestroy, OnChanges, Cont @HostBinding('attr.autocapitalize') autocapitalize = 'off'; @HostBinding('attr.autocorrect') autocorrect = 'off'; @Input() disabled: boolean; + /** + * @deprecated + */ @Input() cssClass: string; @Input() delay = 300; + /** + * @deprecated + */ @Input() minLength: number; @Input() itemTemplate: TemplateRef; @Input() noResultItemTemplate: TemplateRef; @@ -78,6 +84,9 @@ export class AutoCompleteDirective implements OnInit, OnDestroy, OnChanges, Cont @Input() source: any[]; @Input() valueParser: (item: any) => any; @Input() searchFn: (term: string, target?: AutoCompleteDirective) => Observable; + /** + * @deprecated + */ @Input() dropdown: boolean; @Input() maxHeight = 300; @Input() disabledKey: string; @@ -90,7 +99,11 @@ export class AutoCompleteDirective implements OnInit, OnDestroy, OnChanges, Cont @Output() loadMore = new EventEmitter(); @Output() selectValue = new EventEmitter(); @Output() transInputFocusEmit = new EventEmitter(); // input状态传给父组件函数 + /** + * @deprecated + */ @Output() changeDropDownStatus = new EventEmitter(); + @Output() toggleChange = new EventEmitter(); KEYBOARD_EVENT_NOT_REFRESH = ['escape', 'enter', 'arrowup', 'arrowdown', /* ie 10 edge */ 'esc', 'up', 'down']; popupRef: ComponentRef; @@ -287,6 +300,7 @@ export class AutoCompleteDirective implements OnInit, OnDestroy, OnChanges, Cont this.popupRef.instance.disabled = this.disabled; addClassToOrigin(this.elementRef); this.changeDropDownStatus.emit(true); + this.toggleChange.emit(true); } writeValue(obj): void { @@ -408,6 +422,7 @@ export class AutoCompleteDirective implements OnInit, OnDestroy, OnChanges, Cont this.popupRef.instance.isOpen = false; removeClassFromOrigin(this.elementRef); this.changeDropDownStatus.emit(false); + this.toggleChange.emit(false); } } diff --git a/devui/auto-complete/doc/api-cn.md b/devui/auto-complete/doc/api-cn.md index 647e357f..d820c927 100644 --- a/devui/auto-complete/doc/api-cn.md +++ b/devui/auto-complete/doc/api-cn.md @@ -38,14 +38,17 @@ import { AutoCompleteModule } from 'ng-devui/auto-complete'; | enableLazyLoad | `boolean` | false | 可选,是否允许懒加载 | [启用懒加载](demo#auto-lazy-load) | | dAutoCompleteWidth | `number` | -- | 可选,调整宽度(`px`) | | showAnimation | `boolean` | true | 可选,是否开启动画 | | ✔ | +| maxHeight | `number` | `300` | 可选,提示框的最大高度 | | +| cdkOverlayOffsetY | `number` | `0` | 可选,appendToBody 为 true 时,Y 轴的偏移量 | ## dAutoComplete 事件 -| 参数 | 类型 | 说明 | 跳转 Demo | -| :-----------------: | :----------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------- | -| loadMore | `EventEmitter>` | 懒加载触发事件,配合`enableLazyLoad`使用,使用`$event.loadFinish()`关闭 loading 状态,其中\$event 为 AutoCompletePopupComponent 的实例 | [启用懒加载](demo#auto-lazy-load) | -| selectValue | `EventEmitter` | 可选,选择选项之后的回调函数 | [启用懒加载](demo#auto-lazy-load) | -| transInputFocusEmit | `EventEmitter<{focus: boolean, popupRef: ComponentRef}>` | 可选,Input focus 时回调函数 | [启用懒加载](demo#auto-lazy-load) | +| 参数 | 类型 | 说明 | 跳转 Demo | +| :-----------------: | :----------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------- | +| loadMore | `EventEmitter>` | 可选,懒加载触发事件,配合`enableLazyLoad`使用,使用`$event.loadFinish()`关闭 loading 状态,其中\$event 为 AutoCompletePopupComponent 的实例 | [启用懒加载](demo#auto-lazy-load) | +| selectValue | `EventEmitter` | 可选,选择选项之后的回调函数 | [启用懒加载](demo#auto-lazy-load) | +| transInputFocusEmit | `EventEmitter<{focus: boolean, popupRef: ComponentRef}>` | 可选,Input focus 时回调函数 | [启用懒加载](demo#auto-lazy-load) | +| toggleChange | `EventEmitter` | 可选,触发下拉开关时,返回下拉是否开启 | # 接口 & 类型定义 diff --git a/devui/auto-complete/doc/api-en.md b/devui/auto-complete/doc/api-en.md index 7867e13b..e92d66a3 100644 --- a/devui/auto-complete/doc/api-en.md +++ b/devui/auto-complete/doc/api-en.md @@ -21,7 +21,7 @@ In the page | source | `Array` | -- | Required. This parameter is optional if searchFn is specified. | [Basic usage](demo#basic-usage) | | allowEmptyValueSearch | `boolean` | false | Optional. indicates whether to display a search message when the bound text box value is empty. | [Customized template display](demo#auto-custom) | | appendToBody | `boolean` | false | Optional. Whether to append to body is displayed in the drop-down list box. | [Customized template display](demo#auto-custom) | -| appendToBodyDirections | `Array` | `['rightDown','leftDown','rightUp','leftUp']` | Optional. The first position in the array is preferred for the direction array, for details about AppendToBodyDirection and ConnectedPosition, see dropdown | [Customized template display](demo#auto-custom) | +| appendToBodyDirections | `Array` | `['rightDown','leftDown',`
`'rightUp','leftUp']` | Optional. The first position in the array is preferred for the direction array, for details about AppendToBodyDirection and ConnectedPosition, see dropdown | [Customized template display](demo#auto-custom) | | disabled | `boolean` | false | Optional. Indicating whether to disable commands. | [Disabled](demo#auto-disable) | | delay | `number` | 300 | Optional. The search is performed only after the delay time elapses and a new value is entered. (`ms`) | [Customized template display](demo#auto-custom) | | disabledKey | `string` | -- | Optional. Disable a single option. If the input resource source option type is an object, for example, disabled, and the disable attribute of the object is true, for example, {label: xxx, disabled: true}, this option will be disabled | [Disabled](demo#auto-disable) | @@ -38,14 +38,17 @@ In the page | enableLazyLoad | `boolean` | false | Optional. Whether lazy loading is allowed | [Enable lazy load](demo#auto-lazy-load) | | dAutoCompleteWidth | `number` | -- | Optional. Adjust the width (`px`) | | showAnimation | `boolean` | true | optional. Whether to enable animation. | | ✔ | +| maxHeight | `number` | `300` | Optional. Maximum height of the prompt box. | | +| cdkOverlayOffsetY | `number` | `0` | Optional. Specifies the offset of the Y axis when appendToBody is set to true. | ## dAutoComplete Event -| Parameter | Type | Description | Jump to Demo | -| :-----------------: | :----------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------- | -| loadMore | `EventEmitter>` | : optional. It is a lazy loading trigger event. It is used together with enableLazyLoad. \`$event.loadFinish()\` is used to disable the loading status. $event is the instance of the pop-up component AutoCompletePopupComponent | [Enable lazy load](demo#auto-lazy-load) | -| selectValue | `EventEmitter` | (optional), callback function after selecting an option | [Enable lazy load](demo#auto-lazy-load) | -| transInputFocusEmit | `EventEmitter<{focus: boolean, popupRef: ComponentRef}>` | (optional). Callback function for input focus | [Enable lazy load](demo#auto-lazy-load) | +| Parameter | Type | Description | Jump to Demo | +| :-----------------: | :----------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------- | +| loadMore | `EventEmitter>` | Optional. It is a lazy loading trigger event. It is used together with enableLazyLoad. \`$event.loadFinish()\` is used to disable the loading status. $event is the instance of the pop-up component AutoCompletePopupComponent | [Enable lazy load](demo#auto-lazy-load) | +| selectValue | `EventEmitter` | Optional. Callback function after selecting an option | [Enable lazy load](demo#auto-lazy-load) | +| transInputFocusEmit | `EventEmitter<{focus: boolean, popupRef: ComponentRef}>` | Optional. Callback function for input focus | [Enable lazy load](demo#auto-lazy-load) | +| toggleChange | `EventEmitter` | Optional. When the pull-down switch is triggered, return to whether the pull-down switch is turned on. | # Interface & Type Definition diff --git a/devui/badge/badge.component.html b/devui/badge/badge.component.html index a4606646..0aae226e 100644 --- a/devui/badge/badge.component.html +++ b/devui/badge/badge.component.html @@ -9,14 +9,14 @@ - {{ count }} - {{ maxCount }}+ + {{ count }} + {{ maxCount }}+ diff --git a/devui/badge/badge.component.scss b/devui/badge/badge.component.scss index e432173a..b1c7bcf8 100644 --- a/devui/badge/badge.component.scss +++ b/devui/badge/badge.component.scss @@ -1,5 +1,6 @@ @import '../style/theme/color'; -@import '../style/core/_font'; +@import '../style/core/font'; +@import '../style/theme/corner'; @mixin status-color { &-danger { @@ -21,6 +22,11 @@ &-info { background: $devui-info; } + + &-common { + background: $devui-unavailable; + color: $devui-aide-text; + } } :host { @@ -41,7 +47,7 @@ line-height: 16px; text-align: center; padding: 0 4px; - border-radius: 8px; + border-radius: $devui-border-radius-full; } &-dot { @@ -88,7 +94,7 @@ line-height: 16px; text-align: center; padding: 0 4px; - border-radius: 8px; + border-radius: $devui-border-radius-full; @include status-color; } diff --git a/devui/badge/badge.component.ts b/devui/badge/badge.component.ts index 24658f76..1ea9f4f4 100644 --- a/devui/badge/badge.component.ts +++ b/devui/badge/badge.component.ts @@ -22,8 +22,23 @@ export class BadgeComponent implements AfterViewInit { @Input() maxCount = 99; @Input() showDot = false; @Input() status: BadgeStatusType; - @Input() badgePos: BadgePositionType = 'top-right'; - @Input() offsetXY: [number, number]; + /** + * @deprecated + * 用position替代 + */ + @Input() set badgePos(value: BadgePositionType) { + this.position = value; + } + @Input() position: BadgePositionType = 'top-right'; + /** + * @deprecated + * 用offset替代 + */ + @Input() set offsetXY(value: [number, number]) { + this.offset = value; + } + @Input() offset: [number, number]; + @Input() bgColor: string; @Input() textColor: string; @@ -33,6 +48,15 @@ export class BadgeComponent implements AfterViewInit { this.hasContent = contents.length ? true : false; } + parseCountToNumber() { + if(typeof(this.count) === 'number') { + return this.count; + } else { + const parseNumber = parseInt(this.count); + return isNaN(parseNumber) ? -1 : parseNumber; + } + } + constructor( private cdr: ChangeDetectorRef, ) { } diff --git a/devui/badge/badge.types.ts b/devui/badge/badge.types.ts index dadd283c..40ece14d 100644 --- a/devui/badge/badge.types.ts +++ b/devui/badge/badge.types.ts @@ -1,5 +1,5 @@ /** * Define Status Type */ -export type BadgeStatusType = 'danger' | 'warning' | 'waiting' | 'success' | 'info'; +export type BadgeStatusType = 'danger' | 'warning' | 'waiting' | 'success' | 'info' | 'common'; export type BadgePositionType = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; diff --git a/devui/badge/demo/badge-demo.component.html b/devui/badge/demo/badge-demo.component.html index 11e96a49..925ca015 100644 --- a/devui/badge/demo/badge-demo.component.html +++ b/devui/badge/demo/badge-demo.component.html @@ -9,14 +9,6 @@
-
-
{{ 'components.badge.dotDemo.title' | translate }}
-
{{ 'components.badge.dotDemo.description' | translate }}
- - - -
-
{{ 'components.badge.countDemo.title' | translate }}
{{ 'components.badge.countDemo.description' | translate }}
@@ -25,6 +17,14 @@
+
+
{{ 'components.badge.dotDemo.title' | translate }}
+
{{ 'components.badge.dotDemo.description' | translate }}
+ + + +
+
{{ 'components.badge.statusDemo.title' | translate }}
{{ 'components.badge.statusDemo.description' | translate }}
diff --git a/devui/badge/demo/badge-demo.component.ts b/devui/badge/demo/badge-demo.component.ts index 71559ae1..638b9434 100644 --- a/devui/badge/demo/badge-demo.component.ts +++ b/devui/badge/demo/badge-demo.component.ts @@ -60,8 +60,8 @@ export class BadgeDemoComponent implements OnInit, OnDestroy { setNavValues(values) { this.navItems = [ { dAnchorLink: 'badge-basic', value: values['badge-basic'] }, - { dAnchorLink: 'badge-dot', value: values['badge-dot'] }, { dAnchorLink: 'badge-count', value: values['badge-count'] }, + { dAnchorLink: 'badge-dot', value: values['badge-dot'] }, { dAnchorLink: 'badge-status', value: values['badge-status'] }, { dAnchorLink: 'position', value: values['position'] }, { dAnchorLink: 'custom', value: values['custom'] } diff --git a/devui/badge/demo/count/count.component.html b/devui/badge/demo/count/count.component.html index a8db8bcd..94b62df2 100644 --- a/devui/badge/demo/count/count.component.html +++ b/devui/badge/demo/count/count.component.html @@ -3,11 +3,11 @@
diff --git a/devui/badge/demo/count/count.component.scss b/devui/badge/demo/count/count.component.scss index f945dd2a..d74624a5 100644 --- a/devui/badge/demo/count/count.component.scss +++ b/devui/badge/demo/count/count.component.scss @@ -2,25 +2,20 @@ .title { font-size: $devui-font-size-card-title; - margin-bottom: 10px; + margin-bottom: 8px; font-weight: bold; } .menu { - left: 0; width: 200px; - background: $devui-global-bg; + background: $devui-base-bg; + box-shadow: $devui-shadow-length-base $devui-light-shadow; &-item { - position: relative; padding: 8px 16px; - display: block; - - .right-badge { - position: absolute; - right: 20px; - top: 12px; - } + display: flex; + align-items: center; + justify-content: space-between; .item-title { color: $devui-text; diff --git a/devui/badge/demo/custom/custom.component.html b/devui/badge/demo/custom/custom.component.html index 4743034e..c56e82be 100644 --- a/devui/badge/demo/custom/custom.component.html +++ b/devui/badge/demo/custom/custom.component.html @@ -2,7 +2,7 @@ - + Code diff --git a/devui/badge/demo/position/position.component.html b/devui/badge/demo/position/position.component.html index eb7d2ec8..e50b5f5a 100644 --- a/devui/badge/demo/position/position.component.html +++ b/devui/badge/demo/position/position.component.html @@ -1,8 +1,8 @@
- + - +
diff --git a/devui/badge/doc/api-cn.md b/devui/badge/doc/api-cn.md index 5ad9f1ef..5f8dc1d2 100644 --- a/devui/badge/doc/api-cn.md +++ b/devui/badge/doc/api-cn.md @@ -6,10 +6,10 @@ import { BadgeModule } from 'ng-devui/badge'; 在页面中使用: ```html - +
未读消息
- + ``` # Badge @@ -20,8 +20,8 @@ import { BadgeModule } from 'ng-devui/badge'; | count | `number` | -- | 可选,设置基本徽章和计数徽章中显示的数目 | [基本徽章](demo#badge-basic) | | maxCount | `number` | 99 | 可选,设置基本徽章和计数徽章最大可显示数目,当 count > maxCount 时显示maxCount+ | [基本徽章](demo#badge-basic) | | showDot | `boolean` | false | 可选,true时为点状徽章(有包裹)或状态徽章(无包裹),false时为基本徽章(有包裹)或计数徽章(无包裹) | [点状徽章](demo#badge-dot) | -| status |`BadgeStatusType` | -- | 可选,状态色 'danger' \| 'warning' \| 'waiting' \| 'success' \| 'info' | [基本徽章](demo#badge-basic) | -| badgePos | `BadgePositionType` | 'top-right' | 可选,徽标位置 'top-left' \| 'top-right' \| 'bottom-left' \| ''bottom-right'' | [徽章位置](demo#position) | -| offsetXY | `[number, number]` | -- | 可选,有包裹时徽标位置偏移量,格式为[x,y],单位为px。x为相对right偏移量(right: -x `px`),y为相对top偏移量(top: y `px`) | [自定义](demo#custom) | +| status |`BadgeStatusType` | -- | 可选,状态色 'danger' \| 'warning' \| 'waiting' \| 'success' \| 'info' \| 'common' | [基本徽章](demo#badge-basic) | +| position | `BadgePositionType` | 'top-right' | 可选,徽标位置 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right' | [徽章位置](demo#position) | +| offset | `[number, number]` | -- | 可选,有包裹时徽标位置偏移量,格式为[x,y],单位为px。x为相对right偏移量(right: -x `px`),y为相对top偏移量(top: y `px`) | [自定义](demo#custom) | | bgColor | `string` | -- | 可选,自定义徽标色,此时status参数设置的徽章状态色失效 | [自定义](demo#custom) | | textColor | `string` | -- | 可选, 可自定义徽标文字颜色 | [自定义](demo#custom) | diff --git a/devui/badge/doc/api-en.md b/devui/badge/doc/api-en.md index e128fa23..1d77608a 100644 --- a/devui/badge/doc/api-en.md +++ b/devui/badge/doc/api-en.md @@ -6,10 +6,10 @@ import { BadgeModule } from 'ng-devui/badge'; In the page: ```html - +
Unread messages
- + ``` # Badge @@ -20,8 +20,8 @@ In the page: | count | `number` | -- | Optional. Set the number of basic badges and count badges to be displayed. | [Basic Badge](demo#badge-basic) | | maxCount | `number` | 99 | Optional. Sets the maximum number of basic and counting badges that can be displayed. When count is greater than maxCount, maxCount+ is displayed. | [Basic Badge](demo#badge-basic) | | showDot | `boolean` | false | Optional. The value true indicates the dot badge (with package) or status badge (without package). The value false indicates the basic badge (with package) or count badge (without package). | [Dotted Badge](demo#badge-dot) | -| status |`BadgeStatusType` | -- | Optional. The status color is'danger'\| 'warning' \| 'waiting' \| 'success' \| 'info'. | [Basic Badge](demo#badge-basic) | -| badgePos | `BadgePositionType` | 'top-right' | Optional. Logo position'top-left' \|'top-right' \|'bottom-left' \|'bottom-right'. | [Badge Position](demo#position) | -| offsetXY | `[number, number]` | -- |Optional. Indicates the logo position offset when there is a package. The format is [x,y], in px. This parameter is optional. x is the relative right offset (right: -x `px`), y is the relative top offset (top: y `px`). | [Custom](demo#custom) | +| status |`BadgeStatusType` | -- | Optional. The status color is'danger'\| 'warning' \| 'waiting' \| 'success' \| 'info' \| 'common'. | [Basic Badge](demo#badge-basic) | +| position | `BadgePositionType` | 'top-right' | Optional. Logo position'top-left' \|'top-right' \|'bottom-left' \|'bottom-right'. | [Badge Position](demo#position) | +| offset | `[number, number]` | -- |Optional. Indicates the logo position offset when there is a package. The format is [x,y], in px. This parameter is optional. x is the relative right offset (right: -x `px`), y is the relative top offset (top: y `px`). | [Custom](demo#custom) | | bgColor | `string` | -- | Optional. The badge color can be customized. In this case, the badge status color specified by status is invalid.| [Custom](demo#custom) | | textColor | `string` | -- | Optional. You can customize the logo text color. | [Custom](demo#custom) | diff --git a/devui/breadcrumb/breadcrumb.component.scss b/devui/breadcrumb/breadcrumb.component.scss index 89487c36..cc6a49ee 100644 --- a/devui/breadcrumb/breadcrumb.component.scss +++ b/devui/breadcrumb/breadcrumb.component.scss @@ -1,6 +1,7 @@ :host { display: flex; -webkit-align-items: center; + min-height: 28px; ::ng-deep d-breadcrumb-item:last-child { .devui-breadcrumb-separator { diff --git a/devui/breadcrumb/breadcrumb.component.ts b/devui/breadcrumb/breadcrumb.component.ts index fb0c64a1..6e3ccc60 100644 --- a/devui/breadcrumb/breadcrumb.component.ts +++ b/devui/breadcrumb/breadcrumb.component.ts @@ -1,8 +1,4 @@ -import { - Component, - Input, - TemplateRef, -} from '@angular/core'; +import { Component, forwardRef, Input, TemplateRef } from '@angular/core'; import { BreadCrumbService } from './breadcrumb.service'; import { BREADCRUMB } from './breadcrumb.token'; import { SourceConfig } from './breadcrumb.type'; @@ -13,9 +9,10 @@ import { SourceConfig } from './breadcrumb.type'; templateUrl: './breadcrumb.component.html', styleUrls: ['./breadcrumb.component.scss'], preserveWhitespaces: false, - providers: [ - {provide: BREADCRUMB, useExisting: BreadCrumbComponent} - ], + providers: [{ + provide: BREADCRUMB, + useExisting: forwardRef(() => BreadCrumbComponent) + }], }) export class BreadCrumbComponent { @Input() separatorIcon: TemplateRef; diff --git a/devui/breadcrumb/public-api.ts b/devui/breadcrumb/public-api.ts index 1883661b..d985c26e 100644 --- a/devui/breadcrumb/public-api.ts +++ b/devui/breadcrumb/public-api.ts @@ -2,4 +2,5 @@ export * from './breadcrumb-item/breadcrumb-item.component'; export * from './breadcrumb.component'; export * from './breadcrumb.module'; export * from './breadcrumb.service'; +export * from './breadcrumb.token'; export * from './breadcrumb.type'; diff --git a/devui/button/button.component.scss b/devui/button/button.component.scss index 7bc56c12..389a2573 100755 --- a/devui/button/button.component.scss +++ b/devui/button/button.component.scss @@ -1,6 +1,5 @@ -@import '../style/mixins/index'; + @import '../style/theme/color'; -@import '../style/theme/variables'; @import '../style/core/font'; @import '../style/theme/corner'; @import '../style/core/animation'; diff --git a/devui/button/button.component.ts b/devui/button/button.component.ts index 898ec823..b53aaf41 100755 --- a/devui/button/button.component.ts +++ b/devui/button/button.component.ts @@ -12,6 +12,9 @@ import { ViewChild } from '@angular/core'; export type IButtonType = 'button' | 'submit' | 'reset'; +/** + * 类型中text-dark参数废弃 + */ export type IButtonStyle = 'common' | 'primary' | 'text' | 'text-dark' | 'danger' | 'success' | 'warning'; export type IButtonPosition = 'left' | 'right' | 'default'; export type IButtonSize = 'lg' | 'md' | 'sm' | 'xs'; @@ -28,6 +31,10 @@ export class ButtonComponent implements AfterContentChecked { @Input() type: IButtonType = 'button'; @Input() bsStyle: IButtonStyle = 'primary'; @Input() bsSize: IButtonSize = 'md'; + /** + * @deprecated + * 原左右按钮用按钮组实现 + */ @Input() bsPosition: IButtonPosition = 'default'; @Input() bordered: boolean; @Input() icon: string; diff --git a/devui/button/demo/button-demo.component.html b/devui/button/demo/button-demo.component.html index 16b02255..db9f7136 100755 --- a/devui/button/demo/button-demo.component.html +++ b/devui/button/demo/button-demo.component.html @@ -26,12 +26,6 @@
-
-
{{ 'components.button.button-left-right.title' | translate }}
- - - -
{{ 'components.button.button-danger.title' | translate }}
diff --git a/devui/button/demo/button-demo.component.ts b/devui/button/demo/button-demo.component.ts index 65559374..e7e3280f 100755 --- a/devui/button/demo/button-demo.component.ts +++ b/devui/button/demo/button-demo.component.ts @@ -28,12 +28,6 @@ export class ButtonDemoComponent implements OnInit, OnDestroy { { title: 'TS', language: 'typescript', code: require('./primary/primary.component.ts?raw') }, ]; - leftRightSource: Array = [ - { title: 'HTML', language: 'xml', code: require('./left-right/left-right.component.html?raw') }, - { title: 'TS', language: 'typescript', code: require('./left-right/left-right.component.ts?raw') }, - { title: 'SCSS', language: 'css', code: require('./left-right/left-right.component.scss?raw') }, - ]; - textSource: Array = [ { title: 'HTML', language: 'xml', code: require('./text/text.component.html?raw') }, { title: 'TS', language: 'typescript', code: require('./text/text.component.ts?raw') }, diff --git a/devui/button/demo/button-demo.module.ts b/devui/button/demo/button-demo.module.ts index 64943546..4c06d90c 100755 --- a/devui/button/demo/button-demo.module.ts +++ b/devui/button/demo/button-demo.module.ts @@ -16,7 +16,6 @@ import { CommonComponent } from './common/common.component'; import { DangerComponent } from './danger/danger.component'; import { GroupsComponent } from './groups/groups.component'; import { IconComponent } from './icon/icon.component'; -import { LeftRightComponent } from './left-right/left-right.component'; import { LoadingComponent } from './loading/loading.component'; import { PrimaryComponent } from './primary/primary.component'; import { SizeComponent } from './size/size.component'; @@ -48,7 +47,6 @@ import { TextComponent } from './text/text.component'; IconComponent, LoadingComponent, PrimaryComponent, - LeftRightComponent, DangerComponent, TextComponent, CombinationComponent, diff --git a/devui/button/demo/combination/combination.component.html b/devui/button/demo/combination/combination.component.html index 088511f1..e0f6ad92 100644 --- a/devui/button/demo/combination/combination.component.html +++ b/devui/button/demo/combination/combination.component.html @@ -3,7 +3,7 @@ Cancel
- Back - Go - Cancel + Back + Go + Cancel
diff --git a/devui/button/demo/left-right/left-right.component.html b/devui/button/demo/left-right/left-right.component.html deleted file mode 100644 index 34e3591f..00000000 --- a/devui/button/demo/left-right/left-right.component.html +++ /dev/null @@ -1,2 +0,0 @@ -Left -Right diff --git a/devui/button/demo/left-right/left-right.component.scss b/devui/button/demo/left-right/left-right.component.scss deleted file mode 100644 index a618fc5c..00000000 --- a/devui/button/demo/left-right/left-right.component.scss +++ /dev/null @@ -1,15 +0,0 @@ -@import '~ng-devui/styles-var/devui-var.scss'; - -d-button:last-child { - position: relative; - - &::before { - content: ' '; - position: absolute; - top: 4px; - bottom: 4px; - left: 0; - width: 1px; - background-color: $devui-light-text; - } -} diff --git a/devui/button/demo/left-right/left-right.component.ts b/devui/button/demo/left-right/left-right.component.ts deleted file mode 100644 index 1eb5176d..00000000 --- a/devui/button/demo/left-right/left-right.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'd-button-left-right', - templateUrl: './left-right.component.html', - styleUrls: ['./left-right.component.scss'] -}) -export class LeftRightComponent {} diff --git a/devui/button/demo/size/size.component.html b/devui/button/demo/size/size.component.html index e5a0bf5b..b6c87c48 100644 --- a/devui/button/demo/size/size.component.html +++ b/devui/button/demo/size/size.component.html @@ -1,4 +1,6 @@ - Extra small - Small - Middle - Large +
+ Extra small + Small + Middle + Large +
diff --git a/devui/button/demo/text/text.component.html b/devui/button/demo/text/text.component.html index 9581c611..79d492ed 100755 --- a/devui/button/demo/text/text.component.html +++ b/devui/button/demo/text/text.component.html @@ -1,4 +1,3 @@ lgText Text -Text dark Disabled diff --git a/devui/button/doc/api-cn.md b/devui/button/doc/api-cn.md index 72b1ed34..7e14ff2e 100644 --- a/devui/button/doc/api-cn.md +++ b/devui/button/doc/api-cn.md @@ -18,15 +18,15 @@ import { ButtonModule } from 'ng-devui/button'; | :----------------: | :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | | | id | `string` | -- | 可选,button id | [主要按钮](demo#button-primary) | | type | [`IButtonType`](#ibuttontype) | 'button' | 可选,类型 `'button' \| 'submit' \| 'reset' ` | [警示按钮](demo#button-danger) | -| bsStyle | [`IButtonStyle`](#ibuttonstyle) | 'primary' | 可选,风格 `'primary' \| 'common' \| 'text' \| 'text-dark' \| 'danger'` | [次要按钮](demo#button-common) | +| bsStyle | [`IButtonStyle`](#ibuttonstyle) | 'primary' | 可选,风格 `'primary' \| 'common' \| 'text' \| 'danger'` | [次要按钮](demo#button-common) | | bsSize | [`IButtonSize`](#ibuttonsize) | 'md' | 可选,大小 `'lg' \| 'md' \| 'sm' \| 'xs'` | [按钮尺寸](demo#button-size) | -| bsPosition |[`IButtonPosition`](#ibuttonposition) |'default' | 可选,按钮位置 `'default' \| 'left' \| 'right'` | [左右按钮](demo#button-left-right) | | bordered | `boolean` | false | 可选,是否有边框 | [自动获得焦点](demo#button-auto-focus) | | icon | `string` | -- | 可选, 自定义按钮图标 | [图标按钮](demo#button-icon) | | showLoading | `boolean` | false | 可选,是否显示加载提示 | [加载中状态](demo#button-loading) | | width | `string` | -- | 可选,button 宽度 | [主要按钮与次要按钮组合](demo#button-primary-and-common) | | disabled | `boolean` | false | 可选,是否禁用 button | [主要按钮](demo#button-primary) | | autofocus | `boolean` | false | 可选,按钮加载时是否自动获得焦点 | [自动获得焦点](demo#button-auto-focus) | +|loadingTemplateRef|`TemplateRef`| --| 可选,按钮加载时的展示模板 | | ## d-button 事件 @@ -56,7 +56,7 @@ export type IButtonType = 'button' | 'submit' | 'reset'; 默认值为'primary',表示button风格 ```ts -export type IButtonStyle = 'common' | 'primary' | 'text' | 'text-dark' | 'danger'; +export type IButtonStyle = 'common' | 'primary' | 'text' | 'danger'; ``` ### IButtonPosition diff --git a/devui/button/doc/api-en.md b/devui/button/doc/api-en.md index b626daa9..6ed51229 100644 --- a/devui/button/doc/api-en.md +++ b/devui/button/doc/api-en.md @@ -18,15 +18,15 @@ In the page: | :----------------: | :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | | | id | `string` | -- | Optional. ID of the button. | [Primary Buttons](demo#button-primary)| | type | [`IButtonType`](#ibuttontype) | 'button' | Optional. The type is `'button' \| 'submit' \| 'reset'` |[Danger Buttons](demo#button-danger) | -| bsStyle | [`IButtonStyle`](#ibuttonstyle) | 'primary' | Optional. The style is `'primary' \| 'common' \| 'text' \| 'text-dark' \| 'danger'` | [Common Buttons](demo#button-common) | +| bsStyle | [`IButtonStyle`](#ibuttonstyle) | 'primary' | Optional. The style is `'primary' \| 'common' \| 'text' \| 'danger'` | [Common Buttons](demo#button-common) | | bsSize | [`IButtonSize`](#ibuttonsize) | 'md' | Optional. The size is `'lg' \| 'md' \| 'sm' \| 'xs'` | [Button Size](demo#button-size) | -| bsPosition |[`IButtonPosition`](#ibuttonposition) |'default'| Optional. The button position is `'default' \| 'left' \| 'right'` | [Left & Right Buttons](demo#button-left-right) | | bordered | `boolean` | false | Optional. Indicating whether a border exists | [Auto-focus Buttons](demo#button-auto-focus)| | icon | `string` | -- | Optional. Customized button icon | [Icon Buttons](demo#button-icon) | | showLoading | `boolean` | false | Optional. Indicating whether to display the loading prompt | [Loading Buttons](demo#button-loading) | | width | `string` | -- | Optional. Button width |[Combinations of Primary & Common Buttons](demo#button-primary-and-common) | | disabled | `boolean` | false | Optional. Indicating whether to disable the button | [Primary Buttons](demo#button-primary) | | autofocus | `boolean` | false | Optional. Indicating whether to automatically obtain the focus during button loading | [Auto-focus Buttons](demo#button-auto-focus) | +|loadingTemplateRef|`TemplateRef`| --| Optional. It is the display template when the button is loaded. | | ## d-button Event @@ -56,7 +56,7 @@ export type IButtonType = 'button' | 'submit' | 'reset'; The default value is 'primary', indicating the button style. ```ts -export type IButtonStyle = 'common' | 'primary' | 'text' | 'text-dark' | 'danger'; +export type IButtonStyle = 'common' | 'primary' | 'text' | 'danger'; ``` ### IButtonPosition diff --git a/devui/cascader/cascader-li.component.scss b/devui/cascader/cascader-li.component.scss index 7d6bac26..1932a62a 100644 --- a/devui/cascader/cascader-li.component.scss +++ b/devui/cascader/cascader-li.component.scss @@ -8,8 +8,8 @@ } .devui-dropdown-item { - height: 32px; - padding: 8px 12px; + height: 36px; + padding: 0 12px; cursor: pointer; display: flex; align-items: center; diff --git a/devui/cascader/cascader.component.html b/devui/cascader/cascader.component.html index f997a7dc..b45c96d5 100644 --- a/devui/cascader/cascader.component.html +++ b/devui/cascader/cascader.component.html @@ -22,7 +22,7 @@ [ngModel]="showTextValue" (ngModelChange)="valueChanges($event)" /> -
+
-
+
t !== '') ).subscribe(value => { + clearTimeout(this.timer); if (this.mainDropdown && !this.mainDropdown.isOpen) { this.mainDropdown.isOpen = true; } @@ -361,7 +364,7 @@ export class CascaderComponent implements OnInit, OnDestroy, OnChanges, ControlV this.writeValue(this.cascaderSrv.currentValue); } // 在动画结束后再设置参数,防止panel中内容突变,动画时间200 - setTimeout(() => { + this.timer = setTimeout(() => { this.showSearchPanel = false; }, 200); } diff --git a/devui/cascader/cascader.spec.ts b/devui/cascader/cascader.spec.ts index bbd67723..93f51f7d 100644 --- a/devui/cascader/cascader.spec.ts +++ b/devui/cascader/cascader.spec.ts @@ -712,11 +712,13 @@ describe('cascader', () => { })); it('multiple search should work', fakeAsync(() => { + clickDropDownToggle(); const searchInputEle = fixture.debugElement.query(By.css('.inner-input')).nativeElement; expect(searchInputEle).toBeTruthy(); })); it ('multiple search result should work', fakeAsync(() => { + clickDropDownToggle(); const searchInputEle = fixture.debugElement.query(By.css('.inner-input')).nativeElement; searchInputEle.value = '1-1'; searchInputEle.dispatchEvent(new Event('input', {})); @@ -736,6 +738,7 @@ describe('cascader', () => { })); it ('click active result should not work', fakeAsync(() => { + clickDropDownToggle(); const searchInputEle = fixture.debugElement.query(By.css('.inner-input')).nativeElement; searchInputEle.value = '1-1'; searchInputEle.dispatchEvent(new Event('input', {})); diff --git a/devui/cascader/demo/basic/basic.component.html b/devui/cascader/demo/basic/basic.component.html index 08403016..eedae38b 100644 --- a/devui/cascader/demo/basic/basic.component.html +++ b/devui/cascader/demo/basic/basic.component.html @@ -17,7 +17,7 @@

click mode

(ngModelChange)="onChanges($event)" [showPath]="true" [allowClear]="true" - [dropdownWidth]="120" + [dropdownWidth]="130" >

data empty

diff --git a/devui/cascader/demo/search-cascader/search-cascader.component.ts b/devui/cascader/demo/search-cascader/search-cascader.component.ts index e7a9f45d..c7d92ced 100644 --- a/devui/cascader/demo/search-cascader/search-cascader.component.ts +++ b/devui/cascader/demo/search-cascader/search-cascader.component.ts @@ -17,7 +17,7 @@ export class SearchCascaderComponent { { label: 'option1-1-1', value : 8, - children: [] + isLeaf: true }, { label: 'option1-1-2', diff --git a/devui/cascader/demo/template-cascader/template-cascader.component.html b/devui/cascader/demo/template-cascader/template-cascader.component.html index 986c9840..2cc98420 100644 --- a/devui/cascader/demo/template-cascader/template-cascader.component.html +++ b/devui/cascader/demo/template-cascader/template-cascader.component.html @@ -7,7 +7,7 @@

template

[trigger]="'click'" (ngModelChange)="onChanges($event)" [allowClear]="true" - [dropdownWidth]="120" + [dropdownWidth]="160" [dropDownItemTemplate]="dropItem" > diff --git a/devui/category-search/category-search.component.html b/devui/category-search/category-search.component.html index 7858d051..3b0ce30f 100644 --- a/devui/category-search/category-search.component.html +++ b/devui/category-search/category-search.component.html @@ -68,49 +68,11 @@ dDropDownMenu class="devui-dropdown-menu devui-tag-dropdown-menu devui-dropdown-overlay devui-dropdown-menu-fix" [ngClass]="{ 'max-height': item.type !== 'treeSelect' }" - [ngSwitch]="item.type" > - - - - - - - -
@@ -135,7 +97,7 @@ [(ngModel)]="searchKey" (ngModelChange)="searchKeyChangeEvent($event)" (click)="openMenu(inputDropdown, $event)" - (keyup)="checkInputSearching($event); openMenu(inputDropdown, $event)" + (keyup)="checkInputSearching(); openMenu(inputDropdown, $event)" (keydown.backspace)="backspaceEvent(inputDropdown)" (keydown.enter)="searchInputValue($event); closeMenu(inputDropdown)" (focus)="isHover = false; isFocus = true" @@ -164,64 +126,41 @@ -
  • - {{ i18nCategorySearchText?.getSearchMessage(searchKey) }} -
  • -
  • - {{ i18nCategorySearchText?.getFindingMessage(item?.label) }} +
  • + {{ showSearchConfig.keywordDescription(searchKey) }}
  • -
    -
    {{ i18nCategorySearchText?.selectFilterCondition }}:
    - +
    +
    + +
    + {{ showSearchConfig.categoryDescription }} +
    + +
    - - - + - - - - - @@ -328,7 +267,7 @@ #seeMoreDropdown="d-dropdown" dDropDown appendToBody - [alignOrigin]="PrimeContainerRef" + [alignOrigin]="primeContainer" [appendToBodyDirections]="['rightDown', 'rightUp', 'leftDown', 'leftUp']" >
    -
      +
      • {{ item?.groupName }}
        - + +
        {{ i18nCommonText?.noData }}
        +
        + +
        @@ -406,13 +349,13 @@
      - + @@ -431,7 +374,7 @@ - +
      @@ -450,7 +393,7 @@
    - +
    @@ -474,7 +417,7 @@
    - +
    - +
    - +
      {{ i18nCategorySearchText?.selected }} @@ -589,7 +532,3 @@ {{ i18nCategorySearchText?.cancel }}
    - - -
    {{ i18nCommonText?.noData }}
    -
    diff --git a/devui/category-search/category-search.component.scss b/devui/category-search/category-search.component.scss index 3c1761f5..0bddd3a2 100644 --- a/devui/category-search/category-search.component.scss +++ b/devui/category-search/category-search.component.scss @@ -9,6 +9,7 @@ width: 100%; padding: 0 8px; display: flex; + align-items: flex-start; height: 32px; background: transparent; transition: border $devui-animation-duration-slow $devui-animation-ease-in-out-smooth; @@ -32,20 +33,21 @@ overflow: hidden; overflow-x: auto; position: relative; - top: -1px; .devui-category-search-line { display: flex; flex-flow: row nowrap; justify-content: flex-start; - align-items: center; + align-items: flex-start; width: 100%; height: 30px; & > li { + display: flex; + align-items: center; flex-grow: 0; white-space: nowrap; - line-height: 30px; + height: 30px; } .devui-category-search-input { @@ -56,6 +58,12 @@ min-width: 160px; padding-right: 20px; + input { + width: auto; + height: 30px; + font-size: $devui-font-size-sm; + } + .devui-category-search-toggle { padding-left: 0; } @@ -105,7 +113,7 @@ .devui-color-block-sm { width: 8px; height: 8px; - border-radius: 2px; + border-radius: $devui-border-radius; margin-right: 4px; display: inline-block; position: relative; @@ -179,7 +187,7 @@ d-tag { .devui-dropdown-operation-area { border-top: 1px solid $devui-dividing-line; - padding-top: 16px; + padding-top: 8px; margin: 8px 0; display: flex; justify-content: center; @@ -279,7 +287,7 @@ d-tag { flex-flow: row wrap; align-items: center; justify-content: flex-start; - padding: 4px 4px 0; + padding: 4px; max-height: 390px; overflow: auto; @@ -299,7 +307,7 @@ d-tag { li a { display: block; line-height: 32px; - border-radius: 4px; + border-radius: $devui-border-radius; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -366,7 +374,7 @@ d-tag { width: 12px; height: 12px; margin-right: 8px; - border-radius: 2px; + border-radius: $devui-border-radius; top: -1px; position: relative; vertical-align: middle; @@ -466,7 +474,7 @@ d-tag { .devui-dropdown-menu-tip { cursor: text; - padding: 12px; + padding: 12px 12px 0; pointer-events: none; color: $devui-aide-text; } diff --git a/devui/category-search/category-search.component.ts b/devui/category-search/category-search.component.ts index 42bdb42a..022652fe 100644 --- a/devui/category-search/category-search.component.ts +++ b/devui/category-search/category-search.component.ts @@ -1,14 +1,15 @@ import { DOCUMENT } from '@angular/common'; import { + AfterContentInit, AfterViewInit, Component, + ContentChildren, ElementRef, EventEmitter, Inject, Input, OnChanges, OnDestroy, - OnInit, Output, QueryList, SimpleChanges, @@ -23,17 +24,27 @@ import { I18nInterface, I18nService } from 'ng-devui/i18n'; import { ITreeItem } from 'ng-devui/tree'; import { DefaultIcons } from 'ng-devui/tree-select'; import { DateConverter, DefaultDateConverter } from 'ng-devui/utils'; -import { cloneDeep, isEqual } from 'lodash-es'; +import { cloneDeep, isEqual, merge } from 'lodash-es'; import { fromEvent, Observable, Subject } from 'rxjs'; import { debounceTime, takeUntil, tap } from 'rxjs/operators'; -import { CreateFilterEvent, ICategorySearchTagItem, SearchEvent, SelectedTagsEvent } from './category-search.type'; +import { + ALLOWED_SEARCH_FIELD_TYPES, + COLORS, + CreateFilterEvent, + ICategorySearchTagItem, + SearchConfig, + SearchEvent, + SelectedTagsEvent +} from './category-search.type'; +import { ContentTemplateDirective } from './content-template.directive'; +import { DefaultTemplateDirective } from './default-template.directive'; @Component({ selector: 'd-category-search', templateUrl: './category-search.component.html', styleUrls: ['./category-search.component.scss'], }) -export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit { +export class CategorySearchComponent implements OnChanges, OnDestroy, AfterViewInit, AfterContentInit { static ID_SEED = 0; @Input() category: Array; @Input() defaultSearchField = []; @@ -43,9 +54,9 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af @Input() allowShowMore = false; @Input() toggleScrollToTail = false; @Input() searchKey = ''; - @Input() placeholderText; + @Input() placeholderText: string; @Input() inputReadOnly = false; - @Input() showSearchCategory = true; // 是否显示搜索关键字下拉菜单 + @Input() showSearchCategory: SearchConfig | boolean = true; // 配置是否显示搜索相关下拉选项 @Input() categoryInGroup = false; // 是否按组别显示分类下拉列表 @Input() groupOrderConfig: Array; // 用户配置组顺序 @Input() customGroupNameTemplate: TemplateRef; // 用户自定义组名称显示模板 @@ -60,10 +71,12 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af @Output() searchKeyChange = new EventEmitter(); @ViewChild('InputEle') inputEle: ElementRef; @ViewChild('ScrollBarContainer') scrollBarContainer: ElementRef; - @ViewChild('PrimeContainer') PrimeContainerRef: ElementRef; + @ViewChild('PrimeContainer') primeContainer: ElementRef; @ViewChildren('selectedDropdown') selectedDropdownList: QueryList; @ViewChildren(DatepickerProCalendarComponent) datePickers: QueryList; @ViewChildren(DatepickerProCalendarComponent, { read: ElementRef }) datePickerElements: QueryList; + @ViewChildren(DefaultTemplateDirective) defaultTemplates: QueryList; + @ContentChildren(ContentTemplateDirective) contentTemplates: QueryList; public currentSelectTag = undefined; public currentTag: ICategorySearchTagItem; public searchField; @@ -88,30 +101,54 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af scrollTimeout: any; // 如果标签在可视范围内则延时展开下拉的定时器 scrollToTailFlag = true; // 是否在更新标签内容后滚动至输入框的开关 DROPDOWN_ANIMATION_TIMEOUT = 200; // 下拉动画延迟 + DELAY = 300; // 防抖延迟 + templates = {}; // 所有类型默认模板 + customTemplates = {}; // 按field标记的自定义模板集合 + showSearchConfig: SearchConfig; document: Document; + get showFilterNameClear() { return typeof this.filterName === 'string' && this.filterName.length > 0; } - constructor(private i18n: I18nService, private elm: ElementRef, @Inject(DOCUMENT) private doc: any) { + constructor(private i18n: I18nService, @Inject(DOCUMENT) private doc: any) { + this.document = this.doc; this.dateConverter = new DefaultDateConverter(); this.id = CategorySearchComponent.ID_SEED++; - this.document = this.doc; - } - - ngOnInit() { this.setI18nText(); - this.setSearchKeyTag(); - this.setTagsMaxWidth(); + this.showSearchConfig = { + keyword: true, + keywordDescription: this.i18nCategorySearchText.getSearchMessage, + field: true, + fieldDescription: this.i18nCategorySearchText.getFindingMessage, + category: true, + categoryDescription: this.i18nCategorySearchText.selectFilterCondition, + }; } ngOnChanges(changes: SimpleChanges): void { if (changes['defaultSearchField'] || changes['category'] || changes['selectedTags']) { - this.getDefaultSearchField(); + this.init(); + } + if (changes['searchKey']) { + this.setSearchKeyTag(); + } + if (changes['showSearchCategory']) { + this.setSearchShow(); + } + if (changes['tagMaxWidth']) { + this.setTagsMaxWidth(); } } ngAfterViewInit() { + // 获取所有默认模板,规避脏检查添加延时 + setTimeout(() => + this.defaultTemplates.forEach((item) => { + this.templates[item.type] = item.template; + }) + ); + if (this.scrollBarContainer && this.inputEle) { // 初始化如果有滚动条直接位移至输入框 this.scrollToTail(true); @@ -127,17 +164,37 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af } }), // 300毫秒内不再触发滚动事件则展开下拉列表 - debounceTime(300) + debounceTime(this.DELAY) ) .subscribe((event) => this.openCurrentScrollTagMenu(event)); } } + ngAfterContentInit() { + this.setCustomTemplate(this.contentTemplates); + this.contentTemplates.changes.subscribe((data) => this.setCustomTemplate(data)); + } + ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } + setCustomTemplate(data) { + if (data?.length && this.category) { + this.customTemplates = {}; + data.forEach((item) => { + this.customTemplates[item.field] = item.template; + }); + this.category.forEach((tag) => { + tag.customTemplate = this.customTemplates[tag.field]; + }); + this.selectedTags.forEach((tag) => { + tag.customTemplate = this.customTemplates[tag.field]; + }); + } + } + setI18nText() { this.i18nCommonText = this.i18n.getI18nText().common; this.i18nCategorySearchText = this.i18n.getI18nText().categorySearch; @@ -147,6 +204,12 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af .subscribe((data) => { this.i18nCommonText = data.common; this.i18nCategorySearchText = data.categorySearch; + // 关键字分类内文本不能随语言对象变化,需重新赋值 + const [keyword] = this.selectedTags.filter((item) => item.field === 'devuiCategorySearchKeyword'); + if (keyword) { + keyword.label = this.i18nCategorySearchText['keyword']; + keyword.title = `${keyword.label}:${keyword.value?.label}`; + } }); } @@ -160,11 +223,22 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af } } + setSearchShow() { + const customConfig = + typeof this.showSearchCategory === 'boolean' + ? { + keyword: this.showSearchCategory, + field: this.showSearchCategory, + category: this.showSearchCategory, + } + : this.showSearchCategory; + this.showSearchConfig = { ...this.showSearchConfig, ...customConfig }; + } + setSearchKeyTag() { const result = this.selectedTags.filter((item) => item.field !== 'devuiCategorySearchKeyword'); if (this.searchKey && !this.currentSelectTag) { const label = this.i18nCategorySearchText['keyword']; - const value = [{ label: this.searchKey }]; const searchKeyTag = { options: [], field: 'devuiCategorySearchKeyword', @@ -173,23 +247,28 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af title: `${label}:${this.searchKey}`, value: { label: this.searchKey, + value: this.searchKey, + cache: this.searchKey, }, }; this.updateSelectedTags(searchKeyTag, true, result); this.searchKeyCache = this.searchKey; } this.searchKey = ''; - setTimeout(() => {this.enterSearch = false;}, 300); + setTimeout(() => { + this.enterSearch = false; + }, this.DELAY); return result; } - // 初始化数据 - getDefaultSearchField() { + init() { this.setValue(this.category); - this.setValue(this.selectedTags); + this.setValue(this.selectedTags, true); this.initCategoryDisplay(); if (this.defaultSearchField && this.defaultSearchField.length) { - this.searchField = this.category.filter((item) => this.defaultSearchField.includes(item.field)); + this.searchField = this.category.filter( + (item) => this.defaultSearchField.includes(item.field) && ALLOWED_SEARCH_FIELD_TYPES.includes(item.type) + ); } // 初始化时判断已选中分类中最后一项是否赋值,未赋值则识别为正在处理的分类,优先显示赋值下拉列表 if (this.selectedTags.length) { @@ -216,21 +295,30 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af if (item.type === 'treeSelect' && item.options && item.options.length) { item.value.options = cloneDeep(item.options); } - const result = (item.type === 'checkbox' || item.type === 'label') && this.getItemValue(item.value.value, item.filterKey || 'label'); - item.title = this.setTitle(item, item.type, result); + item.customTemplate = this.customTemplates[item.field]; return item; } - setValue(data) { - if (data && Array.isArray(data) && data.length) { - data.forEach((item) => {item = this.initCategoryItem(item);}); + setValue(data, isSelectedTags = false) { + if (Array.isArray(data) && data.length) { + data.forEach((item) => { + if (isSelectedTags) { + const origin = this.category.find((categoryItem) => categoryItem.field === item.field); + merge(item, origin); + const result = + (item.type === 'checkbox' || item.type === 'label') && this.getItemValue(item.value.value, item.filterKey || 'label'); + item.title = this.setTitle(item, item.type, result); + } else { + item = this.initCategoryItem(item); + } + }); } } setTitle(tag: ICategorySearchTagItem, type: string, result?: string) { return type === 'checkbox' || type === 'label' ? `${tag.label}: ${result || ''}` - : `${tag.label}: ${(tag.value && tag.value[tag.filterKey || 'label']) || ''}`; + : `${tag.label}: ${result || (tag.value && tag.value[tag.filterKey || 'label']) || ''}`; } initCategoryDisplay() { @@ -277,7 +365,8 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af this.updateFieldValue(validField, this.searchKey); this.updateSelectedTags(validField); this.searchKey = ''; - this.inputEle.nativeElement.focus(); + this.enterSearch = false; + this.finishChoose(); } searchInputValue(event) { @@ -309,6 +398,10 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af } const index = this.selectedTags.map((item) => item.field).indexOf(tag.field); if (index > -1) { + if (!tag.value.value) { + // 通过输入选择分类时避免空值覆盖已选值 + merge(tag, this.selectedTags[index]); + } this.selectedTags[index] = tag; } else { this.selectedTags.push(tag); @@ -345,7 +438,7 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af if (tags[index]) { this.currentScrollTagIndex = index; tags[index].scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' }); - this.scrollTimeout = setTimeout(() => this.openCurrentScrollTagMenu(event), 300); + this.scrollTimeout = setTimeout(() => this.openCurrentScrollTagMenu(event), this.DELAY); } } @@ -360,8 +453,33 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af } updateFieldValue(field, value) { - field.value[field.filterKey || 'label'] = value; - field.value.value = value; + const result = {}; + const filterKey = field.filterKey || 'label'; + const colorKey = field.colorKey || 'color'; + result[filterKey] = value; + switch (field.type) { + case 'radio': + field.value.value = value; + field.title = this.setTitle(field, 'radio', value); + break; + case 'label': + if (!field.options[0]?.$label) { + this.mergeToLabel(field); + } + result[colorKey] = COLORS[Math.floor(COLORS.length * Math.random())]; + result['$label'] = `${value}_${result[colorKey]}`; + field.value.value = [result]; + // setTitle中checkbox与label同样处理,不需要针对label修改类型参数 + field.title = this.setTitle(field, 'checkbox', value); + break; + case 'checkbox': + field.value.value = [result]; + // setTitle中checkbox与label同样处理,不需要针对label修改类型参数 + field.title = this.setTitle(field, 'checkbox', value); + break; + default: + } + field.value[filterKey] = value; field.value.cache = cloneDeep(field.value.value); } @@ -379,6 +497,7 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af this.selectedTagsChange.emit({ selectedTags: this.selectedTags, currentChangeTag: tag, operation: 'delete' }); this.resolveCategoryDisplay(tag, 'add'); } else { + this.searchKey = this.searchKey === this.searchKeyCache ? '' : this.searchKey; this.searchKeyCache = ''; this.searchEvent.emit({ selectedTags: this.selectedTags, searchKey: '' }); } @@ -386,7 +505,7 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af }); } - checkInputSearching(event) { + checkInputSearching() { this.isFocus = true; if (this.searchKey === '') { this.enterSearch = false; @@ -543,7 +662,7 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af // radio 单选 处理选中项方法 chooseItem(tag, chooseItem) { this.afterDropdownClosed(); - tag.value = chooseItem; + tag.value = cloneDeep(chooseItem); tag.value.cache = tag.value.value; tag.title = this.setTitle(tag, 'radio'); this.updateSelectedTags(tag); @@ -560,11 +679,16 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af } dateValueChange(tag, datepickerpro: DatepickerProCalendarComponent) { - const index = datepickerpro.currentActiveInput === 'start' ? 0 : 1; - if (tag.value.value) { - tag.value.value[index] = datepickerpro.curActiveDate; + if (datepickerpro.dateValue.length) { + const index = datepickerpro.currentActiveInput === 'start' ? 0 : 1; + if (tag.value.value && !datepickerpro.dateValue.includes('')) { + tag.value.value[index] = datepickerpro.curActiveDate; + tag.value.value = [...tag.value.value]; + } else { + tag.value.value = [datepickerpro.curActiveDate]; + } } else { - tag.value.value = [datepickerpro.curActiveDate]; + tag.value.value = []; } } @@ -617,6 +741,7 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af ? this.datePickers.find((v, i) => this.datePickerElements.toArray()[i]?.nativeElement?.id === tag.field) : this.datePickers.first; datePickerItem.updateCurPosition(); + datePickerItem.focusChange('start'); } } else if (this.currentSelectTag) { const isArrayType = this.currentSelectTag.type === 'numberRange' || this.currentSelectTag.type === 'treeSelect'; @@ -647,7 +772,9 @@ export class CategorySearchComponent implements OnInit, OnChanges, OnDestroy, Af // label 合并名称和颜色字段赋给tag,待[tag]支持传入对象后可移除 mergeToLabel(obj) { if (obj && obj.options && Array.isArray(obj.options)) { - obj.options.map((item) => {item.$label = `${item[obj.filterKey || 'label']}_${item[obj.colorKey || 'color']}`;}); + obj.options.map((item) => { + item.$label = `${item[obj.filterKey || 'label']}_${item[obj.colorKey || 'color']}`; + }); } return obj; } diff --git a/devui/category-search/category-search.module.ts b/devui/category-search/category-search.module.ts index 80142a71..ae7fadb4 100644 --- a/devui/category-search/category-search.module.ts +++ b/devui/category-search/category-search.module.ts @@ -14,9 +14,10 @@ import { TextInputModule } from 'ng-devui/text-input'; import { TreeModule } from 'ng-devui/tree'; import { PopperModule } from 'ng-devui/utils'; import { CategorySearchComponent } from './category-search.component'; +import { ContentTemplateDirective } from './content-template.directive'; +import { DefaultTemplateDirective } from './default-template.directive'; @NgModule({ - declarations: [CategorySearchComponent], imports: [ CommonModule, FormModule, @@ -32,8 +33,9 @@ import { CategorySearchComponent } from './category-search.component'; LoadingModule, TreeModule, PopperModule, - DatepickerProModule + DatepickerProModule, ], - exports: [CategorySearchComponent], + declarations: [CategorySearchComponent, ContentTemplateDirective, DefaultTemplateDirective], + exports: [CategorySearchComponent, ContentTemplateDirective, DefaultTemplateDirective], }) export class CategorySearchModule {} diff --git a/devui/category-search/category-search.type.ts b/devui/category-search/category-search.type.ts index 236568fe..7072e5a7 100644 --- a/devui/category-search/category-search.type.ts +++ b/devui/category-search/category-search.type.ts @@ -44,16 +44,16 @@ export interface ICategorySearchTagItem { */ colorKey?: 'color'; /** - * 自定义下拉模板的展示内容 - */ + * 自定义下拉模板的展示内容 + */ customTemplate?: TemplateRef; /** * 已选中值 */ value?: { label?: string; - value?: Array; - cache?: Array; + value?: string | Array; + cache?: string | Array; [propName: string]: any; }; [propName: string]: any; @@ -75,3 +75,116 @@ export interface SearchEvent { selectedTags: Array; searchKey: string; } + +export interface SearchConfig { + keyword?: boolean; + keywordDescription?: (searchKey: string) => string; + field?: boolean; + fieldDescription?: (label: string) => string; + category?: boolean; + categoryDescription?: string; +} + +export const ALLOWED_SEARCH_FIELD_TYPES = ['radio', 'checkbox', 'label']; + +export const COLORS = [ + '#f2f5fc', + '#e9edfa', + '#beccfa', + '#96adfa', + '#7693f5', + '#5e7ce0', + '#526ecc', + '#465eb8', + '#3c51a6', + '#344899', + '#2a3c85', + '#ebf6ff', + '#d1ebff', + '#b8e0ff', + '#9ed5ff', + '#85caff', + '#6cbfff', + '#4ea6e6', + '#3590cc', + '#207ab3', + '#0f6999', + '#035880', + '#edfff9', + '#cffcee', + '#acf2dc', + '#8be8cb', + '#6ddebb', + '#50d4ab', + '#3ac295', + '#27b080', + '#169e6c', + '#088c58', + '#007a45', + '#f0ffe6', + '#e5ffd4', + '#d8fcc0', + '#c5f2a7', + '#b3e890', + '#a6dd82', + '#92cc68', + '#7eba50', + '#6ca83b', + '#5e9629', + '#518519', + '#fffbf0', + '#fff1c2', + '#ffe794', + '#ffdc66', + '#ffd138', + '#fac20a', + '#e3aa00', + '#cc9600', + '#b58200', + '#9e6f00', + '#875c00', + '#fff3e8', + '#ffe1c7', + '#ffd0a6', + '#ffbf85', + '#ffad63', + '#fa9841', + '#e37d29', + '#cc6414', + '#b54e04', + '#9e3f00', + '#873400', + '#ffeeed', + '#ffd5d4', + '#ffbcba', + '#ffa4a1', + '#ff8b87', + '#f66f6a', + '#de504e', + '#c73636', + '#b02121', + '#991111', + '#820404', + '#ffedf3', + '#ffd4e3', + '#ffbad2', + '#ffa1c2', + '#fc86b0', + '#f3689a', + '#db4d83', + '#c4356e', + '#ad215b', + '#96114d', + '#800440', + '#f5f0ff', + '#e7d9ff', + '#d8c2ff', + '#caabff', + '#bc94ff', + '#a97af8', + '#8a5ce0', + '#6f42c9', + '#572db3', + '#3f1a9c', + '#2a0c85', +]; diff --git a/devui/category-search/content-template.directive.ts b/devui/category-search/content-template.directive.ts new file mode 100644 index 00000000..61ccb3e1 --- /dev/null +++ b/devui/category-search/content-template.directive.ts @@ -0,0 +1,11 @@ +import { Directive, Input, TemplateRef } from '@angular/core'; + +@Directive({ + /* eslint-disable */ + selector: 'ng-template[field]', +}) +export class ContentTemplateDirective { + @Input() field: string; + + constructor(public template: TemplateRef) {} +} diff --git a/devui/category-search/default-template.directive.ts b/devui/category-search/default-template.directive.ts new file mode 100644 index 00000000..2023fcd8 --- /dev/null +++ b/devui/category-search/default-template.directive.ts @@ -0,0 +1,11 @@ +import { Directive, Input, TemplateRef } from '@angular/core'; + +@Directive({ + /* eslint-disable */ + selector: 'ng-template[type]', +}) +export class DefaultTemplateDirective { + @Input() type: string; + + constructor(public template: TemplateRef) {} +} diff --git a/devui/category-search/demo/basic/basic.component.html b/devui/category-search/demo/basic/basic.component.html index 9fc3ebdd..9bd54274 100644 --- a/devui/category-search/demo/basic/basic.component.html +++ b/devui/category-search/demo/basic/basic.component.html @@ -1,6 +1,7 @@
    +
    {{ 'components.category-search.autoScrollDemo.title' | translate }}
    diff --git a/devui/category-search/demo/category-search-demo.component.ts b/devui/category-search/demo/category-search-demo.component.ts index 40d38b5e..59201af1 100644 --- a/devui/category-search/demo/category-search-demo.component.ts +++ b/devui/category-search/demo/category-search-demo.component.ts @@ -1,37 +1,64 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { TranslateService, TranslationChangeEvent } from '@ngx-translate/core'; -import { DevuiSourceData } from 'ng-devui/shared/devui-codebox'; -import { Subscription } from 'rxjs'; - +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { DevuiSourceData } from "ng-devui/shared/devui-codebox"; +import { TranslateService, TranslationChangeEvent } from "@ngx-translate/core"; +import { Subscription } from "rxjs"; @Component({ - selector: 'd-category-search-demo', - templateUrl: './category-search-demo.component.html', + selector: "d-category-search-demo", + templateUrl: "./category-search-demo.component.html", }) export class CategorySearchDemoComponent implements OnInit, OnDestroy { basicSource: Array = [ - { title: 'HTML', language: 'xml', code: require('./basic/basic.component.html?raw') }, - { title: 'TS', language: 'typescript', code: require('./basic/basic.component.ts?raw') }, - { title: 'DATA', language: 'typescript', code: require('./demo-data.ts?raw') }, + { + title: "HTML", + language: "xml", + code: require("./basic/basic.component.html?raw"), + }, + { + title: "TS", + language: "typescript", + code: require("./basic/basic.component.ts?raw"), + }, + { + title: "DATA", + language: "typescript", + code: require("./demo-data.ts?raw"), + }, ]; autoScrollSource: Array = [ - { title: 'HTML', language: 'xml', code: require('./auto-scroll/auto-scroll.component.html?raw') }, - { title: 'TS', language: 'typescript', code: require('./auto-scroll/auto-scroll.component.ts?raw') }, - { title: 'DATA', language: 'typescript', code: require('./demo-data.ts?raw') }, + { + title: "HTML", + language: "xml", + code: require("./auto-scroll/auto-scroll.component.html?raw"), + }, + { + title: "TS", + language: "typescript", + code: require("./auto-scroll/auto-scroll.component.ts?raw"), + }, + { + title: "DATA", + language: "typescript", + code: require("./demo-data.ts?raw"), + }, ]; navItems = []; subs: Subscription = new Subscription(); - constructor(private translate: TranslateService) { } + + constructor(private translate: TranslateService) {} ngOnInit() { this.subs.add( - this.translate.get('components.category-search.anchorLinkValues').subscribe((res) => { - this.setNavValues(res); - }) + this.translate + .get("components.category-search.anchorLinkValues") + .subscribe((res) => { + this.setNavValues(res); + }) ); - this.subs.add( this.translate.onLangChange.subscribe((event: TranslationChangeEvent) => { - const values = this.translate.instant('components.category-search.anchorLinkValues'); + const values = this.translate.instant( + "components.category-search.anchorLinkValues" + ); this.setNavValues(values); }) ); @@ -45,8 +72,14 @@ export class CategorySearchDemoComponent implements OnInit, OnDestroy { setNavValues(values) { this.navItems = [ - { dAnchorLink: 'basic-usage', value: values['basicDemo'] }, - { dAnchorLink: 'auto-scroll', value: values['autoScrollDemo'] }, + { + dAnchorLink: "basic-usage", + value: values["basicDemo"], + }, + { + dAnchorLink: "auto-scroll", + value: values["autoScrollDemo"], + }, ]; } } diff --git a/devui/category-search/demo/category-search-demo.module.ts b/devui/category-search/demo/category-search-demo.module.ts index c4826b43..56b03b4c 100644 --- a/devui/category-search/demo/category-search-demo.module.ts +++ b/devui/category-search/demo/category-search-demo.module.ts @@ -1,21 +1,24 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { CategorySearchModule } from 'ng-devui/category-search'; -import { LoadingModule } from 'ng-devui/loading'; -import { SearchModule } from 'ng-devui/search'; -import { DevUIApiComponent } from 'ng-devui/shared/devui-api/devui-api.component'; -import { DevUIApiModule } from 'ng-devui/shared/devui-api/devui-api.module'; -import { DevUICodeboxModule } from 'ng-devui/shared/devui-codebox'; -import { LazyLoadModule } from 'ng-devui/utils'; -import { TranslateModule } from '@ngx-translate/core'; -import { DDemoNavModule } from 'src/app/component/d-demo-nav.module'; -import { AutoScrollComponent } from './auto-scroll/auto-scroll.component'; -import { BasicComponent } from './basic/basic.component'; -import { CategorySearchDemoComponent } from './category-search-demo.component'; - +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { CategorySearchModule } from "ng-devui/category-search"; +import { LoadingModule } from "ng-devui/loading"; +import { SearchModule } from "ng-devui/search"; +import { DevUIApiComponent } from "ng-devui/shared/devui-api/devui-api.component"; +import { DevUIApiModule } from "ng-devui/shared/devui-api/devui-api.module"; +import { DevUICodeboxModule } from "ng-devui/shared/devui-codebox"; +import { LazyLoadModule } from "ng-devui/utils"; +import { TranslateModule } from "@ngx-translate/core"; +import { DDemoNavModule } from "src/app/component/d-demo-nav.module"; +import { AutoScrollComponent } from "./auto-scroll/auto-scroll.component"; +import { BasicComponent } from "./basic/basic.component"; +import { CategorySearchDemoComponent } from "./category-search-demo.component"; @NgModule({ - declarations: [CategorySearchDemoComponent, BasicComponent, AutoScrollComponent], + declarations: [ + CategorySearchDemoComponent, + BasicComponent, + AutoScrollComponent, + ], imports: [ TranslateModule, CommonModule, @@ -27,15 +30,23 @@ import { CategorySearchDemoComponent } from './category-search-demo.component'; LazyLoadModule, SearchModule, RouterModule.forChild([ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: CategorySearchDemoComponent }, { - path: 'api', component: DevUIApiComponent, data: { - 'zh-cn': require('!html-loader!markdown-loader!../doc/api-cn.md'), - 'en-us': require('!html-loader!markdown-loader!../doc/api-en.md') - } - } - ]) + path: "", + redirectTo: "demo", + }, + { + path: "demo", + component: CategorySearchDemoComponent, + }, + { + path: "api", + component: DevUIApiComponent, + data: { + "zh-cn": require("!html-loader!markdown-loader!../doc/api-cn.md"), + "en-us": require("!html-loader!markdown-loader!../doc/api-en.md"), + }, + }, + ]), ], }) -export class CategorySearchDemoModule { } +export class CategorySearchDemoModule {} diff --git a/devui/category-search/demo/demo-data.ts b/devui/category-search/demo/demo-data.ts index ab829b1e..18817c51 100644 --- a/devui/category-search/demo/demo-data.ts +++ b/devui/category-search/demo/demo-data.ts @@ -48,14 +48,14 @@ export const demoData: ICategorySearchTagItem[] = [ field: 'creatTime', type: 'dateRange', group: 'Time-related', - showTime: false, + showTime: true, }, { label: 'modified time', field: 'modifiedTime', type: 'dateRange', group: 'Time-related', - showTime: true, + showTime: false, }, { label: 'IP address', diff --git a/devui/category-search/doc/api-cn.md b/devui/category-search/doc/api-cn.md index d544c5f7..746d585b 100644 --- a/devui/category-search/doc/api-cn.md +++ b/devui/category-search/doc/api-cn.md @@ -23,7 +23,7 @@ import { CategorySearchModule } from 'ng-devui/category-search'; | allowSave | `boolean` | true | 可选,是否显示保存当前过滤的按钮 | [基本用法](demo#basic-usage) | | allowClear | `boolean` | true | 可选,是否显示清除当前过滤的按钮 | [基本用法](demo#basic-usage) | | allowShowMore | `boolean` | false | 可选,是否显示当前过滤条件下拉列表的按钮 | [大数据量优化展示](demo#auto-scroll) | -| showSearchCategory | `boolean` | true | 可选,是否显示搜索关键字下拉菜单 | | +| showSearchCategory | `boolean \| SearchConfig` | true | 可选,是否显示搜索关键字下拉菜单 | [自定义展示模板](demo##custom-template) | | searchKey | `string` | '' | 可选,搜索框内的默认展示值 | [基本用法](demo#basic-usage) | | beforeTagChange | `(tag, searchKey, operation) => boolean \| Promise \| Observable` | -- | 可选,改变标签前调用的方法,返回 boolean 类型,返回 false 可以阻止分类值改变 | | | toggleEvent | `(dropdown, tag?, currentSelectTag?) => void` | -- | 可选,已选分类的下拉菜单开关时调用的方法,可使用 return 阻止之后的默认方法执行 | [基本用法](demo#basic-usage) | @@ -87,9 +87,9 @@ export interface ICategorySearchTagItem { * 已选中值 */ value?: { - value: Array; // 下拉列表的选择值 label: string; // 用于显示选中值,如果指定了 filterKey 则使用该值为属性名,例如 basic demo 中的状态 - cache: Array; // 下拉列表展开时用于重置选择值的缓存数据 + value: string | Array; // 下拉列表的选择值 + cache: string | Array; // 下拉列表展开时用于重置选择值的缓存数据 }; /** * dateRange 类型是否显示时分秒 @@ -107,23 +107,32 @@ export interface ITagOption { [propName: string]: any; } -export type SelectedTagsEvent = { +export interface SelectedTagsEvent = { selectedTags: Array; currentChangeTag: ICategorySearchTagItem; operation: 'add' | 'delete' | 'clear'; }; -export type CreateFilterEvent = { +export interface CreateFilterEvent = { name: string; selectedTags: Array; keyword: string; }; -export type SearchEvent = { +export interface SearchEvent = { selectedTags: Array; searchKey: string; }; +export interface SearchConfig { + keyword?: boolean; + keywordDescription?: ((searchKey: string) => string); + field?: boolean; + fieldDescription?: ((label: string) => string); + category?: boolean; + categoryDescription?: string; +} + export type DValidateRules = | { validators?: DValidateRule[]; // 同步校验规则 diff --git a/devui/category-search/doc/api-en.md b/devui/category-search/doc/api-en.md index 91d2931d..35f359f5 100644 --- a/devui/category-search/doc/api-en.md +++ b/devui/category-search/doc/api-en.md @@ -22,7 +22,7 @@ In the page | allowSave | `boolean` | true | Optional. Whether to show save current filter button. | [Basic usage](demo#basic-usage) | | allowClear | `boolean` | true | Optional. Whether to display the button for clearing the current filter. | [Basic usage](demo#basic-usage) | | allowShowMore | `boolean` | false | Optional. Whether to display the button in the drop-down list of the current filter criteria. | [Large-scale data display optimization](demo#auto-scroll) | -| showSearchCategory | `boolean` | true | Optional. Whether to display the search keyword drop-down list. | | +| showSearchCategory | `boolean \| SearchConfig` | true | Optional. Whether to display the search keyword drop-down list. | [Customize drop-down list box](demo##custom-template) | | searchKey | `string` | '' | Optional. Default value displayed in the search box. | [Basic usage](demo#basic-usage) | | beforeTagChange | `(tag, searchKey, operation) => boolean \| Promise \| Observable` | -- | Optional. Method called before changing the tag, returns the boolean type, and returns false to prevent the classification value from changing. | | | toggleEvent | `(dropdown, tag?, currentSelectTag?) => void` | -- | Optional. Method called when the drop-down menu switch of the selected classification is enabled, which can be executed by the default method after being blocked by return. | [Basic usage](demo#basic-usage) | @@ -86,9 +86,9 @@ export interface ICategorySearchTagItem { * Selected Value */ value?: { - value: Array; // Selected value from the drop-down list box label: string; // Used to display the selected value, or the property name if filterKey is specified, such as the status in basic demo. - cache: Array; // Cached data used to reset the selection value when the drop-down list expands + value: string | Array; // Selected value from the drop-down list box + cache: string | Array; // Cached data used to reset the selection value when the drop-down list expands }; /** * Indicates whether to display hour, minute, and second for the dateRange type. @@ -123,6 +123,15 @@ export type SearchEvent = { searchKey: string; }; +export interface SearchConfig { + keyword?: boolean; + keywordDescription?: (searchKey: string) => string; + field?: boolean; + fieldDescription?: (label: string) => string; + category?: boolean; + categoryDescription?: string; +} + export type DValidateRules = | { validators?: DValidateRule[]; // Synchronize verification rules. diff --git a/devui/category-search/public-api.ts b/devui/category-search/public-api.ts index 03a39594..80e9f11b 100644 --- a/devui/category-search/public-api.ts +++ b/devui/category-search/public-api.ts @@ -1,3 +1,5 @@ -export * from './category-search.module'; export * from './category-search.component'; +export * from './category-search.module'; export * from './category-search.type'; +export * from './content-template.directive'; +export * from './default-template.directive'; diff --git a/devui/checkbox/checkbox-group.component.scss b/devui/checkbox/checkbox-group.component.scss index a4aae500..36a3e907 100755 --- a/devui/checkbox/checkbox-group.component.scss +++ b/devui/checkbox/checkbox-group.component.scss @@ -25,7 +25,7 @@ } } -.devui-checkbox-wrap ::ng-deep .devui-checkbox label { +.devui-checkbox-wrap ::ng-deep .devui-checkbox label .devui-checkbox-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; diff --git a/devui/checkbox/checkbox.component.html b/devui/checkbox/checkbox.component.html index bd50cc1d..2c5b982b 100755 --- a/devui/checkbox/checkbox.component.html +++ b/devui/checkbox/checkbox.component.html @@ -52,12 +52,14 @@ - {{ label }} - - +
    + {{ label }} + + +
    diff --git a/devui/checkbox/checkbox.component.scss b/devui/checkbox/checkbox.component.scss index 70498eaf..5b1af787 100755 --- a/devui/checkbox/checkbox.component.scss +++ b/devui/checkbox/checkbox.component.scss @@ -1,4 +1,4 @@ -@import '../style/mixins/index'; + @import '../style/theme/color'; @import '../style/theme/corner'; @import '../style/core/animation'; @@ -98,7 +98,7 @@ border-radius: $devui-border-radius; background: linear-gradient($devui-brand, $devui-brand) no-repeat center/0%; margin-right: 8px; - vertical-align: text-bottom; + flex-shrink: 0; &.devui-checkbox-default-background { background-color: $devui-base-bg; @@ -161,16 +161,16 @@ position: relative; font-weight: normal; height: 16px; - line-height: 16px; cursor: pointer; color: $devui-text; margin: 0; - display: block; + display: flex; + align-items: center; + min-width: 0; & > span { display: inline-block; box-sizing: content-box; - vertical-align: top; } } diff --git a/devui/checkbox/checkbox.component.ts b/devui/checkbox/checkbox.component.ts index 49e0b6d0..f46bea84 100755 --- a/devui/checkbox/checkbox.component.ts +++ b/devui/checkbox/checkbox.component.ts @@ -111,7 +111,7 @@ export class CheckBoxComponent implements ControlValueAccessor, OnChanges { } ngOnChanges(changes: SimpleChanges) { - if (changes.hasOwnProperty('halfchecked')) { + if (Object.prototype.hasOwnProperty.call(changes, 'halfchecked')) { this.unlockAnimation(); } } diff --git a/devui/checkbox/demo/group/checkbox-group-basic.component.html b/devui/checkbox/demo/group/checkbox-group-basic.component.html index 6c4d8521..95d0eb08 100644 --- a/devui/checkbox/demo/group/checkbox-group-basic.component.html +++ b/devui/checkbox/demo/group/checkbox-group-basic.component.html @@ -10,8 +10,8 @@

    Input Object Array

    (change)="onCheckbox1Change($event)" > - - {{ label }} + + {{ label }}
    diff --git a/devui/checkbox/doc/api-cn.md b/devui/checkbox/doc/api-cn.md index 4d91ef67..98251af0 100644 --- a/devui/checkbox/doc/api-cn.md +++ b/devui/checkbox/doc/api-cn.md @@ -29,6 +29,7 @@ import { CheckBoxModule } from 'ng-devui'; | color | `string` | -- | 可选,复选框颜色 | [基本用法](demo#checkbox-basic) | | showAnimation | `boolean` | true | 可选,控制是否显示动画 | [基本用法](demo#checkbox-basic) | ✔ | | beforeChange | `Function\|Promise\|Observable` | -- | 可选,checkbox 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 checkbox 切换 | [回调切换](demo#condition-change) | +| cssClass | `string` | -- | 可选,checkbox 的className | ## d-checkbox 事件 @@ -49,7 +50,6 @@ import { CheckBoxModule } from 'ng-devui'; | options | `Array` | [] | 可选,复选框选项数组 | [使用 CheckBoxGroup](demo#tabs-group) | | filterKey | `string` | -- | 可选,options 为对象数组时,标识选项唯一 id 的键值 | [使用 CheckBoxGroup](demo#tabs-group) | | labelTemplate | `TemplateRef` | -- | 可选,标签的自定义模板 | [使用 CheckBoxGroup](demo#tabs-group) | -| halfchecked | `boolean` | false | 可选,半选状态 | | | color | `string` | -- | 可选,复选框颜色 | [使用 CheckBoxGroup](demo#tabs-group) | | showAnimation | `boolean` | true | 可选,控制是否显示动画 | [使用 CheckBoxGroup](demo#tabs-group) |✔ | | beforeChange | `Function\|Promise\|Observable` | -- | 可选,checkbox 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 checkbox-group 切换 | [回调切换](demo#condition-change) | diff --git a/devui/checkbox/doc/api-en.md b/devui/checkbox/doc/api-en.md index 948613e1..4bdebd5e 100644 --- a/devui/checkbox/doc/api-en.md +++ b/devui/checkbox/doc/api-en.md @@ -29,6 +29,7 @@ In the page: | color | `string` | -- | Optional. Check box color | [Basic usage](demo#checkbox-basic) | | showAnimation | `boolean` | true | Optional. Controls whether to display animations. | [Basic usage](demo#checkbox-basic) | ✔ | | beforeChange | `Function\|Promise\|Observable` | -- | Callback function before checkbox switching, which returns the boolean type. If false is returned, checkbox switching is prevented. | [Stop Checkbox Switching](demo#condition-change) | +| cssClass | `string` | -- | Optional. ClassName of the checkbox. | ## d-checkbox Event @@ -49,7 +50,6 @@ In the page: | options | `Array` | [] | Optional. Check box option array | [Checkbox Group](demo#tabs-group) | | filterKey | `string` | -- | Optional. When options is an object array, this parameter identifies the key value of the unique ID of the option. | [Checkbox Group](demo#tabs-group) | | labelTemplate | `TemplateRef` | -- | Optional. Custom template of the label | [Checkbox Group](demo#tabs-group) | -| halfchecked | `boolean` | false | Optional. Half-selected | | | color | `string` | -- | Optional. Check box color | [Checkbox Group](demo#tabs-group) | | showAnimation | `boolean` | true | Optional. Controls whether to display animations. | [Checkbox Group](demo#tabs-group) |✔ | | beforeChange | `Function\|Promise\|Observable` | -- | Callback function before checkbox switching, which returns the boolean type. If false is returned, checkbox-group switching is prevented. | [Stop Checkbox Switching](demo#condition-change) | diff --git a/devui/common/demo/clipboard/clipboard.component.scss b/devui/common/demo/clipboard/clipboard.component.scss index 570c786e..e2d79ea3 100644 --- a/devui/common/demo/clipboard/clipboard.component.scss +++ b/devui/common/demo/clipboard/clipboard.component.scss @@ -2,6 +2,7 @@ .input-group { display: flex; + height: auto; input { width: 200px; @@ -15,6 +16,6 @@ outline: none !important; border: 1px solid $devui-form-control-line; border-left: none; - height: 28px; + height: inherit; } } diff --git a/devui/common/demo/lazy-load/lazy-load.component.ts b/devui/common/demo/lazy-load/lazy-load.component.ts index 02def05f..daccd89c 100644 --- a/devui/common/demo/lazy-load/lazy-load.component.ts +++ b/devui/common/demo/lazy-load/lazy-load.component.ts @@ -16,7 +16,7 @@ export class LazyLoadComponent implements OnInit { next1 = 1; showLoading1 = false; list1 = []; - target: any = window; + target = window; constructor() { } ngOnInit() { diff --git a/devui/common/doc/api-cn.md b/devui/common/doc/api-cn.md index 4f4af516..4a5c6d99 100644 --- a/devui/common/doc/api-cn.md +++ b/devui/common/doc/api-cn.md @@ -6,6 +6,12 @@ import { DCommonModule } from 'ng-devui/common'; ``` +如果你需要使用到 dLazyLoad,则引入: + +```ts +import { LazyLoadModule } from 'ng-devui/utils'; +``` + 如果你需要使用到 HelperUtils,则引入: ```ts @@ -339,10 +345,12 @@ import { HelperUtils } from 'ng-devui'; | option.header | `Object` | -- | 可选,用于设置请求 header,使用键值对的 Object 设置 header 值,左值为 header 选项的 key,右值为 header 选项的 value, 如`{'X-lang': 'en'}` | | option.responseOption | `'response' \| 'body' \| 'json'` | 'json' | 可选用于指定失败时候返回的默认格式,若格式处理失败会降级返回 | | option.filename | `string` | -- | 可选,默认不需要设置,优先设置为配置项,其次会从响应头 Content-Type 指定的 filename 获取,再其次从访问路径获取 | +| option.reportProgress | `boolean` | false | 可选,默认为flase,是否监听下载的进度,设置为true是可以用onProgress方法监听下载进度 | | option.withCredentials | `boolean` | false | 可选,调用 http 接口是否启用 xhr.withCredentials | | option.downloadWithoutDispositionHeader | `boolean` | false | 可选,默认需要请求头标记 Content-Disposition: attachment 否则当作非文件流出错处理。 设置为 true,则返回响应头 http 码为成功(2xx)的情况下则强制将返回的 response | | onError | `(res: any) => void` | -- | 可选,用于下载失败时候的回调,类型为 (response) => void, 参数 response 为请求返回的错误信息,response 试图将返回信息转为 json 如果失败则返回原返回数据的 textcontent,此处和 downloadFile 一致 | -| onSuccess | `(res: any) => void` | -- | 可选,用于下载成功回调,类型为 (response) => void, 参数 response 为请求返回的整个 Http 信息,response 内 body 的加载类型为 ArrayBuffer。由于 body 为下载的文件流,故不会将 body 转为 json 或者试图解析 body 为文本,此处与 onError 不同 | +| onSuccess | `(res: HttpResponse) => void` | -- | 可选,用于下载成功回调,类型为 (response) => void, 参数 response 为请求返回的整个 Http 信息,response 内 body 的加载类型为 ArrayBuffer。由于 body 为下载的文件流,故不会将 body 转为 json 或者试图解析 body 为文本,此处与 onError 不同 | +| onProgress | `(res: HttpProgressEvent) => void` | -- | 可选,用于下载进度事件的回调,类型为 (response) => void, 参数 response 为请求返回的下载进度信息,response的加载类型为 blob。 | 如何获取 httpClient 实例: @@ -444,3 +452,12 @@ export interface CopyResult { content: string; } ``` + +### HttpProgressEvent +```typescript +interface HttpProgressEvent { + type: HttpEventType.DownloadProgress | HttpEventType.UploadProgress; + loaded: number; + total?: number; +} +``` \ No newline at end of file diff --git a/devui/common/doc/api-en.md b/devui/common/doc/api-en.md index bff62aec..1ee73af7 100644 --- a/devui/common/doc/api-en.md +++ b/devui/common/doc/api-en.md @@ -340,9 +340,11 @@ Note: The browsers use different default opening modes for different types of fi | option.responseOption | `response' \| 'body' \| 'json'` | 'json' | Optional. This parameter is used to specify the default format returned when the format fails to be processed. If the format fails to be processed, the format will be degraded. | | option.filename | `string` | -- | Optional. This parameter is not set by default. It is set to a configuration item first, obtained from filename specified in Content-Type in the response header, and then obtained from the access path. | | option.withCredentials | `boolean` | false | Optional. Indicates whether to enable xhr.withCredentials when HTTP interfaces are invoked. | +| option.reportProgress | `boolean` | false | is optional. The default value is flase. It indicates whether to monitor the download progress. If it is set to true, the onProgress method can be used to monitor the download progress.| | option.downloadWithoutDispositionHeader | `boolean` | false | Optional. Content-Disposition: attachment is required in the request header by default. Otherwise, an error occurs in the non-file stream. If this parameter is set to true, the returned response is forcibly returned when the HTTP code in the response header is 2xx. | | onError | `(res: any) => void` | -- | Optional. It is used for callback when the download fails. The type is (response) => void. The parameter response indicates the error information returned by the request. The response attempts to convert the returned information to JSON. If the download fails, the textcontent of the original returned data is returned. The value is the same as that of downloadFile. | -| onSuccess | `(res: any) => void` | -- | Optional. It is used to call back the download success. The type is (response) => void. The parameter response indicates the entire HTTP information returned by the request. The loading type of the body in the response is ArrayBuffer. The body is the downloaded file stream. Therefore, the body is not converted to JSON or attempted to parse the body as text. This is different from onError. | +| onSuccess | `(res: HttpResponse) => void` | -- | Optional. It is used to call back the download success. The type is (response) => void. The parameter response indicates the entire HTTP information returned by the request. The loading type of the body in the response is ArrayBuffer. The body is the downloaded file stream. Therefore, the body is not converted to JSON or attempted to parse the body as text. This is different from onError. | +| onProgress | `(res: HttpProgressEvent) => void` | -- | is optional. It is used to call back the download progress event. The type is (response) => void. The parameter response is the download progress information returned by the request. The loading type of the response is blob.| How to get httpClient instance: @@ -445,3 +447,11 @@ export interface CopyResult { } ``` +### HttpProgressEvent +```typescript +interface HttpProgressEvent { + type: HttpEventType.DownloadProgress | HttpEventType.UploadProgress; + loaded: number; + total?: number; +} +``` \ No newline at end of file diff --git a/devui/common/helper-utils.ts b/devui/common/helper-utils.ts index 7851f81e..8c434f9f 100755 --- a/devui/common/helper-utils.ts +++ b/devui/common/helper-utils.ts @@ -1,4 +1,4 @@ -import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; +import { HttpClient, HttpErrorResponse, HttpEvent, HttpEventType, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; import { Directive, HostListener, Input } from '@angular/core'; declare type HttpObserve = 'body' | 'events' | 'response'; @@ -96,12 +96,14 @@ export class HelperUtils { [header: string]: string | string[]; }; responseOption?: 'response' | 'body' | 'json'; + reportProgress?: boolean; filename?: string; withCredentials?: boolean; downloadWithoutDispositionHeader?: boolean; }, onError?: (response) => void, onSuccess?: (response) => void, + onProgress?: (response) => void, ) { const requestMethod = option && option.method && option.method.toLowerCase() || 'post'; @@ -118,13 +120,14 @@ export class HelperUtils { /* eslint-disable-next-line prefer-object-spread */ const requestOption = Object.assign({}, { body: requestBody, - observe: 'response' as HttpObserve, + observe: (option.reportProgress ? 'events' : 'response') as HttpObserve, params: requestOptionParams, headers: { 'Content-Type': requestHeaderContentType }, withCredentials: option.withCredentials, - responseType: 'arraybuffer' as ResponseType + reportProgress: option.reportProgress, + responseType: (option.reportProgress ? 'blob' : 'arraybuffer') as ResponseType }, { headers: option.header }); @@ -203,27 +206,34 @@ export class HelperUtils { } }; - httpClient.request(requestMethod, requestUrl, requestOption).subscribe((res: HttpResponse) => { - const disposition = (res.headers).get('content-disposition'); - const contentType = (res.headers).get('content-type'); - if (/^attachment/i.test(disposition) || option.downloadWithoutDispositionHeader) { - const downloadFilename = option.filename || disposition && getFilenameFromDisposition(disposition) || url ; - downloadFileFromArrayBuffer(res.body, downloadFilename, contentType); - if (onSuccess) { - onSuccess(res); + httpClient.request(requestMethod, requestUrl, requestOption).subscribe((res: HttpEvent) => { + if (res.type === HttpEventType.DownloadProgress) { + if (onProgress) { + onProgress(res); } - } else { - if (onError) { - let response; - try { - response = handleResponse(res); - } catch (e) { - response = res; + } else if (res.type === HttpEventType.Response) { + const httpResponse = res as HttpResponse; + const disposition = (httpResponse.headers).get('content-disposition'); + const contentType = (httpResponse.headers).get('content-type'); + + if (/^attachment/i.test(disposition) || option.downloadWithoutDispositionHeader) { + const downloadFilename = option.filename || disposition && getFilenameFromDisposition(disposition) || url ; + downloadFileFromArrayBuffer(httpResponse.body, downloadFilename, contentType); + if (onSuccess) { + onSuccess(httpResponse); + } + } else { + if (onError) { + let response; + try { + response = handleResponse(httpResponse); + } catch (e) { + response = httpResponse; + } + onError(response); } - onError(response); } } - }, err => { if (onError) { let response; diff --git a/devui/dashboard/dashboard.component.ts b/devui/dashboard/dashboard.component.ts index c64e2f1b..678c839b 100644 --- a/devui/dashboard/dashboard.component.ts +++ b/devui/dashboard/dashboard.component.ts @@ -1,23 +1,38 @@ import { - AfterViewInit, ChangeDetectorRef, Component, ContentChildren, ElementRef, EventEmitter, HostBinding, - HostListener, Input, isDevMode, OnChanges, OnDestroy, Output, QueryList, Renderer2, SimpleChanges + Component, + ElementRef, + Input, + ContentChildren, + QueryList, + HostBinding, + ChangeDetectorRef, + Output, + OnChanges, + AfterViewInit, + SimpleChanges, + Renderer2, + HostListener, + EventEmitter, + OnDestroy, + isDevMode, } from '@angular/core'; -import { GridStack, GridStackNode, GridStackOptions } from 'gridstack'; +import { GridStackOptions, GridStack, GridStackNode } from 'gridstack'; +import { DashboardWidgetComponent } from './widget/widget.component'; import { DashBoardGridStackDefaultOption } from './grid-stack.config'; import { GridStackService } from './grid-stack.service'; -import './polyfill'; import { DashboardLibraryTrashDirective } from './widget-library/library-trash.directive'; import { DashboardLibraryWidgetDirective } from './widget-library/library-widget.directive'; -import { DashboardWidgetComponent } from './widget/widget.component'; +import './polyfill'; +import { GridStackNodeCompatible } from './grid-stack.config'; export type DashboardWidgetEvent = Array<{ widget?: DashboardWidgetComponent; // change, remove - node?: GridStackNode & { + node?: GridStackNodeCompatible & { widgetData?: any; // add willItFit?: boolean; trashData?: any; // remove }; - origNode?: GridStackNode; // add(optional) + origNode?: GridStackNodeCompatible; // add(optional) }>; @Component({ @@ -26,7 +41,7 @@ export type DashboardWidgetEvent = Array<{ styleUrls: ['./dashboard.component.scss'], providers: [GridStackService], exportAs: 'dDashboard', - preserveWhitespaces: false + preserveWhitespaces: false, }) export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { public get gridStack() { @@ -43,14 +58,17 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { @Input() widgetResizable: boolean; @HostBinding('class.d-dashboard-show-grid-block') - @Input() showGridBlock = false; + @Input() + showGridBlock = false; /* layout setting */ @Input() column: number; - @HostBinding('attr.data-gs-min-row') - @Input() minRow: number; - @HostBinding('attr.data-gs-max-row') - @Input() maxRow: number; + @HostBinding('attr.gs-min-row') + @Input() + minRow: number; + @HostBinding('attr.gs-max-row') + @Input() + maxRow: number; @Input() cellHeight: number | string; @Input() margin: number | string; @@ -62,11 +80,14 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { finalOption: GridStackOptions; renderedWidgets: Array; - @HostBinding('class.grid-stack') - addClass = true; + @HostBinding('class.grid-stack') addClass = true; - constructor(public el: ElementRef, private cdr: ChangeDetectorRef, private renderer: Renderer2, - public gridStackService: GridStackService) { } + constructor( + public el: ElementRef, + private cdr: ChangeDetectorRef, + private renderer: Renderer2, + public gridStackService: GridStackService + ) { } ngOnChanges(changes: SimpleChanges) { if (this.gridStack) { @@ -83,13 +104,13 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { this.gridStack.setAnimation(!!this.animate); } if (changes.widgetMoveable) { - this.gridStack.enableMove(!this.static && this.widgetMoveable, true); + this.gridStack.enableMove(!this.static && this.widgetMoveable); } if (changes.widgetResizable) { - this.gridStack.enableResize(!this.static && this.widgetResizable, true); + this.gridStack.enableResize(!this.static && this.widgetResizable); } if (changes.column && this.column !== undefined) { - this.gridStack.column(this.column, false); + this.gridStack.column(this.column); this.gridStackService.updateBackgroundGridBlock(); } if (changes.maxRow) { @@ -107,7 +128,7 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { } ngAfterViewInit() { - this.finalOption = { ...DashBoardGridStackDefaultOption, ...this.initOptions, ...this.getTransformOption()}; + this.finalOption = { ...DashBoardGridStackDefaultOption, ...this.initOptions, ...this.getTransformOption() }; this.renderer.addClass(this.el.nativeElement, 'grid-stack-' + this.finalOption.column); this.gridStackService.gridStack = GridStack.init(this.finalOption, this.el.nativeElement); this.gridStackService.resetAcceptWidget(this); @@ -116,13 +137,14 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { this.renderedWidgets = this.widgetComponents.toArray(); setTimeout(() => { - this.renderedWidgets.forEach(widget => widget.handleChange(widget.elem.nativeElement['gridstackNode'])); + this.renderedWidgets.forEach((widget) => widget.handleChange( + this.addGridStackNodeCompatible(widget.elem.nativeElement['gridstackNode'])) + ); + }); + this.widgetComponents.changes.subscribe((changes) => { + this.handleItemChanges(this.renderedWidgets, this.widgetComponents.toArray()); + this.renderedWidgets = this.widgetComponents.toArray(); }); - this.widgetComponents.changes - .subscribe(changes => { - this.handleItemChanges(this.renderedWidgets, this.widgetComponents.toArray()); - this.renderedWidgets = this.widgetComponents.toArray(); - }); this.dashboardInit.emit(); } @@ -136,7 +158,9 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { private getTransformOption() { const option = {}; const getOppositeKeepUndefined = (v) => { - if (v === undefined) { return undefined; } + if (v === undefined) { + return undefined; + } return !v; }; @@ -150,10 +174,10 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { float: this.float, animate: this.animate, disableDrag: getOppositeKeepUndefined(this.widgetMoveable), - disableResize: getOppositeKeepUndefined(this.widgetResizable) + disableResize: getOppositeKeepUndefined(this.widgetResizable), }); - Object.keys(option).forEach(k => { + Object.keys(option).forEach((k) => { if (option[k] === undefined) { delete option[k]; } @@ -162,11 +186,11 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { } private handleItemChanges(renderedItems: DashboardWidgetComponent[], items: DashboardWidgetComponent[]): void { - const itemsToAdd = items.filter(i => !renderedItems.some(w => w === i)); - const itemsToRemove = renderedItems.filter(w => !items.some(i => w === i)); + const itemsToAdd = items.filter((i) => !renderedItems.some((w) => w === i)); + const itemsToRemove = renderedItems.filter((w) => !items.some((i) => w === i)); this.gridStack.batchUpdate(); - itemsToAdd.forEach(i => this.gridStack.addWidget(i.elem.nativeElement)); - itemsToRemove.forEach(i => this.gridStack.removeWidget(i.elem.nativeElement)); + itemsToAdd.forEach((i) => this.gridStack.addWidget(i.elem.nativeElement)); + itemsToRemove.forEach((i) => this.gridStack.removeWidget(i.elem.nativeElement)); this.gridStack.commit(); } @@ -181,13 +205,14 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { @HostListener('added', ['$event', '$event.detail']) public addedHandler = (event, items: GridStackNode[]) => { setTimeout(() => { - const all = items.map(item => ({ - node: item, - widget: this.widgetComponents.toArray().find(widget => item.el === widget.elem.nativeElement) + const all = items.map((item) => ({ + node: this.addGridStackNodeCompatible(item), + widget: this.widgetComponents.toArray().find((widget) => item.el === widget.elem.nativeElement), })); // 处理ContentChildren数据推送进来的 - all.filter(wd => wd.widget) + all + .filter((wd) => wd.widget) .forEach(({ node, widget }) => { widget.handleChange(node); }); @@ -196,21 +221,25 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { @HostListener('change', ['$event', '$event.detail']) public changeHandler = (event, items: GridStackNode[]) => { - if (!this.gridStack) { return; } + if (!this.gridStack) { + return; + } if (!this.gridStack['_oneColumnMode']) { setTimeout(() => { - const all = items.map(item => ({ - node: item, - widget: this.renderedWidgets.find(widget => item.el === widget.elem.nativeElement) + const all = items.map((item) => ({ + node: this.addGridStackNodeCompatible(item), + widget: this.renderedWidgets.find((widget) => item.el === widget.elem.nativeElement), })); // 处理UI操作调整大小/调整位置 - all.filter(w => w.widget).forEach(({ node, widget }) => { - widget.handleChange(node); - }); - if (isDevMode() && all.some(w => !w.widget)) { + all + .filter((w) => w.widget) + .forEach(({ node, widget }) => { + widget.handleChange(node); + }); + if (isDevMode() && all.some((w) => !w.widget)) { console.warn('remove: something wrong, not handled by dashboard'); } - this.widgetChanged.emit(all.filter(w => w.widget)); + this.widgetChanged.emit(all.filter((w) => w.widget)); }); } if (this.showGridBlock) { @@ -220,65 +249,95 @@ export class DashboardComponent implements OnChanges, AfterViewInit, OnDestroy { @HostListener('removed', ['$event', '$event.detail']) public removedHandler = (event, items: GridStackNode[]) => { - const all = items.map(item => ({ - node: item, - widget: this.renderedWidgets.find(widget => item.el === widget.elem.nativeElement) + const all = items.map((item) => ({ + node: this.addGridStackNodeCompatible(item), + widget: this.renderedWidgets.find((widget) => item.el === widget.elem.nativeElement), })); // 不做处理仅提醒部分组件的移除不能被dashboard所理解 - if (isDevMode() && all.some(wd => !wd.widget)) { + if (isDevMode() && all.some((wd) => !wd.widget)) { console.warn('remove: something wrong, not handled by dashboard'); } }; handleDragInNode(node: GridStackNode, origNode: GridStackNode, widget: DashboardLibraryWidgetDirective) { - this.widgetAdded.emit([{ - node: { - ...node, - widgetData: widget.widgetData, - willItFit: this.willItFit(node.x, node.y, widget.width, widget.height) + this.widgetAdded.emit([ + { + node: { + ...this.addGridStackNodeCompatible(node), + widgetData: widget.widgetData, + willItFit: this.willItFit(node.x, node.y, widget.width, widget.height), + }, + // origNode: this.addGridStackNodeCompatible(origNode), }, - origNode - }]); + ]); } handleDragOutNode(node: GridStackNode, dropArea: DashboardLibraryTrashDirective) { - this.widgetRemoved.emit([{ - widget: this.renderedWidgets.find(widget => node.el === widget.elem.nativeElement), - node: { - ...node, - trashData: dropArea.trashData + this.widgetRemoved.emit([ + { + widget: this.renderedWidgets.find((widget) => node.el === widget.elem.nativeElement), + node: { + ...this.addGridStackNodeCompatible(node), + trashData: dropArea.trashData, + }, + }, + ]); + } + + private addGridStackNodeCompatible(item: GridStackNode): GridStackNodeCompatible { + return { + ...item, + ...{ + x: item.x, + y: item.y, + width: item.w, + height: item.h } - }]); + }; } public getCurrentColumn() { - if (!this.gridStack) { return null; } + if (!this.gridStack) { + return null; + } return this.gridStack.getColumn(); } public getCurrentRow() { - if (!this.gridStack) { return null; } + if (!this.gridStack) { + return null; + } return this.gridStack.getRow(); } public getCurrentColumnWidth() { - if (!this.gridStack) { return null; } + if (!this.gridStack) { + return null; + } return this.gridStack.cellWidth(); } public getCurrentCellHeight() { - if (!this.gridStack) { return null; } + if (!this.gridStack) { + return null; + } return this.gridStack.getCellHeight(); } public getCurrentMargin() { - if (!this.gridStack) { return null; } + if (!this.gridStack) { + return null; + } return this.gridStack.getMargin(); } public compact() { - if (!this.gridStack) { return; } + if (!this.gridStack) { + return; + } this.gridStack.compact(); } public willItFit(x: number, y: number, width: number, height: number, autoPosition = false): boolean { - if (!this.gridStack) { return; } - return this.gridStack.willItFit(x, y, width, height, autoPosition); + if (!this.gridStack) { + return; + } + return this.gridStack.willItFit({ x, y, w: width, h: height, autoPosition }); } } diff --git a/devui/dashboard/demo/dashboard-demo.module.ts b/devui/dashboard/demo/dashboard-demo.module.ts index 95f6ea55..1e40c1db 100644 --- a/devui/dashboard/demo/dashboard-demo.module.ts +++ b/devui/dashboard/demo/dashboard-demo.module.ts @@ -1,23 +1,22 @@ - import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; -import { TranslateModule } from '@ngx-translate/core'; import { AnchorModule, ButtonModule, DrawerModule, DropDownModule, FormModule, SearchModule, TabsModule, ToggleModule } from 'ng-devui'; -// import { OptionChartModule } from 'ng-devui-plus/experimental/option-chart'; import { DashboardModule } from 'ng-devui/dashboard'; import { DevUIApiComponent } from 'ng-devui/shared/devui-api/devui-api.component'; import { DevUIApiModule } from 'ng-devui/shared/devui-api/devui-api.module'; import { DevUICodeboxModule } from 'ng-devui/shared/devui-codebox'; +import { TranslateModule } from '@ngx-translate/core'; import { DDemoNavModule } from 'src/app/component/d-demo-nav.module'; import { BasicComponent } from './basic/basic.component'; import { DashboardDemoComponent } from './dashboard-demo.component'; import { MoreConfigComponent } from './more-config/more-config.component'; + @NgModule({ declarations: [ DashboardDemoComponent, @@ -38,7 +37,6 @@ import { MoreConfigComponent } from './more-config/more-config.component'; DDemoNavModule, DashboardModule, FormModule, - // OptionChartModule, SearchModule, DrawerModule, TabsModule, diff --git a/devui/dashboard/demo/more-config/more-config.component.scss b/devui/dashboard/demo/more-config/more-config.component.scss index f6e30a88..a1c704d9 100644 --- a/devui/dashboard/demo/more-config/more-config.component.scss +++ b/devui/dashboard/demo/more-config/more-config.component.scss @@ -31,12 +31,13 @@ text-align: center; border: 1px solid $devui-primary-line; background: $devui-primary-bg; - padding: 20px; + padding: 16px; cursor: pointer; + z-index: 1; .icon { - font-size: 2em; - margin-bottom: 16px; + font-size: 1.5em; + margin-bottom: 20px; } } @@ -47,11 +48,11 @@ text-align: center; border: 1px solid $devui-danger-line; background: $devui-danger-bg; - padding: 20px; + padding: 16px; .icon { - font-size: 2em; - margin-bottom: 16px; + font-size: 1.5em; + margin-bottom: 8px; } } diff --git a/devui/dashboard/doc/api-cn.md b/devui/dashboard/doc/api-cn.md index be5c59b5..d2208f9d 100644 --- a/devui/dashboard/doc/api-cn.md +++ b/devui/dashboard/doc/api-cn.md @@ -18,7 +18,7 @@ import { DashboardModule } from 'ng-devui/dashboard'; 组件所需依赖 ```json -"gridstack": "2.0.1", +"gridstack": "4.2.6", ``` diff --git a/devui/dashboard/doc/api-en.md b/devui/dashboard/doc/api-en.md index 2ea3cc25..89e08996 100644 --- a/devui/dashboard/doc/api-en.md +++ b/devui/dashboard/doc/api-en.md @@ -18,7 +18,7 @@ Used in the page: Dependencies Required by Components ```json -"gridstack": "2.0.1", +"gridstack": "4.2.6", ``` ## d-dashboard component diff --git a/devui/dashboard/grid-stack.config.ts b/devui/dashboard/grid-stack.config.ts index 67e83885..69319501 100644 --- a/devui/dashboard/grid-stack.config.ts +++ b/devui/dashboard/grid-stack.config.ts @@ -1,4 +1,4 @@ -import { GridStackOptions } from 'gridstack'; +import { GridStackNode, GridStackOptions } from 'gridstack'; const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( window.navigator.userAgent ); @@ -27,3 +27,11 @@ export const DashBoardGridStackDefaultOption: GridStackOptions = { disableResize: false, animate: true }; +export interface GridStackNodeCompatibleWithV2 { + x?: number; + y?: number; + width?: number; + height?: number; +} + +export interface GridStackNodeCompatible extends GridStackNode, GridStackNodeCompatibleWithV2 {} diff --git a/devui/dashboard/grid-stack.service.ts b/devui/dashboard/grid-stack.service.ts index 8e46e033..4b01e454 100644 --- a/devui/dashboard/grid-stack.service.ts +++ b/devui/dashboard/grid-stack.service.ts @@ -1,10 +1,10 @@ import { Injectable, isDevMode } from '@angular/core'; -import { $, GridItemHTMLElement, GridStack, GridStackNode, Utils } from 'gridstack'; +import { GridItemHTMLElement, GridStack, GridStackDDI, GridStackNode, Utils } from 'gridstack'; +import 'gridstack/dist/h5/gridstack-dd-native'; +import { GridStackDDNative } from 'gridstack/dist/h5/gridstack-dd-native'; import { DashboardComponent } from './dashboard.component'; import { DashboardLibraryTrashDirective } from './widget-library/library-trash.directive'; import { DashboardLibraryWidgetDirective } from './widget-library/library-widget.directive'; - -/* eslint-disable */ @Injectable() export class GridStackService { gridStack: GridStack; @@ -12,31 +12,51 @@ export class GridStackService { lastColumn: number; lastStyleSheet: CSSStyleSheet; + getDD() { + return (GridStackDDI.get() as GridStackDDNative); + } + static cleanDragIn(el: HTMLElement) { - if (Boolean($(el).data('ui-draggable'))) { - $(el).draggable('destroy'); + if (el.classList.contains('ui-draggable')) { + (GridStackDDI.get() as GridStackDDNative).draggable(el, 'destroy'); } } - - static isDraggable(el) { return Boolean($(el).data('ui-draggable')); } - static isDroppable(el) { return Boolean($(el).data('ui-droppable')); } - static enableDrag(el) { - if (!GridStackService.isDraggable(el)) {return; } - $(el).draggable('enable'); + static isDraggable(el: HTMLElement) { + return Boolean(el.classList.contains('ui-draggable')); + } + static isDroppable(el: HTMLElement) { + return Boolean(el.classList.contains('ui-droppable')); + } + static enableDrag(el: HTMLElement) { + if (!GridStackService.isDraggable(el)) { + return; + } + (GridStackDDI.get() as GridStackDDNative).draggable(el, 'enable'); } - static disableDrag(el) { - if (!GridStackService.isDraggable(el)) {return; } - $(el).draggable('disable'); + static disableDrag(el: HTMLElement) { + if (!GridStackService.isDraggable(el)) { + return; + } + (GridStackDDI.get() as GridStackDDNative).draggable(el, 'disable'); } - static enableDrop(el) { - if (!GridStackService.isDroppable(el)) {return; } - $(el).droppable('enable'); + static enableDrop(el: HTMLElement) { + if (!GridStackService.isDroppable(el)) { + return; + } + (GridStackDDI.get() as GridStackDDNative).droppable(el, 'enable'); } - static disableDrop(el) { - if (!GridStackService.isDroppable(el)) {return; } - $(el).droppable('disable'); + static disableDrop(el: HTMLElement) { + if (!GridStackService.isDroppable(el)) { + return; + } + (GridStackDDI.get() as GridStackDDNative).droppable(el, 'disable'); } - + _itemRemoving = (el: GridItemHTMLElement, remove: boolean) => { + const node = el ? el.gridstackNode : undefined; + if (!node || !node.grid) { return; } + remove ? node['_isAboutToRemove'] = true : delete node['_isAboutToRemove']; + remove ? el.classList.add('grid-stack-item-removing') : el.classList.remove('grid-stack-item-removing'); + }; resetAcceptWidget(dashboard: DashboardComponent) { if (!this.gridStack) { if (isDevMode()) { @@ -47,107 +67,42 @@ export class GridStackService { if (this.gridStack.opts.staticGrid || !this.gridStack.opts.acceptWidgets) { return; } - if (!Boolean($(this.gridStack.el).data('ui-droppable'))) { + if (!this.getDD().isDroppable(this.gridStack.el)) { const that = this.gridStack; - this.gridStack.dd.droppable(that.el, { + this.getDD().droppable(that.el, { accept: (el: GridItemHTMLElement) => { const node: GridStackNode = el.gridstackNode; - if (node && node.grid === that) { - return false; - } + // set accept drop to true on ourself (which we ignore) so we don't get "can't drop" icon in HTML5 mode while moving + if (node && node.grid === that) { return true; } + if (!that.opts.acceptWidgets) { return false; } + // check for accept method or class matching + let canAccept = true; if (typeof that.opts.acceptWidgets === 'function') { - return that.opts.acceptWidgets(el); + canAccept = that.opts.acceptWidgets(el); + } else { + const selector = (that.opts.acceptWidgets === true ? '.grid-stack-item' : that.opts.acceptWidgets as string); + canAccept = el.matches(selector); } - const selector = (that.opts.acceptWidgets === true ? '.grid-stack-item' : that.opts.acceptWidgets as string); - return el.matches(selector); - } + // finally check to make sure we actually have space left #1571 + if (canAccept && node && that.opts.maxRow) { + const n = { w: node.w, h: node.h, minW: node.minW, minH: node.minH }; // only width/height matters and autoPosition + canAccept = that.engine.willItFit(n); + } + return canAccept; + }, }); } - const onDrag = (event, el, helper?: HTMLElement) => { - const that = this.gridStack; - const node = el.gridstackNode; - // 修改为与被拖拽元素对齐而不是鼠标, 与板块内拖拽体验一致 - const {left, top} = (helper || el).getBoundingClientRect(); - const cellWidth = that.cellWidth(); - const cellHeight = that.getCellHeight(); - const pos = that.getCellFromPixel({ - left: left + cellWidth / 2, - top: top + cellHeight / 2 + document.documentElement.scrollTop - }, true); // 重写了ondrag的这行 - const x = Math.max(0, pos.x); - const y = Math.max(0, pos.y); - if (!node['_added']) { - node['_added'] = true; - - node.el = el; - node.x = x; - node.y = y; - delete node.autoPosition; - that.engine.cleanNodes(); - that.engine.beginUpdate(node); - that.engine.addNode(node); - - that['_writeAttrs'](that['placeholder'], node.x, node.y, node.width, node.height); - that.el.appendChild(that['placeholder']); - node.el = that['placeholder']; // dom we update while dragging... - node._beforeDragX = node.x; - node._beforeDragY = node.y; - - that['_updateContainerHeight'](); - } else if ((x !== node.x || y !== node.y) && that.engine.canMoveNode(node, x, y)) { - that.engine.moveNode(node, x, y); - that['_updateContainerHeight'](); - } - }; - - this.gridStack.dd - .off(this.gridStack.el, 'dropover') - .on(this.gridStack.el, 'dropover', (event, el) => { - // 覆盖这个方法为了重写onDrag里的一行 - const that = this.gridStack; - let width, height; - - // see if we already have a node with widget/height and check for attributes - let node = el.gridstackNode; - if (!node || !node.width || !node.height) { - const w = parseInt(el.getAttribute('data-gs-width'), 10); - if (w > 0) { node = node || {}; node.width = w; } - const h = parseInt(el.getAttribute('data-gs-height'), 10); - if (h > 0) { node = node || {}; node.height = h; } - } - - // if not calculate the grid size based on element outer size - const cellWidth = that.cellWidth(); - const cellHeight = that.getCellHeight(); - width = node && node.width ? node.width : Math.round(el.offsetWidth / cellWidth) || 1; - height = node && node.height ? node.height : Math.round(el.offsetHeight / cellHeight) || 1; - - const newNode = (that.engine as any)['prepareNode']({width, height, _added: false, _temporary: true}); - newNode['_isOutOfGrid'] = true; - el.gridstackNode = newNode; - el['_gridstackNodeOrig'] = node; - - that.dd.on(el, 'drag', onDrag); - return false; - }) + this.getDD() .off(this.gridStack.el, 'dropout') - .on(this.gridStack.el, 'dropout', (event, el: GridItemHTMLElement) => { + .on(this.gridStack.el, 'dropout', (event, el: GridItemHTMLElement, helper) => { // 覆盖这个方法是因为 float模式下 dropout影响了原来的布局 const that = this.gridStack; const node = el.gridstackNode; - if (!node || !node['_isOutOfGrid']) { - return; + if (!node.grid || node.grid === that) { + that['_leave'](el, helper); } this.fixFloat(that, node); // 增加了float模式下的恢复 - that.dd.off(el, 'drag'); - node.el = null; - that.engine.removeNode(node); - if (that['placeholder'].parentNode === that.el) { - that.el.removeChild(that['placeholder']); - } - that['_updateContainerHeight'](); - - el.gridstackNode = el['_gridstackNodeOrig']; + this.getDD().off(el, 'drag'); return false; }) .off(this.gridStack.el, 'drop') @@ -155,15 +110,22 @@ export class GridStackService { // 覆盖这个方法是因为 drop的情况不想让它放进去而是只发射通知 const that = this.gridStack; + const node: GridStackNode = el.gridstackNode; + if (node && node.grid === that && !node['_isExternal']) { return false; } + + const wasAdded = !!that['placeholder'].parentElement; that['placeholder'].remove(); const origNode = el['_gridstackNodeOrig']; delete el['_gridstackNodeOrig']; - const node: GridStackNode = el.gridstackNode; - that.engine.cleanupNode(node); // 好像没用 + if (!node) { return false; } + if (wasAdded) { + that.engine.cleanupNode(node); // 好像没用 + node.grid = that; + } + - node.grid = that; if (helper !== el) { helper.remove(); el.gridstackNode = origNode; // original item (left behind) is re-stored to pre dragging as the node now has drop info @@ -171,7 +133,7 @@ export class GridStackService { Utils.removePositioningStyles(el); } - that.dd.off(el, 'drag'); + this.getDD().off(el, 'drag'); that.engine.removeNode(node); this.fixFloat(that, node); @@ -191,24 +153,29 @@ export class GridStackService { return; } const trashZone = document.querySelector(this.gridStack.opts.removable) as HTMLElement; - if (!trashZone) { return; } - if (this.gridStack.dd.isDroppable(trashZone)) { + if (!trashZone) { + return; + } + if (this.getDD().isDroppable(trashZone)) { // 清理掉了dropover和dropout 直接重新绑定对应的逻辑 - this.gridStack.dd.off(trashZone, 'dropover').off(trashZone, 'dropout'); + this.getDD().off(trashZone, 'dropover').off(trashZone, 'dropout'); } } private fixFloat(gridstack: GridStack, node: GridStackNode) { if (gridstack.getFloat()) { gridstack.engine.batchUpdate(); - gridstack.engine.nodes.filter(n => n !== node).reverse().forEach(n => { - if (n['_origX'] !== undefined || n['_origY'] !== undefined) { - n.x = n['_origX'] !== undefined ? n['_origX'] : n.x; - n.y = n['_origY'] !== undefined ? n['_orig&'] : n.y; - gridstack.engine.moveNode(n, n.x, n.y); - gridstack['_writeAttrs'](n.el, n.x, n.y); - } - }); + gridstack.engine.nodes + .filter((n) => n !== node) + .reverse() + .forEach((n) => { + if (n['_origX'] !== undefined || n['_origY'] !== undefined) { + n.x = n['_origX'] !== undefined ? n['_origX'] : n.x; + n.y = n['_origY'] !== undefined ? n['_orig&'] : n.y; + gridstack.engine.moveNode(n, { x: n.x, y: n.y }); + gridstack['_writeAttrs'](n.el, n.x, n.y); + } + }); gridstack.engine.commit(); } } @@ -216,26 +183,30 @@ export class GridStackService { setupDragIn( el: HTMLElement, widget: DashboardLibraryWidgetDirective, - helper?: ((event: any) => HTMLElement)|string, - notify?: (eventType: string) => (...args) => void + helper?: ((event: any) => HTMLElement) | string, + notify?: (eventType: string) => (...args: any) => void ) { - this.gridStack.dd.dragIn(el, Object.assign({}, - this.gridStack.opts.dragInOptions, - { helper: helper || this.gridStack.opts.dragInOptions.helper }, - { + this.getDD().dragIn(el, { + ...widget.targetDashboard.finalOption.dragInOptions, + ...{ helper: helper || widget.targetDashboard.finalOption.dragInOptions.helper ,handle:this.gridStack.opts.handle}, + ...{ start: () => { this.dragInWidget = widget; - if (notify) { notify('dragStart')(); } + if (notify) { + notify('dragStart')(); + } }, stop: () => { this.dragInWidget = undefined; - if (notify) { notify('dragStop')(); } - } - } - )); + if (notify) { + notify('dragStop')(); + } + }, + }, + }); } destroyDragIn(el: HTMLElement) { - this.gridStack.dd.draggable(el, 'destroy'); + this.getDD().draggable(el, 'destroy'); } /* 设置自定义的回收站 */ @@ -246,22 +217,10 @@ export class GridStackService { } return; } - const that = this.gridStack; - if (!that.dd.isDroppable(trashZone)) { - that.dd.droppable(trashZone, that.opts.removableOptions); - } - that.dd - .on(trashZone, 'dropover', (event, el) => { - el.classList.add('grid-stack-item-removing'); - }) - .on(trashZone, 'dropout', (event, el) => { - el.classList.remove('grid-stack-item-removing'); - }) - .on(trashZone, 'drop', (event, el) => { - el.classList.remove('grid-stack-item-removing'); - const node = el.gridstackNode; - dashboard.handleDragOutNode(node, trash); - }); + const trashEl = trashZone; + this.getDD().droppable(trashEl, this.gridStack.opts.removableOptions) + .on(trashEl, 'dropover', (event, el) => this._itemRemoving(el, true)) + .on(trashEl, 'dropout', (event, el) => this._itemRemoving(el, false)); } /* 清理自定义的回收站 */ @@ -271,17 +230,20 @@ export class GridStackService { return; } const that = this.gridStack; - if (!that.dd.isDroppable(trashZone)) { + if (!this.getDD().isDroppable(trashZone)) { return; } - that.dd.off(trashZone, 'dropover').off(trashZone, 'dropout').off(trashZone, 'drop'); + this.getDD().off(trashZone, 'dropover').off(trashZone, 'dropout').off(trashZone, 'drop'); } // 设置背景 updateBackgroundGridBlock() { if (this.gridStack) { if (!this.lastStyleSheet) { - this.lastStyleSheet = Utils.createStylesheet('d-dashboard-' + this.gridStack.opts['_class']); + this.lastStyleSheet = Utils.createStylesheet( + 'd-dashboard-' + this.gridStack.opts['_styleSheetClass'], + this.gridStack.el.parentElement + ); } else { this.lastStyleSheet.removeRule(0); } @@ -290,9 +252,15 @@ export class GridStackService { const marginUnit = this.gridStack.opts.marginUnit; const cellHeight = this.gridStack.opts.cellHeight as number; const cellHeightUnit = this.gridStack.opts.cellHeightUnit; - const prefix = `.${this.gridStack.opts['_class']}`; + const prefix = `.${this.gridStack.opts['_styleSheetClass']}`; + if (!this.lastStyleSheet) { + return; + } - Utils.addCSSRule(this.lastStyleSheet, `${prefix}.d-dashboard-show-grid-block::before`, ` + Utils.addCSSRule( + this.lastStyleSheet, + `${prefix}.d-dashboard-show-grid-block::before`, + ` background-image: linear-gradient(#fff 0, #fff ${margin * 2}${marginUnit}, transparent ${margin * 2}${marginUnit}, transparent 100%), @@ -307,7 +275,8 @@ export class GridStackService { linear-gradient(var(--devui-area, #f8f8f8) 0 , var(--devui-area, #f8f8f8) 100%); background-size: ${100 / column}% ${cellHeight}${cellHeightUnit}; background-position: -${margin}${marginUnit} -${margin}${marginUnit}; - `); + ` + ); this.lastColumn = column; } } @@ -323,5 +292,4 @@ export class GridStackService { Utils.removeStylesheet('d-dashboard-' + this.gridStack.opts['_class']); } } - } diff --git a/devui/dashboard/package.json b/devui/dashboard/package.json index 1096144c..6756d6f5 100644 --- a/devui/dashboard/package.json +++ b/devui/dashboard/package.json @@ -5,7 +5,7 @@ } }, "peerDependencies": { - "gridstack": "2.0.1" + "gridstack": "4.2.6" }, "sideEffects": true } diff --git a/devui/dashboard/polyfill.ts b/devui/dashboard/polyfill.ts index 22f8c01b..191234f8 100644 --- a/devui/dashboard/polyfill.ts +++ b/devui/dashboard/polyfill.ts @@ -2,7 +2,7 @@ // Source: https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/append()/append().md export default (function (arr) { arr.forEach(function (item) { - if (item.hasOwnProperty('append')) { + if (Object.prototype.hasOwnProperty.call(item,'append')) { return; } Object.defineProperty(item, 'append', { diff --git a/devui/dashboard/widget-library/library-widget.directive.ts b/devui/dashboard/widget-library/library-widget.directive.ts index 90ed7d89..f0542836 100644 --- a/devui/dashboard/widget-library/library-widget.directive.ts +++ b/devui/dashboard/widget-library/library-widget.directive.ts @@ -1,19 +1,7 @@ import { DomPortalOutlet, TemplatePortal } from '@angular/cdk/portal'; import { - AfterViewInit, - ApplicationRef, - ComponentFactoryResolver, - Directive, - ElementRef, - HostBinding, - Injector, - Input, - OnChanges, - OnDestroy, - Optional, - SimpleChanges, - TemplateRef, - ViewContainerRef, + AfterViewInit, ApplicationRef, ComponentFactoryResolver, Directive, ElementRef, HostBinding, Injector, + Input, OnChanges, OnDestroy, Optional, SimpleChanges, TemplateRef, ViewContainerRef } from '@angular/core'; import { DashboardComponent } from '../dashboard.component'; import { GridStackService } from '../grid-stack.service'; @@ -23,11 +11,11 @@ import { DashboardLibraryPanelDirective } from '../widget-library/library-panel. selector: '[dDashboardLibraryWidget]', }) export class DashboardLibraryWidgetDirective implements OnChanges, AfterViewInit, OnDestroy { - @HostBinding('attr.data-gs-width') + @HostBinding('attr.gs-w') @Input() width: number; - @HostBinding('attr.data-gs-height') + @HostBinding('attr.gs-h') @Input() height: number; @@ -40,7 +28,7 @@ export class DashboardLibraryWidgetDirective implements OnChanges, AfterViewInit @HostBinding('class.grid-stack-new-item') hostBinding = true; - @HostBinding('attr.data-gs-instance') + @HostBinding('attr.gs-instance') gridStackId; @Input() targetDashboard: DashboardComponent; @@ -55,7 +43,7 @@ export class DashboardLibraryWidgetDirective implements OnChanges, AfterViewInit private injector: Injector, private vcf: ViewContainerRef, @Optional() private libraryPanel: DashboardLibraryPanelDirective - ) {} + ) { } ngOnChanges(changes: SimpleChanges) { if (changes.targetDashboard) { @@ -109,7 +97,7 @@ export class DashboardLibraryWidgetDirective implements OnChanges, AfterViewInit }; } } else { - return () => {}; + return () => { }; } }; @@ -131,10 +119,10 @@ export class DashboardLibraryWidgetDirective implements OnChanges, AfterViewInit el.classList.add('grid-stack-item-adding-item-template'); el.style.zIndex = '1060'; if (this.width !== undefined) { - el.setAttribute('data-gs-width', String(this.width)); + el.setAttribute('gs-w', `${this.width}`); } if (this.height !== undefined) { - el.setAttribute('data-gs-height', String(this.height)); + el.setAttribute('gs-h', `${this.height}`); } this.setDragWidthHeight(el); const domPortalOutlet = new DomPortalOutlet(el, this.cfr, this.appRef, this.injector); diff --git a/devui/dashboard/widget/widget.component.scss b/devui/dashboard/widget/widget.component.scss index 23297a56..1f9d6673 100644 --- a/devui/dashboard/widget/widget.component.scss +++ b/devui/dashboard/widget/widget.component.scss @@ -1,18 +1,23 @@ -@import '../../style/theme/animation'; +@import '../../style/core/animation'; @import '../../style/theme/color'; @import '../../style/theme/corner'; :host { display: block; background-color: transparent; - // 解决hover在handle的时候不高亮卡片,搭配:host:hover颜色使用 + position: absolute !important; + // hover卡片之间间距的时候不应该高亮 pointer-events: none; - + // 内部元素 & ::ng-deep > * { pointer-events: auto; } } +.ui-draggable-dragging :host > * { + pointer-events: none !important; +} + .d-dashboard-widget { border: 1px solid transparent; box-shadow: 0 2px 8px 0 $devui-light-shadow; diff --git a/devui/dashboard/widget/widget.component.ts b/devui/dashboard/widget/widget.component.ts index acf89a46..56e56dd0 100644 --- a/devui/dashboard/widget/widget.component.ts +++ b/devui/dashboard/widget/widget.component.ts @@ -1,8 +1,19 @@ import { - AfterViewInit, ChangeDetectionStrategy, Component, - ElementRef, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, Optional, Output, SimpleChanges + Component, + ElementRef, + Input, + ChangeDetectionStrategy, + HostBinding, + EventEmitter, + Output, + OnChanges, + SimpleChanges, + Optional, + AfterViewInit, + OnDestroy, } from '@angular/core'; import { GridStackNode, GridStackWidget } from 'gridstack'; +import { GridStackNodeCompatible } from '../grid-stack.config'; import { GridStackService } from '../grid-stack.service'; export type DashboardWidget = GridStackWidget & { @@ -20,53 +31,66 @@ export type DashboardWidget = GridStackWidget & { }) export class DashboardWidgetComponent implements GridStackNode, OnChanges, AfterViewInit, OnDestroy { static autoNumberedId = 0; - @HostBinding('attr.data-gs-x') - @Input() x: number; + @HostBinding('attr.gs-x') + @Input() + x: number; @Output() xChange = new EventEmitter(); - @HostBinding('attr.data-gs-y') - @Input() y: number; + @HostBinding('attr.gs-y') + @Input() + y: number; @Output() yChange = new EventEmitter(); - @HostBinding('attr.data-gs-width') - @Input() width: number; + @HostBinding('attr.gs-w') + @Input() + width: number; @Output() widthChange = new EventEmitter(); - @HostBinding('attr.data-gs-height') - @Input() height: number; + @HostBinding('attr.gs-h') + @Input() + height: number; @Output() heightChange = new EventEmitter(); - @HostBinding('attr.data-gs-id') - @Input() id: string; + @HostBinding('attr.gs-id') + @Input() + id: string; - @HostBinding('attr.data-gs-max-width') - @Input() maxWidth: number; + @HostBinding('attr.gs-max-w') + @Input() + maxWidth: number; - @HostBinding('attr.data-gs-max-height') - @Input() maxHeight: number; + @HostBinding('attr.gs-max-h') + @Input() + maxHeight: number; - @HostBinding('attr.data-gs-min-width') - @Input() minWidth: number; + @HostBinding('attr.gs-min-w') + @Input() + minWidth: number; - @HostBinding('attr.data-gs-min-height') - @Input() minHeight: number; + @HostBinding('attr.gs-min-h') + @Input() + minHeight: number; - @HostBinding('attr.data-gs-no-resize') - @Input() noResize: boolean; + @HostBinding('attr.gs-no-resize') + @Input() + noResize: boolean; - @HostBinding('attr.data-gs-no-move') - @Input() noMove: boolean; + @HostBinding('attr.gs-no-move') + @Input() + noMove: boolean; - @HostBinding('attr.data-gs-auto-position') - @Input() autoPosition: boolean; // 仅初始化有效,默认为false + @HostBinding('attr.gs-auto-position') + @Input() + autoPosition: boolean; // 仅初始化有效,默认为false - @HostBinding('attr.data-gs-locked') - @Input() locked: boolean; + @HostBinding('attr.gs-locked') + @Input() + locked: boolean; @Input() widgetData; @Output() widgetInit = new EventEmitter(true); - @Output() widgetResize = new EventEmitter<{width: number; height: number} | null>(true); + @Output() widgetResize = new EventEmitter<{ width: number; height: number } | null>(true); @Output() widgetDestroy = new EventEmitter(); @HostBinding('class.grid-stack-item') @@ -79,7 +103,7 @@ export class DashboardWidgetComponent implements GridStackNode, OnChanges, After ngOnChanges(changes: SimpleChanges) { if (this.gridStackService && this.gridStackService.gridStack) { if (changes.x || changes.y || changes.width || changes.height) { - this.gridStackService.gridStack.update(this.elem.nativeElement, this.x, this.y, this.width, this.height); + this.gridStackService.gridStack.update(this.elem.nativeElement, { x: this.x, y: this.y, w: this.width, h: this.height }); } if (changes.noResize) { this.gridStackService.gridStack.resizable(this.elem.nativeElement, !this.noResize); @@ -88,19 +112,19 @@ export class DashboardWidgetComponent implements GridStackNode, OnChanges, After this.gridStackService.gridStack.movable(this.elem.nativeElement, !this.noMove); } if (changes.locked) { - this.gridStackService.gridStack.locked(this.elem.nativeElement, !!this.locked); + this.gridStackService.gridStack.update(this.elem.nativeElement, { locked: !!this.locked }); } if (changes.maxWidth) { - this.gridStackService.gridStack.maxWidth(this.elem.nativeElement, this.maxWidth); + this.gridStackService.gridStack.update(this.elem.nativeElement, { maxW: this.maxWidth }); } if (changes.maxHeight) { - this.gridStackService.gridStack.maxHeight(this.elem.nativeElement, this.maxHeight); + this.gridStackService.gridStack.update(this.elem.nativeElement, { maxH: this.maxHeight }); } if (changes.minWidth) { - this.gridStackService.gridStack.minWidth(this.elem.nativeElement, this.minWidth); + this.gridStackService.gridStack.update(this.elem.nativeElement, { minW: this.minWidth }); } if (changes.minHeight) { - this.gridStackService.gridStack.minHeight(this.elem.nativeElement, this.minHeight); + this.gridStackService.gridStack.update(this.elem.nativeElement, { minH: this.minHeight }); } } } @@ -112,10 +136,10 @@ export class DashboardWidgetComponent implements GridStackNode, OnChanges, After this.widgetDestroy.emit(); } - handleChange({ x, y, width, height }: GridStackNode) { - const change = { x, y, width, height }; - const beforeChange = {width: this.width, height: this.height}; - Object.keys(change).forEach(key => { + handleChange({ x, y, width, height }: GridStackNodeCompatible) { + const change = { x, y, width, height}; + const beforeChange = { width: this.width, height: this.height }; + Object.keys(change).forEach((key) => { if (change[key] !== this[key]) { this[key] = change[key]; const eventEmitter = this[key + 'Change'] as EventEmitter; @@ -125,7 +149,7 @@ export class DashboardWidgetComponent implements GridStackNode, OnChanges, After } }); if (change.width !== beforeChange.width || change.height !== beforeChange.height) { - this.widgetResize.emit({width: width, height: height}); + this.widgetResize.emit({ width, height}); } } } diff --git a/devui/data-table/data-table-head.component.ts b/devui/data-table/data-table-head.component.ts index 1206fb84..eab8925f 100755 --- a/devui/data-table/data-table-head.component.ts +++ b/devui/data-table/data-table-head.component.ts @@ -99,7 +99,7 @@ export class DataTableHeadComponent implements OnInit, OnChanges, AfterViewInit, fixTableScrollViewEl; animationRequestId; colOffset = 0; - seconedHeaderOffset = 0; + secondHeaderOffset = 0; cellMapOffset = 0; cellMap = {}; iterableDiffer; @@ -609,7 +609,7 @@ export class DataTableHeadComponent implements OnInit, OnChanges, AfterViewInit, } buildFakeTable(table) { this.colOffset = 0; - this.seconedHeaderOffset = 0; + this.secondHeaderOffset = 0; return Array.from(table.rows[0].children).map((cell, index) => { return this.getColumnAsTableByIndex(table, index, (cell).colSpan, (cell).rowSpan); }); @@ -659,9 +659,9 @@ export class DataTableHeadComponent implements OnInit, OnChanges, AfterViewInit, ); } - css(el, csses) { - Object.keys(csses).forEach((k) => { - el.style[k] = csses[k]; + css(el, cssList) { + Object.keys(cssList).forEach((k) => { + el.style[k] = cssList[k]; }); return el; } @@ -923,8 +923,8 @@ export class DataTableHeadComponent implements OnInit, OnChanges, AfterViewInit, } }; const insertBodyColList = this.getDataBetween(selectedColIndex - 1 + this.colOffset, selectedColIndex + this.colOffset + colSpan); - const insertHeaderColList = this.getDataBetween(selectedColIndex + this.seconedHeaderOffset - 1, selectedColIndex + - this.seconedHeaderOffset + colSpan - rowSpan + 1); + const insertHeaderColList = this.getDataBetween(selectedColIndex + this.secondHeaderOffset - 1, selectedColIndex + + this.secondHeaderOffset + colSpan - rowSpan + 1); const getTreeTableCol = (row, rowIndex) => { const target = this.getChildTableColumn((row).children[0].children[0], selectedColIndex); empty((row).children[0]); @@ -992,7 +992,7 @@ export class DataTableHeadComponent implements OnInit, OnChanges, AfterViewInit, this.css(row, { height: `${table.rows[rowIndex].getBoundingClientRect().height}px` }); }); this.colOffset += (colSpan - 1); - this.seconedHeaderOffset = rowSpan > 1 ? this.seconedHeaderOffset - 1 : this.seconedHeaderOffset; + this.secondHeaderOffset = rowSpan > 1 ? this.secondHeaderOffset - 1 : this.secondHeaderOffset; return cTable; } diff --git a/devui/data-table/data-table-row.component.ts b/devui/data-table/data-table-row.component.ts index 808d7b31..215edfd0 100755 --- a/devui/data-table/data-table-row.component.ts +++ b/devui/data-table/data-table-row.component.ts @@ -1,4 +1,16 @@ -import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, Inject, Input, NgZone, OnInit, Output } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + ElementRef, + EventEmitter, + forwardRef, + HostBinding, + Inject, + Input, + NgZone, + OnInit, + Output +} from '@angular/core'; import { DATA_TABLE_ROW } from './data-table-row.token'; import { DATA_TABLE } from './data-table.token'; import { ForceUpdateReason } from './force-update-reason.model'; @@ -9,9 +21,10 @@ import { DataTableColumnTmplComponent } from './tmpl/data-table-column-tmpl.comp templateUrl: './data-table-row.component.html', styleUrls: ['./data-table-row.component.scss'], preserveWhitespaces: false, - providers: [ - {provide: DATA_TABLE_ROW, useExisting: DataTableRowComponent} - ], + providers: [{ + provide: DATA_TABLE_ROW, + useExisting: forwardRef(() => DataTableRowComponent) + }], }) export class DataTableRowComponent implements OnInit { @Input() rowItem: any; @@ -70,7 +83,6 @@ export class DataTableRowComponent implements OnInit { } onRowClick($event) { - // $event.stopPropagation(); this.clickCount++; if (this.clickCount === 1) { this.timeoutId = setTimeout(() => { @@ -84,7 +96,6 @@ export class DataTableRowComponent implements OnInit { } onRowDBClick($event) { - // $event.stopPropagation(); this.dt.onRowDBClick({ rowIndex: this.rowIndex, nestedIndex: this.nestedIndex, rowItem: this.rowItem, rowComponent: this }); } diff --git a/devui/data-table/data-table.component.html b/devui/data-table/data-table.component.html index e2ba1842..6e463c69 100755 --- a/devui/data-table/data-table.component.html +++ b/devui/data-table/data-table.component.html @@ -5,7 +5,7 @@ #fixHeaderContainerRef class="table-wrap" [style.overflow-x]="'hidden'" - [style.overflow-y]="'scroll'" + [style.scrollbar-width]="'none'" [style.max-height]="maxHeight ? maxHeight : null" [style.max-width]="maxWidth ? maxWidth : null" [style.width]="!maxWidth ? tableWidth : null" @@ -39,7 +39,6 @@ [style.max-width]="maxWidth ? maxWidth : null" [style.width]="!maxWidth ? tableWidth : null" (scroll)="onBodyScroll($event)" - [style.overflow-y]="fixHeader ? 'scroll' : null" >
    tr > td { padding: 11px 20px 12px; } + + thead > tr > th.devui-checkable-cell { + padding: 10px 20px; + } } &.devui-table-lg ::ng-deep { tbody > tr > td { padding: 15px 20px 16px; } + + thead > tr > th.devui-checkable-cell { + padding: 10px 20px; + } } } diff --git a/devui/data-table/data-table.component.ts b/devui/data-table/data-table.component.ts index 4a5d9518..28ac5079 100755 --- a/devui/data-table/data-table.component.ts +++ b/devui/data-table/data-table.component.ts @@ -1,11 +1,27 @@ import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { DOCUMENT } from '@angular/common'; import { - AfterContentInit, AfterViewInit, ChangeDetectorRef, Component, - ContentChild, ContentChildren, ElementRef, EventEmitter, - HostBinding, Inject, Input, NgZone, - OnChanges, OnDestroy, OnInit, Output, - QueryList, Renderer2, SimpleChanges, TemplateRef, + AfterContentInit, + AfterViewInit, + ChangeDetectorRef, + Component, + ContentChild, + ContentChildren, + ElementRef, + EventEmitter, + forwardRef, + HostBinding, + Inject, + Input, + NgZone, + OnChanges, + OnDestroy, + OnInit, + Output, + QueryList, + Renderer2, + SimpleChanges, + TemplateRef, ViewChild } from '@angular/core'; import { merge, Subscription } from 'rxjs'; @@ -31,9 +47,10 @@ import { DataTableColumnTmplComponent } from './tmpl/data-table-column-tmpl.comp // changeDetection: ChangeDetectionStrategy.OnPush, exportAs: 'dataTable', preserveWhitespaces: false, - providers: [ - {provide: DATA_TABLE, useExisting: DataTableComponent} - ], + providers: [{ + provide: DATA_TABLE, + useExisting: forwardRef(() => DataTableComponent) + }], }) export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterContentInit, AfterViewInit { /** @@ -65,7 +82,7 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo */ @Input() scrollable: boolean; /** - * 【可选】默认表格使用的表格类型,可选值为'cell' + * 【可选】默认表格使用的表格类型,可选值为'cell' @deprecated */ @Input() editModel = 'cell'; /** @@ -125,7 +142,7 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo */ @Input() colDropFreezeTo = 0; /** - * 【可选】用来自定义详情页的模板 + * 【可选】用来自定义详情页的模板 @deprecated */ @Input() detailTemplateRef: TemplateRef; /** @@ -145,7 +162,7 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo */ @Input() showFilterIcon = false; /** - * 多列选择Change事件,用来更新多列选择数组 + * 多列选择Change事件,用来更新多列选择数组, column param * */ @Output() multiSortChange = new EventEmitter(); /** @@ -198,13 +215,14 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo @Output() resize = new EventEmitter(); /** * 当前表格层级,默认为0,在树形表格场景下自增长 + * 内部嵌套使用,不对外暴露 */ @Input() tableLevel = 0; /** - * 配置树形表格的父子选中是否互相关联 - * upward:选中子关联父 - * downward: 选中父关联子 - */ + * 配置树形表格的父子选中是否互相关联 + * upward:选中子关联父 + * downward: 选中父关联子 + */ @Input() checkableRelation: CheckableRelation = { upward: true, downward: true }; /** * 异步加载子列表 @@ -285,6 +303,7 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo @ViewChild('cdkVirtualScrollViewport') virtualScrollViewport: CdkVirtualScrollViewport; @ViewChild('normalScroll') normalScrollElement: ElementRef; @ViewChild('scrollViewTpl') vitualScrollElement: TemplateRef; + @ViewChild('devuiNormalScrollBody', {read: ElementRef}) devuiNormalScrollBody: ElementRef; @HostBinding('style.height') get hostHeight() { return this.tableHeight; @@ -315,6 +334,9 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo tableBodyEl: ElementRef; onDocumentClickListen: any; + _tableTotalWidth = 0; + _lastColSize = 0; + @ViewChild('tableBody') set content(content: ElementRef) { setTimeout(() => { this.tableBodyEl = content; @@ -385,7 +407,9 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo initVirtualBodyHeight() { setTimeout(() => { - this.virtualScrollViewport.checkViewportSize(); + if (this.virtualScrollViewport) { + this.virtualScrollViewport.checkViewportSize(); + } }); if (this.tableHeight && this.tableHeight !== 'auto') { this.virtualBodyHeight = this.tableHeight; @@ -459,9 +483,9 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo if ( this.virtualScroll && - (changes['tableHeight'] && !changes.tableHeight.firstChange) || + ((changes['tableHeight'] && !changes.tableHeight.firstChange) || (changes['maxHeight'] && !changes.maxHeight.firstChange) || - (changes['virtualScroll'] && !changes.virtualScroll.firstChange) + (changes['virtualScroll'] && !changes.virtualScroll.firstChange)) ) { this.initVirtualBodyHeight(); } @@ -771,6 +795,7 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo beginResizeHandlerEvent($event) { const thRenderWidthList = $event.thRenderWidthList; if (thRenderWidthList.length > 0) { + this._tableTotalWidth = this.elementRef.nativeElement.querySelector('.table-wrap').offsetWidth; // 兼容d-column表头分组场景 const reverseThList = thRenderWidthList.reverse(); this._columns.forEach(column => { @@ -779,6 +804,10 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo column.width = thItem.width + 'px'; } }); + + if (!this._lastColSize) { + this._lastColSize = parseInt(this._columns.slice(-1)[0].width, 10); + } this.updateColumnsWidth(); } this.onDocumentClick($event.event); @@ -798,21 +827,41 @@ export class DataTableComponent implements OnDestroy, OnInit, OnChanges, AfterCo } onResizeHandler({ width, field }) { + if (width < 0) { + return; + } const index = this.tableWidthConfig.findIndex((config) => { return config.field === field; }); if (index > -1) { this.tableWidthConfig[index].width = width + 'px'; } + const curTotal = this.tableWidthConfig.reduce((pre, cur) => { + const value = pre + parseInt(cur.width, 10); + return value; + }, 0); + let columnResizeEventArg; this._columns = this._columns.map((column, colIndex) => { if (column.field === field) { column.width = parseInt(width, 10) + 'px'; - const columnResizeEventArg = { currentColumn: column, nextColumn: this._columns[colIndex + 1] }; + columnResizeEventArg = { currentColumn: column, nextColumn: this._columns[colIndex + 1] }; this.resize.emit(columnResizeEventArg); - return column; } return column; }); + + const changeSize = curTotal - this._tableTotalWidth; + const lastCol = this._columns.slice(-1)[0]; + const lastColWidth = parseInt(lastCol.width, 10); + if (changeSize < 0 && columnResizeEventArg.nextColumn) { + const newSize = parseInt(lastCol.width) - changeSize + 'px'; + lastCol.width = newSize; + this.tableWidthConfig[this.tableWidthConfig.length - 1].width = newSize; + } else if (this._lastColSize < lastColWidth) { + const lastChange = (lastColWidth - this._lastColSize) > changeSize ? changeSize : (lastColWidth - this._lastColSize); + lastCol.width = lastColWidth - lastChange + 'px'; + this.tableWidthConfig[this.tableWidthConfig.length - 1].width = lastColWidth - lastChange + 'px'; + } } handleDragTable({ from, to }) { diff --git a/devui/data-table/data-table.module.ts b/devui/data-table/data-table.module.ts index 0fbbb6fc..f2db100f 100755 --- a/devui/data-table/data-table.module.ts +++ b/devui/data-table/data-table.module.ts @@ -35,7 +35,6 @@ import { DataTableCellTmplComponent } from './tmpl/data-table-cell-tmpl.componen import { DataTableCellViewTmplComponent } from './tmpl/data-table-cell-view-tmpl.component'; import { DataTableColumnTmplComponent } from './tmpl/data-table-column-tmpl.component'; import { DataTableHeadCellTmplComponent } from './tmpl/data-table-head-cell-tmpl.component'; -import { VirtualScrollTreeTableComponent } from './virtualScrollTreeTable.component'; @NgModule({ @@ -75,8 +74,7 @@ import { VirtualScrollTreeTableComponent } from './virtualScrollTreeTable.compon TableTheadComponent, TableTrComponent, TableTbodyComponent, - TableTdComponent, - VirtualScrollTreeTableComponent + TableTdComponent ], declarations: [ DataTableComponent, @@ -97,8 +95,7 @@ import { VirtualScrollTreeTableComponent } from './virtualScrollTreeTable.compon TableTheadComponent, TableTrComponent, TableTbodyComponent, - TableTdComponent, - VirtualScrollTreeTableComponent + TableTdComponent ], providers: [ TableTdService ], diff --git a/devui/data-table/data-table.spec.ts b/devui/data-table/data-table.spec.ts index c64c3478..85b83a7e 100644 --- a/devui/data-table/data-table.spec.ts +++ b/devui/data-table/data-table.spec.ts @@ -1,4 +1,4 @@ -import { +import { ChangeDetectorRef, Component, DebugElement, @@ -631,6 +631,7 @@ class TestDataFixedColumnComponent { } ]; } + describe('data-table', () => { describe('basic', () => { let fixture: ComponentFixture; diff --git a/devui/data-table/dataTableProperties.interface.ts b/devui/data-table/dataTableProperties.interface.ts deleted file mode 100644 index 9bd845cd..00000000 --- a/devui/data-table/dataTableProperties.interface.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TableWidthConfig } from './data-table.model'; - -export interface DataTableProperiesInterface { - maxWidth?: string; - maxHeight?: string; - size?: string; - rowHoveredHighlight?: boolean; - generalRowHoveredData?: boolean; - cssClass?: string; - tableWidth?: string; - fixHeader?: boolean; - colDraggable?: boolean; - colDropFreezeTo?: number; - tableWidthConfig?: TableWidthConfig[]; - showSortIcon?: boolean; - showFilterIcon?: boolean; - showOperationArea?: boolean; - hideColumn?: string[]; - pageAllChecked?: boolean; - onlyOneColumnSort?: boolean; - multiSort?: any; - resizeable?: boolean; - timeout?: number; - beforeCellEdit?: any; - headerBg?: boolean; - tableLayout?: string; - borderType?: string; - striped?: boolean; -} diff --git a/devui/data-table/demo/check-options/check-options.component.ts b/devui/data-table/demo/check-options/check-options.component.ts index 14bb5862..00d504af 100644 --- a/devui/data-table/demo/check-options/check-options.component.ts +++ b/devui/data-table/demo/check-options/check-options.component.ts @@ -15,7 +15,6 @@ import { originSource, SourceType } from '../mock-data'; }) export class CheckOptionsComponent implements OnInit { @ViewChild(DataTableComponent, { static: true }) datatable: DataTableComponent; - // totalData = JSON.parse(JSON.stringify(originSource)); basicDataSource: Array = JSON.parse(JSON.stringify(originSource.slice(0, 6))); dataTableOptions = { columns: [ diff --git a/devui/data-table/demo/data-table-demo.component.html b/devui/data-table/demo/data-table-demo.component.html index 75c70597..f3f61812 100755 --- a/devui/data-table/demo/data-table-demo.component.html +++ b/devui/data-table/demo/data-table-demo.component.html @@ -6,19 +6,15 @@ {{ 'components.datatable.basicDemo.description' | translate }} - - - - - - - - - - - - - + + + + + + + + + @@ -41,19 +37,15 @@ {{ 'components.datatable.interactionDemo.description' | translate }} - - - - - - - - - - - - - + + + + + + + + + @@ -61,19 +53,15 @@
    {{ 'components.datatable.checkOptionsDemo.title' | translate }}
    {{ 'components.datatable.checkOptionsDemo.description' | translate }}
    - - - - - - - - - - - - - + + + + + + + + + @@ -111,20 +99,16 @@
    {{ 'components.datatable.headerGroupingDemo.description' | translate }}
    - - - - - - + + + + - - - - - - + + + + @@ -134,19 +118,15 @@
    {{ 'components.datatable.editableDemo.description' | translate }}
    - - - - - - - - - - - - - + + + + + + + + + @@ -156,19 +136,15 @@
    {{ 'components.datatable.expandRowDemo.description' | translate }}
    - - - - - - - - - - - - - + + + + + + + + + @@ -176,19 +152,15 @@
    {{ 'components.datatable.treeTableDemo.title' | translate }}
    {{ 'components.datatable.treeTableDemo.description' | translate }}
    - - - - - - - - - - - - - + + + + + + + + + @@ -196,19 +168,15 @@
    {{ 'components.datatable.fixColumnDemo.title' | translate }}
    {{ 'components.datatable.fixColumnDemo.description' | translate }}
    - - - - - - - - - - - - - + + + + + + + + + diff --git a/devui/data-table/demo/data-table-demo.component.ts b/devui/data-table/demo/data-table-demo.component.ts index 5c861873..ac2a7c57 100755 --- a/devui/data-table/demo/data-table-demo.component.ts +++ b/devui/data-table/demo/data-table-demo.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { TranslateService, TranslationChangeEvent } from '@ngx-translate/core'; import { DevuiSourceData } from 'ng-devui/shared/devui-codebox'; +import { TranslateService, TranslationChangeEvent } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; @Component({ selector: 'd-datatable-demo', diff --git a/devui/data-table/demo/data-table-demo.module.ts b/devui/data-table/demo/data-table-demo.module.ts index 8552764a..f90efa54 100755 --- a/devui/data-table/demo/data-table-demo.module.ts +++ b/devui/data-table/demo/data-table-demo.module.ts @@ -95,10 +95,8 @@ import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.componen InteractionColumnComponent, VirtualScrollComponent, MutilStylesComponent, - FixHeightVirtualScrollComponent, + FixHeightVirtualScrollComponent ], providers: [], - }) -export class DataTableDemoModule { -} +export class DataTableDemoModule {} diff --git a/devui/data-table/demo/interaction-column/interaction-column.component.html b/devui/data-table/demo/interaction-column/interaction-column.component.html index f31cbfea..aa3e73e7 100644 --- a/devui/data-table/demo/interaction-column/interaction-column.component.html +++ b/devui/data-table/demo/interaction-column/interaction-column.component.html @@ -35,7 +35,6 @@ [sortable]="true" [width]="'150px'" [minWidth]="'100px'" - [maxWidth]="'200px'" [filterable]="true" [closeFilterWhenScroll]="true" [filterIconActive]="filterIconActive" diff --git a/devui/data-table/demo/interaction/interaction.component.html b/devui/data-table/demo/interaction/interaction.component.html index fa793b81..bac69f5a 100644 --- a/devui/data-table/demo/interaction/interaction.component.html +++ b/devui/data-table/demo/interaction/interaction.component.html @@ -42,7 +42,7 @@ dHeadCell [sortable]="true" [showSortIcon]="true" - [(sortDirection)]="genderSortDirecticon" + [(sortDirection)]="genderSortDirection" (sortChange)="onSortChange($event, 'Gender')" [filterable]="true" [filterMultiple]="false" diff --git a/devui/data-table/demo/interaction/interaction.component.ts b/devui/data-table/demo/interaction/interaction.component.ts index 22068a89..c405bf1c 100644 --- a/devui/data-table/demo/interaction/interaction.component.ts +++ b/devui/data-table/demo/interaction/interaction.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { DataTableComponent, SortDirection, SortEventArg, TableWidthConfig } from 'ng-devui/data-table'; import { originSource, SourceType } from '../mock-data'; @@ -59,39 +59,46 @@ export class InteractionComponent implements OnInit { }, { field: '$index', - width: '20%' + width: '150px' }, { field: 'firstName', - width: '20%' + width: '150px' }, { field: 'lastName', - width: '20%' + width: '150px' }, { field: 'gender', - width: '20%' + width: '150px' }, { field: 'dob', - width: '20%' + width: '150px' }, { field: 'description', - width: '20%' + width: '150px' } ]; + _totalWidth = 0; + lastWidth = 0; + firstResize = true; + lastNameSortDirection = SortDirection.ASC; - genderSortDirecticon = SortDirection.default; + genderSortDirection = SortDirection.default; sortParams = {field: 'lastName', direction: this.lastNameSortDirection}; checkboxList = []; allChecked = false; halfChecked = false; filterIconActive = false; - constructor(private ref: ChangeDetectorRef) { } + constructor( + private ref: ChangeDetectorRef, + private ele: ElementRef + ) { } ngOnInit() { this.checkboxList = JSON.parse(JSON.stringify(originSource.slice(0, 6))); this.sortableDataSource[0]['$checkDisabled'] = true; @@ -104,12 +111,36 @@ export class InteractionComponent implements OnInit { }; } - onResize({ width }, field) { + onResize({ width, beforeWidth }, field) { const index = this.tableWidthConfig.findIndex((config) => { return config.field === field; }); if (index > -1) { + if (this.firstResize) { + this.firstResize = false; + const ratio = beforeWidth / parseInt(this.tableWidthConfig[index].width, 10); + this.tableWidthConfig.forEach(t => { + t.width = parseInt(t.width, 10) * ratio + 'px'; + }); + this._totalWidth = this.ele.nativeElement.querySelector('.table-wrap').offsetWidth; + this.lastWidth = parseInt(this.tableWidthConfig.slice(-1)[0].width); + } this.tableWidthConfig[index].width = width + 'px'; + + let newWidthTotal = 0; + this.tableWidthConfig.forEach(t => { + newWidthTotal += parseInt(t.width, 10); + }); + + const lastCol = this.tableWidthConfig[this.tableWidthConfig.length - 1]; + const lastColWidth = parseInt(lastCol.width, 10); + const changeValue = newWidthTotal - this._totalWidth; + if (changeValue < 0) { + lastCol.width = lastColWidth + this._totalWidth - newWidthTotal + 'px'; + } else if (lastColWidth > this.lastWidth) { + const lastChange = (lastColWidth - this.lastWidth) > changeValue ? changeValue : (lastColWidth - this.lastWidth); + lastCol.width = lastColWidth - lastChange + 'px'; + } } } diff --git a/devui/data-table/demo/mutil-styles/mutil-styles.component.html b/devui/data-table/demo/mutil-styles/mutil-styles.component.html index c2ab944e..d15e70c7 100644 --- a/devui/data-table/demo/mutil-styles/mutil-styles.component.html +++ b/devui/data-table/demo/mutil-styles/mutil-styles.component.html @@ -37,7 +37,7 @@ [size]="activeSizeTab" [tableLayout]="activeLayoutTab" > -
    + @@ -46,6 +46,19 @@ + diff --git a/devui/datepicker-pro/lib/calendar-panel.component.scss b/devui/datepicker-pro/lib/calendar-panel.component.scss index 581c7497..fcd4b732 100644 --- a/devui/datepicker-pro/lib/calendar-panel.component.scss +++ b/devui/datepicker-pro/lib/calendar-panel.component.scss @@ -230,6 +230,30 @@ border-color: transparent; } } + + &.devui-table-date-marked span { + position: relative; + + &::after { + content: ''; + display: block; + position: absolute; + right: 9px; + bottom: 2px; + width: 3px; + height: 3px; + border-radius: 50%; + background-color: $devui-list-item-active-bg; + } + } + + &.devui-table-date-marked.devui-table-date-selected span::after { + background-color: $devui-list-item-active-text; + } + + &.devui-table-date-suggested { + border-bottom: 1px solid $devui-link-light-active; + } } &.devui-single-date .devui-table-date { diff --git a/devui/datepicker-pro/lib/calendar-panel.component.ts b/devui/datepicker-pro/lib/calendar-panel.component.ts index 8dae7f7e..e5e57903 100644 --- a/devui/datepicker-pro/lib/calendar-panel.component.ts +++ b/devui/datepicker-pro/lib/calendar-panel.component.ts @@ -46,6 +46,7 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { set curHoverDate(value: Date) { this.pickerSrv.curHoverDate = value; + this.cdr.detectChanges(); } get curDate(): Date { @@ -66,7 +67,10 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { this.pickerSrv.curRangeDate[0] = value; } else if (this.pickerSrv.currentActiveInput === 'end') { if (this.pickerSrv.showTime) { - this.pickerSrv.curRangeDate[1] = this.pickerSrv.curRangeDate[1] ? value : new Date(value.setHours(23, 59, 59)); + this.pickerSrv.curRangeDate[1] = + (this.pickerSrv.curRangeDate[1] && this.pickerSrv.curRangeDate[1].toDateString() === value.toDateString()) + ? value + : new Date(value.setHours(23, 59, 59)); } else { this.pickerSrv.curRangeDate[1] = new Date(value.setHours(23, 59, 59)); } @@ -84,6 +88,10 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { this.pickerSrv.curRangeDate = dateList; } + get markDateTemplate() { + return this.pickerSrv.markDateInfoTemplate; + } + constructor( protected i18n: I18nService, private pickerSrv: DatepickerProService, @@ -123,6 +131,8 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { if (!this.scrollListener) { this.initScrollListener(); } + } else { + this.curHoverDate = null; } }); @@ -142,6 +152,9 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { if (type === 'start') { this.goToDate(this.selectedRangeDate[0] || this.selectedRangeDate[1] || new Date()); } else { + if (!this.selectedRangeDate[1] && this.selectedRangeDate[0]) { + this.updateRangeDate([this.selectedRangeDate[0], this.selectedRangeDate[0]]); + } this.goToDate(this.selectedRangeDate[1] || this.selectedRangeDate[0] || new Date()); } }); @@ -206,8 +219,8 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { }; } - private getDisplayWeeks(yearindex: number, monthIndex: number): DevuiCalendarDateItem[] { - const firstDayOfMonth = new Date(yearindex, monthIndex, 1); + private getDisplayWeeks(yearIndex: number, monthIndex: number): DevuiCalendarDateItem[] { + const firstDayOfMonth = new Date(yearIndex, monthIndex, 1); const weekOfDay = firstDayOfMonth.getDay(); const startDate = new Date(firstDayOfMonth.getTime() - weekOfDay * DAY_DURATION); const displayWeeks = []; @@ -265,9 +278,9 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { const curDate = (this.pickerSrv.currentActiveInput === 'start' ? (dateList[0] || dateList[1]) : (dateList[1] || dateList[0])) || new Date(); - const morethanOneYear = Math.abs(curDate.getFullYear() - (this.currentBodyIndex / 12 + this.pickerSrv.calendarRange[0])) > 1; + const moreThanOneYear = Math.abs(curDate.getFullYear() - (this.currentBodyIndex / 12 + this.pickerSrv.calendarRange[0])) > 1; this.selectedRangeDate = dateList; - this.goToDate(curDate, morethanOneYear ? 'auto' : 'smooth'); + this.goToDate(curDate, moreThanOneYear ? 'auto' : 'smooth'); this.cdr.detectChanges(); } @@ -277,9 +290,9 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { this.cdr.detectChanges(); return; } - const morethanOneYear = Math.abs(date.getFullYear() - (this.currentBodyIndex / 12 + this.pickerSrv.calendarRange[0])) > 1; + const moreThanOneYear = Math.abs(date.getFullYear() - (this.currentBodyIndex / 12 + this.pickerSrv.calendarRange[0])) > 1; this.curDate = date; - this.goToDate(this.curDate, morethanOneYear ? 'auto' : 'smooth'); + this.goToDate(this.curDate, moreThanOneYear ? 'auto' : 'smooth'); this.cdr.detectChanges(); } @@ -378,6 +391,14 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { return this.pickerSrv.isDateAbandon(date); } + isDateSuggest(date: Date): boolean { + return this.pickerSrv.isInSuggestList(date); + } + + isDateMarked(date: Date): boolean { + return this.pickerSrv.isMarkedDate(date); + } + isSingleDate(): boolean { if (this.pickerSrv.currentActiveInput === 'start') { return !this.pickerSrv.curRangeDate[1]; @@ -391,22 +412,23 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { this.curHoverDate = null; return; } + this.curHoverDate = date; if (this.isWeekSelect) { this.weekHoverRange = this.getWeekRange(date); this.curWeekHoverDate = date; + this.cdr.markForCheck(); return; } - - if (this.isRangeType) { - this.curHoverDate = date; - } } getWeekRange(date: Date) { if (!date) { return []; } - const weekStart = new Date(date.getTime() - (date.getDay() - this.pickerSrv.startIndexOfWeek) * DAY_DURATION); + const diff = date.getDay() < this.pickerSrv.startIndexOfWeek + ? 7 - (this.pickerSrv.startIndexOfWeek - date.getDay()) + : date.getDay() - this.pickerSrv.startIndexOfWeek; + const weekStart = new Date(date.getTime() - diff * DAY_DURATION); const weekEnd = new Date(weekStart.getTime() + DAY_DURATION * 6); weekEnd.setHours(23, 59, 59); @@ -420,8 +442,7 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { if (this.pickerSrv.isDateActive(date)) { return false; } - return (this.pickerSrv.isDateInRange(date) || - (range[0]?.getTime() < time && time < range[1]?.getTime()) || + return ((range[0]?.getTime() < time && time < range[1]?.getTime()) || (range[0]?.toDateString() === timeStr || timeStr === range[1]?.toDateString())); } @@ -444,6 +465,14 @@ export class CalendarPanelComponent implements OnInit, OnDestroy { return num < 10 ? `0${num}` : `${num}`; } + isPopoverShow(day: any): boolean { + if (this.isDateMarked(day.date) && this.curHoverDate === day.date && this.markDateTemplate) { + return true; + } else { + return false; + } + } + ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); diff --git a/devui/datepicker-pro/lib/year-panel.component.scss b/devui/datepicker-pro/lib/year-panel.component.scss index 2a65a4f5..122cb225 100644 --- a/devui/datepicker-pro/lib/year-panel.component.scss +++ b/devui/datepicker-pro/lib/year-panel.component.scss @@ -97,11 +97,11 @@ cursor: not-allowed; &:first-of-type { - border-radius: 4px 0 0 4px; + border-radius: $devui-border-radius-feedback 0 0 $devui-border-radius-feedback; } &:last-of-type { - border-radius: 0 4px 4px 0; + border-radius: 0 $devui-border-radius-feedback $devui-border-radius-feedback 0; } } } diff --git a/devui/datepicker-pro/range-datepicker-pro.component.html b/devui/datepicker-pro/range-datepicker-pro.component.html index 6f09fef3..6107be6f 100644 --- a/devui/datepicker-pro/range-datepicker-pro.component.html +++ b/devui/datepicker-pro/range-datepicker-pro.component.html @@ -104,7 +104,7 @@ 'devui-end-side': currentActiveInput === 'end' }" > -
    +
    (); @Output() confirmEvent = new EventEmitter(); @ContentChild('customTemplate') customTemplate: TemplateRef; @ContentChild('footerTemplate') footerTemplate: TemplateRef; @ContentChild('hostTemplate') hostTemplate: TemplateRef; + @ContentChild('markDateInfoTemplate') set markDateInfoTemplate(tmp: TemplateRef) { + this.pickerSrv.markDateInfoTemplate = tmp; + }; @ViewChild('dateInputStart') datepickerInputStart: ElementRef; @ViewChild('dateInputEnd') datepickerInputEnd: ElementRef; @@ -362,11 +371,11 @@ export class RangeDatepickerProComponent implements OnInit, OnDestroy, AfterView this.isOpen = true; } - clear(event?: MouseEvent) { + clear(event?: MouseEvent, isHandle?: boolean) { if (event) { event.stopPropagation(); } - if (this.disabled) { + if (this.disabled && isHandle) { return; } this.pickerSrv.updateDateValue.next({ diff --git a/devui/datepicker/dateRangePicker.spec.ts b/devui/datepicker/dateRangePicker.spec.ts index 392727ca..f9adcd14 100644 --- a/devui/datepicker/dateRangePicker.spec.ts +++ b/devui/datepicker/dateRangePicker.spec.ts @@ -705,9 +705,6 @@ function testInputParam(fixture, wrapperEle, component) { const testTemplate = wrapperEle.querySelector('.test-template'); expect(testTemplate).toBeTruthy(); // ToDo: click后会直接进入组件的ngOnDestroy,并且没有走chooseDate,但是toHaveBeenCalled没有报错也没有执行,预测detectChanges直接结束了it - // testTemplate.dispatchEvent(new Event('click')); - // fixture.detectChanges(); - // expect(component.getValue).toHaveBeenCalled(); tickEvent(document.querySelector('.devui-date-range-custom'), new Event('click'), fixture); expect(wrapperEle.querySelector('.test-class')).toBeTruthy(); diff --git a/devui/datepicker/datepicker-cdk-overlay.component.ts b/devui/datepicker/datepicker-cdk-overlay.component.ts index 6adfebd4..e9a0ea6f 100755 --- a/devui/datepicker/datepicker-cdk-overlay.component.ts +++ b/devui/datepicker/datepicker-cdk-overlay.component.ts @@ -293,7 +293,7 @@ export class DatePickerAppendToBodyComponent implements OnInit, OnChanges, OnDes private writeModelValue(selectDateObj: any) { let selectDate; let dateReason = SelectDateChangeReason.time; - if (selectDateObj && typeof selectDateObj === 'object' && selectDateObj.hasOwnProperty('selectedDate')) { + if (selectDateObj && typeof selectDateObj === 'object' && Object.prototype.hasOwnProperty.call(selectDateObj, 'selectedDate')) { selectDate = selectDateObj.selectedDate; dateReason = selectDateObj.reason; } diff --git a/devui/datepicker/datepicker.component.ts b/devui/datepicker/datepicker.component.ts index cff955bb..6fbf08a7 100755 --- a/devui/datepicker/datepicker.component.ts +++ b/devui/datepicker/datepicker.component.ts @@ -95,20 +95,38 @@ export class DatepickerComponent implements OnInit, OnChanges, OnDestroy, Contro this.minDate.getFullYear() : (nowDate).getFullYear() - Math.floor(this._yearNumber / 2); this.nowMaxYear = (nowDate).getFullYear() + Math.floor(this._yearNumber / 2) > this.maxDate.getFullYear() ? this.maxDate.getFullYear() : (nowDate).getFullYear() + Math.floor(this._yearNumber / 2); + this.initMode(); this.onSelectDateChanged(); this.onDisplayWeeksChange(); this.onYearRangeChange(); this.initDatePicker(); - this.initMode(); } initMode() { if (this.mode === 'year') { this.openChooseYear = true; this.openChooseMonth = false; + if(!this.selectedDate){ + this.selectedDate = new Date(); + } + if(this.maxDate.getTime() < this.selectedDate.getTime()){ + this.selectedDate = new Date(this.maxDate); + } + if(this.minDate.getTime() > this.selectedDate.getTime()){ + this.selectedDate = new Date(this.minDate); + } } else if (this.mode === 'month') { this.openChooseYear = false; this.openChooseMonth = true; + if(!this.selectedDate){ + this.selectedDate = new Date(); + } + if(this.maxDate.getTime() < this.selectedDate.getTime()){ + this.selectedDate = new Date(this.maxDate); + } + if(this.minDate.getTime() > this.selectedDate.getTime()){ + this.selectedDate = new Date(this.minDate); + } } else { this.openChooseYear = this.openChooseMonth = false; } diff --git a/devui/datepicker/datepicker.directive.ts b/devui/datepicker/datepicker.directive.ts index f0e180d0..29cd73b9 100755 --- a/devui/datepicker/datepicker.directive.ts +++ b/devui/datepicker/datepicker.directive.ts @@ -220,7 +220,7 @@ export class DatepickerDirective implements OnInit, OnDestroy, ControlValueAcces writeValue(obj: any): void { let curDate; - if (obj && typeof obj === 'object' && obj.hasOwnProperty('selectedDate')) { + if (obj && typeof obj === 'object' && Object.prototype.hasOwnProperty.call(obj, 'selectedDate')) { curDate = obj.selectedDate; } else { curDate = obj; @@ -274,7 +274,7 @@ export class DatepickerDirective implements OnInit, OnDestroy, ControlValueAcces private writeModelValue(selectDateObj: any) { let selectDate; let dateReason = SelectDateChangeReason.time; - if (selectDateObj && typeof selectDateObj === 'object' && selectDateObj.hasOwnProperty('selectedDate')) { + if (selectDateObj && typeof selectDateObj === 'object' && Object.prototype.hasOwnProperty.call(selectDateObj, 'selectedDate')) { selectDate = selectDateObj.selectedDate; dateReason = selectDateObj.reason; } else { @@ -290,7 +290,7 @@ export class DatepickerDirective implements OnInit, OnDestroy, ControlValueAcces if (this.isOpen) { this.cmpRef.instance.writeValue(this.selectedDate); } - if (selectDateObj && typeof selectDateObj === 'object' && selectDateObj.hasOwnProperty('selectedDate')) { + if (selectDateObj && typeof selectDateObj === 'object' && Object.prototype.hasOwnProperty.call(selectDateObj, 'selectedDate')) { this.selectedDateChange.emit({ reason: dateReason, selectedDate: this.selectedDate, diff --git a/devui/datepicker/datepicker.spec.ts b/devui/datepicker/datepicker.spec.ts index b567261f..5d58a697 100644 --- a/devui/datepicker/datepicker.spec.ts +++ b/devui/datepicker/datepicker.spec.ts @@ -17,7 +17,7 @@ class CommonFunctions { static i18nText() { const lang = localStorage.getItem('lang') ? localStorage.getItem('lang').toLocaleLowerCase() : 'zh-cn'; - if (this.i18nConfig.hasOwnProperty(lang)) { + if (Object.prototype.hasOwnProperty.call(this.i18nConfig, lang)) { return this.i18nConfig[lang]; } else { return zhCN; @@ -973,7 +973,6 @@ function testNgModelAndYearMonth(fixture, wrapperEle, component) { expect(component.inputEle.nativeElement.value).toBe( `${new Date().getFullYear()}/${padZero(new Date().getMonth() + 1)}/05` ); - // expect(currentDay).toBe('05'); closeDatePicker(fixture); component.inputEle.nativeElement.value = `${new Date().getFullYear()}/${padZero(new Date().getMonth() + 1)}/05`; diff --git a/devui/datepicker/demo/set-mode/set-mode.component.html b/devui/datepicker/demo/set-mode/set-mode.component.html index ae62105d..606afd6e 100644 --- a/devui/datepicker/demo/set-mode/set-mode.component.html +++ b/devui/datepicker/demo/set-mode/set-mode.component.html @@ -41,6 +41,7 @@
    mode="month"
    [(ngModel)]="selectedDate2" autocomplete="off" dDatepicker + [maxDate]="maxDate" #datePicker2="datepicker" (selectedDateChange)="getValue($event)" [cssClass]="'custom-css-class'" diff --git a/devui/datepicker/demo/set-mode/set-mode.component.ts b/devui/datepicker/demo/set-mode/set-mode.component.ts index 3c6620ba..b19fc806 100644 --- a/devui/datepicker/demo/set-mode/set-mode.component.ts +++ b/devui/datepicker/demo/set-mode/set-mode.component.ts @@ -8,6 +8,7 @@ import { Component } from '@angular/core'; export class SetModeComponent { selectedDate1 = null; selectedDate2 = null; + maxDate = new Date().setMonth(8); getValue(value) { // 当[mode]="'year'",返回值是当年第一天的日期对象,请右键检查打开console查看 // 当[mode]="'month'",返回值是当月第一天的日期对象,请右键检查打开console查看 diff --git a/devui/datepicker/doc/api-cn.md b/devui/datepicker/doc/api-cn.md index b5a16cfc..4058daa9 100644 --- a/devui/datepicker/doc/api-cn.md +++ b/devui/datepicker/doc/api-cn.md @@ -54,12 +54,12 @@ npm install @angular/cdk --save ``` ```TypeScript -import { ScrollDispatchModule } from '@angular/cdk/scrolling'; +import { ScrollingModule } from '@angular/cdk/scrolling'; @NgModule({ imports: [ // ... - ScrollDispatchModule, + ScrollingModule, // ... ] }) diff --git a/devui/datepicker/doc/api-en.md b/devui/datepicker/doc/api-en.md index e2911901..7efc769d 100644 --- a/devui/datepicker/doc/api-en.md +++ b/devui/datepicker/doc/api-en.md @@ -54,12 +54,12 @@ npm install @angular/cdk --save ``` ```TypeScript -import {ScrollDispatchModule} from '@angular/cdk/scrolling'; +import {ScrollingModule} from '@angular/cdk/scrolling'; @NgModule({ imports: [ //... -ScrollDispatchModule, +ScrollingModule, //... ] }) diff --git a/devui/datepicker/single-date-range-picker.component.ts b/devui/datepicker/single-date-range-picker.component.ts index bffb254b..d8c1e9e4 100644 --- a/devui/datepicker/single-date-range-picker.component.ts +++ b/devui/datepicker/single-date-range-picker.component.ts @@ -330,7 +330,7 @@ export class SingleDateRangePickerComponent extends SingleDatepickerComponent im } ngOnChanges(changes: SimpleChanges) { - if (changes.hasOwnProperty('selectedRange')) { + if (Object.prototype.hasOwnProperty.call(changes, 'selectedRange')) { this.selectingRange = false; [this.rangeStart, this.rangeEnd] = changes['selectedRange'].currentValue; } diff --git a/devui/datepicker/two-datepicker/two-datepicker-single.component.ts b/devui/datepicker/two-datepicker/two-datepicker-single.component.ts index 6e03e725..b07813e4 100644 --- a/devui/datepicker/two-datepicker/two-datepicker-single.component.ts +++ b/devui/datepicker/two-datepicker/two-datepicker-single.component.ts @@ -216,7 +216,7 @@ export class TwoDatepickerSingleComponent extends SingleDatepickerComponent impl } ngOnChanges(changes: SimpleChanges) { - if (changes.hasOwnProperty('selectedRange')) { + if (Object.prototype.hasOwnProperty.call(changes, 'selectedRange')) { [this.rangeStart, this.rangeEnd] = changes['selectedRange'].currentValue; if (this.rangeStart && this.rangeEnd) { this.selectingRange = false; diff --git a/devui/datepicker/twoDatePicker.spec.ts b/devui/datepicker/twoDatePicker.spec.ts index 8a45b603..eac96439 100644 --- a/devui/datepicker/twoDatePicker.spec.ts +++ b/devui/datepicker/twoDatePicker.spec.ts @@ -17,7 +17,7 @@ class CommonFunctions { static i18nText() { const lang = localStorage.getItem('lang') ? localStorage.getItem('lang').toLocaleLowerCase() : 'zh-cn'; - if (this.i18nConfig.hasOwnProperty(lang)) { + if (Object.prototype.hasOwnProperty.call(this.i18nConfig, lang)) { return this.i18nConfig[lang]; } else { return zhCN; diff --git a/devui/design-token/color/demo/color/color.component.html b/devui/design-token/color/demo/color/color.component.html index 1f73af80..81e76ad2 100644 --- a/devui/design-token/color/demo/color/color.component.html +++ b/devui/design-token/color/demo/color/color.component.html @@ -12,51 +12,123 @@

    {{ 'components.design-color.colorDemo.instance.title' - -

    - - - - - - - - - - - +
    +
    {{ tableNameList[index] }}
    + +
    - - - - - - + + + + + + - - - + + + + + + + + + + + + + + +
    + {{ 'components.design-color.colorDemo.instance.formColor' | translate }} +
    +
    +
    +
    +
    {{ '$devui-' + col + '-' + block }}
    +
    {{ colorList[index][idx] }}
    +
    +
    + {{ col }} +
    +
    +
    + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/devui/design-token/color/demo/color/color.component.scss b/devui/design-token/color/demo/color/color.component.scss index 54ab4988..52ae97e4 100644 --- a/devui/design-token/color/demo/color/color.component.scss +++ b/devui/design-token/color/demo/color/color.component.scss @@ -82,3 +82,216 @@ td { .devui-catalog-title { font-weight: bold; } + +.swatches { + display: flex; + flex-wrap: wrap; + overflow: hidden; +} + +.formColor { + margin: 16px 15px 16px 0; + text-align: center; + line-height: 50px; + color: $devui-text; + height: 100%; + font-size: $devui-font-size-page-title; + font-weight: 550; + + .swatches-block { + line-height: 20px; + width: 145px; + position: relative; + height: 64px; + font-size: 12px; + box-sizing: border-box; + padding: 12px; + display: flex; + flex-direction: column; + justify-content: space-between; + } +} + +.formColor:last-child { + margin-right: 0; +} + +$colorMap: ( + '$devui-blue-5': $devui-blue-5, + '$devui-blue-10': $devui-blue-10, + '$devui-blue-20': $devui-blue-20, + '$devui-blue-30': $devui-blue-30, + '$devui-blue-40': $devui-blue-40, + '$devui-blue-50': $devui-blue-50, + '$devui-blue-60': $devui-blue-60, + '$devui-blue-70': $devui-blue-70, + '$devui-blue-80': $devui-blue-80, + '$devui-blue-90': $devui-blue-90, + '$devui-blue-100': $devui-blue-100, + '$devui-sky-5': $devui-sky-5, + '$devui-sky-10': $devui-sky-10, + '$devui-sky-20': $devui-sky-20, + '$devui-sky-30': $devui-sky-30, + '$devui-sky-40': $devui-sky-40, + '$devui-sky-50': $devui-sky-50, + '$devui-sky-60': $devui-sky-60, + '$devui-sky-70': $devui-sky-70, + '$devui-sky-80': $devui-sky-80, + '$devui-sky-90': $devui-sky-90, + '$devui-sky-100': $devui-sky-100, + '$devui-green-5': $devui-green-5, + '$devui-green-10': $devui-green-10, + '$devui-green-20': $devui-green-20, + '$devui-green-30': $devui-green-30, + '$devui-green-40': $devui-green-40, + '$devui-green-50': $devui-green-50, + '$devui-green-60': $devui-green-60, + '$devui-green-70': $devui-green-70, + '$devui-green-80': $devui-green-80, + '$devui-green-90': $devui-green-90, + '$devui-green-100': $devui-green-100, + '$devui-lime-5': $devui-lime-5, + '$devui-lime-10': $devui-lime-10, + '$devui-lime-20': $devui-lime-20, + '$devui-lime-30': $devui-lime-30, + '$devui-lime-40': $devui-lime-40, + '$devui-lime-50': $devui-lime-50, + '$devui-lime-60': $devui-lime-60, + '$devui-lime-70': $devui-lime-70, + '$devui-lime-80': $devui-lime-80, + '$devui-lime-90': $devui-lime-90, + '$devui-lime-100': $devui-lime-100, + '$devui-yellow-5': $devui-yellow-5, + '$devui-yellow-10': $devui-yellow-10, + '$devui-yellow-20': $devui-yellow-20, + '$devui-yellow-30': $devui-yellow-30, + '$devui-yellow-40': $devui-yellow-40, + '$devui-yellow-50': $devui-yellow-50, + '$devui-yellow-60': $devui-yellow-60, + '$devui-yellow-70': $devui-yellow-70, + '$devui-yellow-80': $devui-yellow-80, + '$devui-yellow-90': $devui-yellow-90, + '$devui-yellow-100': $devui-yellow-100, + '$devui-orange-5': $devui-orange-5, + '$devui-orange-10': $devui-orange-10, + '$devui-orange-20': $devui-orange-20, + '$devui-orange-30': $devui-orange-30, + '$devui-orange-40': $devui-orange-40, + '$devui-orange-50': $devui-orange-50, + '$devui-orange-60': $devui-orange-60, + '$devui-orange-70': $devui-orange-70, + '$devui-orange-80': $devui-orange-80, + '$devui-orange-90': $devui-orange-90, + '$devui-orange-100': $devui-orange-100, + '$devui-red-5': $devui-red-5, + '$devui-red-10': $devui-red-10, + '$devui-red-20': $devui-red-20, + '$devui-red-30': $devui-red-30, + '$devui-red-40': $devui-red-40, + '$devui-red-50': $devui-red-50, + '$devui-red-60': $devui-red-60, + '$devui-red-70': $devui-red-70, + '$devui-red-80': $devui-red-80, + '$devui-red-90': $devui-red-90, + '$devui-red-100': $devui-red-100, + '$devui-magenta-5': $devui-magenta-5, + '$devui-magenta-10': $devui-magenta-10, + '$devui-magenta-20': $devui-magenta-20, + '$devui-magenta-30': $devui-magenta-30, + '$devui-magenta-40': $devui-magenta-40, + '$devui-magenta-50': $devui-magenta-50, + '$devui-magenta-60': $devui-magenta-60, + '$devui-magenta-70': $devui-magenta-70, + '$devui-magenta-80': $devui-magenta-80, + '$devui-magenta-90': $devui-magenta-90, + '$devui-magenta-100': $devui-magenta-100, + '$devui-purple-5': $devui-purple-5, + '$devui-purple-10': $devui-purple-10, + '$devui-purple-20': $devui-purple-20, + '$devui-purple-30': $devui-purple-30, + '$devui-purple-40': $devui-purple-40, + '$devui-purple-50': $devui-purple-50, + '$devui-purple-60': $devui-purple-60, + '$devui-purple-70': $devui-purple-70, + '$devui-purple-80': $devui-purple-80, + '$devui-purple-90': $devui-purple-90, + '$devui-purple-100': $devui-purple-100, + '$devui-gray-5': $devui-gray-5, + '$devui-gray-10': $devui-gray-10, + '$devui-gray-20': $devui-gray-20, + '$devui-gray-30': $devui-gray-30, + '$devui-gray-40': $devui-gray-40, + '$devui-gray-50': $devui-gray-50, + '$devui-gray-60': $devui-gray-60, + '$devui-gray-70': $devui-gray-70, + '$devui-gray-80': $devui-gray-80, + '$devui-gray-90': $devui-gray-90, + '$devui-gray-100': $devui-gray-100, + '$devui-slate-5': $devui-slate-5, + '$devui-slate-10': $devui-slate-10, + '$devui-slate-20': $devui-slate-20, + '$devui-slate-30': $devui-slate-30, + '$devui-slate-40': $devui-slate-40, + '$devui-slate-50': $devui-slate-50, + '$devui-slate-60': $devui-slate-60, + '$devui-slate-70': $devui-slate-70, + '$devui-slate-80': $devui-slate-80, + '$devui-slate-90': $devui-slate-90, + '$devui-slate-100': $devui-slate-100, + '$devui-zinc-5': $devui-zinc-5, + '$devui-zinc-10': $devui-zinc-10, + '$devui-zinc-20': $devui-zinc-20, + '$devui-zinc-30': $devui-zinc-30, + '$devui-zinc-40': $devui-zinc-40, + '$devui-zinc-50': $devui-zinc-50, + '$devui-zinc-60': $devui-zinc-60, + '$devui-zinc-70': $devui-zinc-70, + '$devui-zinc-80': $devui-zinc-80, + '$devui-zinc-90': $devui-zinc-90, + '$devui-zinc-100': $devui-zinc-100, + '$devui-dark-gray-5': $devui-dark-gray-5, + '$devui-dark-gray-10': $devui-dark-gray-10, + '$devui-dark-gray-20': $devui-dark-gray-20, + '$devui-dark-gray-30': $devui-dark-gray-30, + '$devui-dark-gray-40': $devui-dark-gray-40, + '$devui-dark-gray-50': $devui-dark-gray-50, + '$devui-dark-gray-60': $devui-dark-gray-60, + '$devui-dark-gray-70': $devui-dark-gray-70, + '$devui-dark-gray-80': $devui-dark-gray-80, + '$devui-dark-gray-90': $devui-dark-gray-90, + '$devui-dark-gray-100': $devui-dark-gray-100, + '$devui-dark-slate-5': $devui-dark-slate-5, + '$devui-dark-slate-10': $devui-dark-slate-10, + '$devui-dark-slate-20': $devui-dark-slate-20, + '$devui-dark-slate-30': $devui-dark-slate-30, + '$devui-dark-slate-40': $devui-dark-slate-40, + '$devui-dark-slate-50': $devui-dark-slate-50, + '$devui-dark-slate-60': $devui-dark-slate-60, + '$devui-dark-slate-70': $devui-dark-slate-70, + '$devui-dark-slate-80': $devui-dark-slate-80, + '$devui-dark-slate-90': $devui-dark-slate-90, + '$devui-dark-slate-100': $devui-dark-slate-100, + '$devui-dark-zinc-5': $devui-dark-zinc-5, + '$devui-dark-zinc-10': $devui-dark-zinc-10, + '$devui-dark-zinc-20': $devui-dark-zinc-20, + '$devui-dark-zinc-30': $devui-dark-zinc-30, + '$devui-dark-zinc-40': $devui-dark-zinc-40, + '$devui-dark-zinc-50': $devui-dark-zinc-50, + '$devui-dark-zinc-60': $devui-dark-zinc-60, + '$devui-dark-zinc-70': $devui-dark-zinc-70, + '$devui-dark-zinc-80': $devui-dark-zinc-80, + '$devui-dark-zinc-90': $devui-dark-zinc-90, + '$devui-dark-zinc-100': $devui-dark-zinc-100, +); + +$colorList: 'blue', 'sky', 'green', 'lime', 'yellow', 'orange', 'red', 'magenta', 'purple', + 'gray', 'slate', 'zinc', 'dark-gray', 'dark-slate', 'dark-zinc'; +$list: 5 10 20 30 40 50 60 70 80 90 100; + +@each $color in $colorList { + @each $i in $list { + .block-#{$color}-#{$i} { + background-color: map-get($colorMap, #{'$'}devui-#{$color}-#{$i}); + } + } +} diff --git a/devui/design-token/color/demo/color/color.component.ts b/devui/design-token/color/demo/color/color.component.ts index b20e1f1b..7d69999b 100644 --- a/devui/design-token/color/demo/color/color.component.ts +++ b/devui/design-token/color/demo/color/color.component.ts @@ -22,7 +22,20 @@ export class ColorComponent implements OnInit, OnDestroy { headerExpandConfig: TableExpandConfig; activeTab: string | number = 'tab1'; colorSource = []; + textColorSource = []; + borderColorSource = []; + backgroundColorSource = []; + statusColorSource = []; + themeColorSource = []; catalogs: CatalogConfig[] = []; + catalogsList: CatalogConfig[] = []; + tableList: CatalogConfig[][] = []; + colorTypeList = ['blue', 'sky', 'green', 'lime', 'yellow', 'orange', 'red', 'magenta', 'purple']; + // TODO: 灰色类变量用于文字,边框,背景,暂不支持开发直接使用灰色变量 + colorTypeSecList = ['gray', 'slate', 'zinc', 'dark-gray', 'dark-slate', 'dark-zinc']; + colorNumberList = ['5', '10' ,'20', '30', '40', '50', '60', '70', '80', '90', '100']; + colorList = []; + tableNameList = []; colors = []; constructor(private translate: TranslateService) {} @@ -39,7 +52,17 @@ export class ColorComponent implements OnInit, OnDestroy { changeValueInTable = () => { const theme = this.themeService.currentTheme; - this.catalogs.map((obj) => { + if(this.activeTab === 'tab1') { + this.catalogs.forEach(item => { + this.changeVal(item, theme); + }); + } else { + this.changeVal(this.catalogs, theme); + } + }; + + changeVal(val, theme) { + val.map((obj) => { const nameArr = obj.name.split('$'); if (nameArr.length === 2) { const match = theme.data[nameArr[1]]; @@ -79,145 +102,156 @@ export class ColorComponent implements OnInit, OnDestroy { } setValues(values) { + console.log('values', values); + Object.values(values.catalogsList).forEach(item => { + this.tableNameList.push(item); + }); + this.colorSource = [ - { type: 'basic', name: '$devui-global-bg', light: '#f3f6f8', dark: '#202124', description: values.colorSource['devui-global-bg'] }, { - type: 'basic', + type: 'background', + name: '$devui-global-bg', + light: '#f3f6f8', + dark: '#202124', + description: values.colorSource['devui-global-bg'] + }, + { + type: 'background', name: '$devui-global-bg-normal', light: '#ffffff', dark: '#202124', description: values.colorSource['devui-global-bg-normal'], }, { - type: 'basic', + type: 'background', name: '$devui-base-bg', light: '#ffffff', dark: '#2E2F31', description: values.colorSource['devui-global-bg-normal'], }, { - type: 'basic', + type: 'background', name: '$devui-base-bg-dark', light: '#333854', dark: '#2e2f31', description: values.colorSource['devui-base-bg-dark'], }, - { type: 'basic', name: '$devui-brand', light: '#5e7ce0', dark: '#5e7ce0', description: values.colorSource['devui-brand'] }, - { type: 'basic', name: '$devui-brand-foil', light: '#859bff', dark: '#313a61', description: values.colorSource['devui-brand-foil'] }, + { type: 'theme', name: '$devui-brand', light: '#5e7ce0', dark: '#5e7ce0', description: values.colorSource['devui-brand'] }, + { type: 'theme', name: '$devui-brand-foil', light: '#859bff', dark: '#313a61', description: values.colorSource['devui-brand-foil'] }, { - type: 'basic', + type: 'theme', name: '$devui-brand-hover', light: '#7693f5', dark: '#425288', description: values.colorSource['devui-brand-hover'], }, { - type: 'basic', + type: 'theme', name: '$devui-brand-active', light: '#526ecc', dark: '#526ecc', description: values.colorSource['devui-brand-active'], }, { - type: 'basic', + type: 'theme', name: '$devui-brand-active-focus', light: '#344899', dark: '#344899', description: values.colorSource['devui-brand-active-focus'], }, - { type: 'basic', name: '$devui-contrast', light: '#C7000B', dark: '#C7000B', description: values.colorSource['devui-contrast'] }, - { type: 'basic', name: '$devui-text', light: '#252b3a', dark: '#E8E8E8', description: values.colorSource['devui-text'] }, - { type: 'basic', name: '$devui-text-weak', light: '#575d6c', dark: '#A0A0A0', description: values.colorSource['devui-text-weak'] }, - { type: 'basic', name: '$devui-aide-text', light: '#8a8e99', dark: '#909090', description: values.colorSource['devui-aide-text'] }, + { type: 'theme', name: '$devui-contrast', light: '#C7000B', dark: '#C7000B', description: values.colorSource['devui-contrast'] }, + { type: 'text', name: '$devui-text', light: '#252b3a', dark: '#E8E8E8', description: values.colorSource['devui-text'] }, + { type: 'text', name: '$devui-text-weak', light: '#575d6c', dark: '#A0A0A0', description: values.colorSource['devui-text-weak'] }, + { type: 'text', name: '$devui-aide-text', light: '#8a8e99', dark: '#909090', description: values.colorSource['devui-aide-text'] }, { - type: 'basic', + type: 'text', name: '$devui-aide-text-stress', light: '#575d6c', dark: '#A0A0A0', description: values.colorSource['devui-aide-text-stress'], }, { - type: 'basic', + type: 'text', name: '$devui-placeholder', light: '#8a8e99', dark: '#8A8A8A', description: values.colorSource['devui-placeholder'], }, - { type: 'basic', name: '$devui-light-text', light: '#ffffff', dark: '#ffffff', description: values.colorSource['devui-light-text'] }, - { type: 'basic', name: '$devui-dark-text', light: '#252b3a', dark: '#252b3a', description: values.colorSource['devui-dark-text'] }, - { type: 'basic', name: '$devui-link', light: '#526ecc', dark: '#526ECC', description: values.colorSource['devui-link'] }, + { type: 'text', name: '$devui-light-text', light: '#ffffff', dark: '#ffffff', description: values.colorSource['devui-light-text'] }, + { type: 'text', name: '$devui-dark-text', light: '#252b3a', dark: '#252b3a', description: values.colorSource['devui-dark-text'] }, + { type: 'text', name: '$devui-link', light: '#526ecc', dark: '#526ECC', description: values.colorSource['devui-link'] }, { - type: 'basic', + type: 'text', name: '$devui-link-active', light: '#344899', dark: '#344899', description: values.colorSource['devui-link-active'], }, - { type: 'basic', name: '$devui-link-light', light: '#96adfa', dark: '#96adfa', description: values.colorSource['devui-link-light'] }, + { type: 'text', name: '$devui-link-light', light: '#96adfa', dark: '#96adfa', description: values.colorSource['devui-link-light'] }, { - type: 'basic', + type: 'text', name: '$devui-link-light-active', light: '#beccfa', dark: '#beccfa', description: values.colorSource['devui-link-light-active'], }, - { type: 'basic', name: '$devui-line', light: '#adb0b8', dark: '#505153', description: values.colorSource['devui-line'] }, + { type: 'border', name: '$devui-line', light: '#adb0b8', dark: '#505153', description: values.colorSource['devui-line'] }, { - type: 'basic', + type: 'border', name: '$devui-dividing-line', light: '#dfe1e6', dark: '#3D3E40', description: values.colorSource['devui-dividing-line'], }, - { type: 'basic', name: '$devui-block', light: '#ffffff', dark: '#606061', description: values.colorSource['devui-block'] }, - { type: 'basic', name: '$devui-area', light: '#f8f8f8', dark: '#34363A', description: values.colorSource['devui-area'] }, - { type: 'basic', name: '$devui-danger', light: '#f66f6a', dark: '#f66f6a', description: values.colorSource['devui-danger'] }, - { type: 'basic', name: '$devui-warning', light: '#fac20a', dark: '#fac20a', description: values.colorSource['devui-warning'] }, - { type: 'basic', name: '$devui-waiting', light: '#9faad7', dark: '#5e6580', description: values.colorSource['devui-waiting'] }, - { type: 'basic', name: '$devui-success', light: '#50d4ab', dark: '#50d4ab', description: values.colorSource['devui-success'] }, - { type: 'basic', name: '$devui-info', light: '#5e7ce0', dark: '#5e7ce0', description: values.colorSource['devui-info'] }, - { type: 'basic', name: '$devui-initial', light: '#e9edfa', dark: '#64676e', description: values.colorSource['devui-initial'] }, + { type: 'background', name: '$devui-block', light: '#ffffff', dark: '#606061', description: values.colorSource['devui-block'] }, + { type: 'background', name: '$devui-area', light: '#f8f8f8', dark: '#34363A', description: values.colorSource['devui-area'] }, + { type: 'status', name: '$devui-danger', light: '#f66f6a', dark: '#f66f6a', description: values.colorSource['devui-danger'] }, + { type: 'status', name: '$devui-warning', light: '#fac20a', dark: '#fac20a', description: values.colorSource['devui-warning'] }, + { type: 'status', name: '$devui-waiting', light: '#9faad7', dark: '#5e6580', description: values.colorSource['devui-waiting'] }, + { type: 'status', name: '$devui-success', light: '#50d4ab', dark: '#50d4ab', description: values.colorSource['devui-success'] }, + { type: 'status', name: '$devui-info', light: '#5e7ce0', dark: '#5e7ce0', description: values.colorSource['devui-info'] }, + { type: 'status', name: '$devui-initial', light: '#e9edfa', dark: '#64676e', description: values.colorSource['devui-initial'] }, { - type: 'basic', + type: 'status', name: '$devui-unavailable', light: '#f5f5f6', dark: '#5b5b5c', description: values.colorSource['devui-unavailable'], }, { - type: 'basic', + type: 'status', name: '$devui-shadow', light: 'rgba(0, 0, 0, 0.2)', dark: 'rgba(17, 18, 19, 0.4)', description: values.colorSource['devui-shadow'], }, { - type: 'basic', + type: 'status', name: '$devui-light-shadow', light: 'rgba(0, 0, 0, 0.1)', dark: 'rgba(17, 18, 19, 0.5)', description: values.colorSource['devui-light-shadow'], }, - { type: 'icon', name: '$devui-icon-text', light: '#252b3a', dark: '#E8E8E8', description: values.colorSource['devui-icon-text'] }, - { type: 'icon', name: '$devui-icon-bg', light: '#ffffff', dark: '#2E2F31', description: values.colorSource['devui-icon-bg'] }, - { type: 'icon', name: '$devui-icon-fill', light: '#d3d5d9', dark: '#606061', description: values.colorSource['devui-icon-fill'] }, + { type: 'text', name: '$devui-icon-text', light: '#252b3a', dark: '#E8E8E8', description: values.colorSource['devui-icon-text'] }, + { type: 'background', name: '$devui-icon-bg', light: '#ffffff', dark: '#2E2F31', description: values.colorSource['devui-icon-bg'] }, + { type: 'status', name: '$devui-icon-fill', light: '#d3d5d9', dark: '#606061', description: values.colorSource['devui-icon-fill'] }, { - type: 'icon', + type: 'status', name: '$devui-icon-fill-hover', light: '#adb5ce', dark: '#73788a', description: values.colorSource['devui-icon-fill-hover'], }, { - type: 'icon', + type: 'status', name: '$devui-icon-fill-active', light: '#5e7ce0', dark: '#5e7ce0', description: values.colorSource['devui-icon-fill-active'], }, { - type: 'icon', + type: 'status', name: '$devui-icon-fill-active-hover', light: '#526ecc', dark: '#526ecc', @@ -225,28 +259,28 @@ export class ColorComponent implements OnInit, OnDestroy { }, { - type: 'form', + type: 'border', name: '$devui-form-control-line', light: '#adb0b8', dark: '#505153', description: values.colorSource['devui-form-control-line'], }, { - type: 'form', + type: 'border', name: '$devui-form-control-line-hover', light: '#575d6c', dark: '#909090', description: values.colorSource['devui-form-control-line-hover'], }, { - type: 'form', + type: 'border', name: '$devui-form-control-line-active', light: '#5e7ce0', dark: '#5e7ce0', description: values.colorSource['devui-form-control-line-active'], }, { - type: 'form', + type: 'border', name: '$devui-form-control-line-active-hover', light: '#344899', dark: '#344899', @@ -254,49 +288,49 @@ export class ColorComponent implements OnInit, OnDestroy { }, { - type: 'list', + type: 'background', name: '$devui-list-item-active-bg', light: '#5e7ce0', dark: '#5e7ce0', description: values.colorSource['devui-list-item-active-bg'], }, { - type: 'list', + type: 'text', name: '$devui-list-item-active-text', light: '#ffffff', dark: '#ffffff', description: values.colorSource['devui-list-item-active-text'], }, { - type: 'list', + type: 'background', name: '$devui-list-item-active-hover-bg', light: '#526ecc', dark: '#526ecc', description: values.colorSource['devui-list-item-active-hover-bg'], }, { - type: 'list', + type: 'background', name: '$devui-list-item-hover-bg', light: '#f2f5fc', dark: '#383838', description: values.colorSource['$devui-list-item-hover-bg'], }, { - type: 'list', + type: 'text', name: '$devui-list-item-hover-text', light: '#526ecc', dark: '#526ecc', description: values.colorSource['devui-list-item-hover-text'], }, { - type: 'list', + type: 'background', name: '$devui-list-item-selected-bg', light: '#e9edfa', dark: '#454545', description: values.colorSource['devui-list-item-selected-bg'], }, { - type: 'list', + type: 'background', name: '$devui-list-item-strip-bg', light: '#f2f5fc', dark: '#383838', @@ -304,35 +338,35 @@ export class ColorComponent implements OnInit, OnDestroy { }, { - type: 'disable', + type: 'background', name: '$devui-disabled-bg', light: '#f5f5f6', dark: '#3D3E44', description: values.colorSource['devui-disabled-bg'], }, { - type: 'disable', + type: 'border', name: '$devui-disabled-line', light: '#dfe1e6', dark: '#505153', description: values.colorSource['devui-disabled-line'], }, { - type: 'disable', + type: 'text', name: '$devui-disabled-text', light: '#adb0b8', dark: '#7D7D7D', description: values.colorSource['devui-disabled-text'], }, { - type: 'disable', + type: 'text', name: 'devui-primary-disabled', light: '#beccfa', dark: '#2b3458', description: values.colorSource['devui-primary-disabled'], }, { - type: 'disable', + type: 'status', name: 'devui-icon-fill-active-disabled', light: '#beccfa', dark: '#2b3458', @@ -340,107 +374,107 @@ export class ColorComponent implements OnInit, OnDestroy { }, { - type: 'specialBackground', + type: 'background', name: '$devui-label-bg', light: '#eef0f5', dark: '#46443F', description: values.colorSource['devui-label-bg'], }, { - type: 'specialBackground', + type: 'background', name: '$devui-connected-overlay-bg', light: '#ffffff', dark: '#2F2F2F', description: values.colorSource['devui-connected-overlay-bg'], }, { - type: 'specialBackground', + type: 'border', name: '$devui-connected-overlay-line', light: '#526ecc', dark: '#526ecc', description: values.colorSource['devui-connected-overlay-line'], }, { - type: 'specialBackground', + type: 'background', name: '$devui-fullscreen-overlay-bg', light: '#ffffff', dark: '#2E2F31', description: values.colorSource['devui-fullscreen-overlay-bg'], }, { - type: 'specialBackground', + type: 'background', name: '$devui-feedback-overlay-bg', light: '#464d6e', dark: '#4C4C4C', description: values.colorSource['devui-feedback-overlay-bg'], }, { - type: 'specialBackground', + type: 'text', name: '$devui-feedback-overlay-text', light: '#dfe1e6', dark: '#DFE1E6', description: values.colorSource['devui-feedback-overlay-text'], }, { - type: 'specialBackground', + type: 'background', name: '$devui-embed-search-bg', light: '#f2f5fc', dark: '#383838', description: values.colorSource['devui-embed-search-bg'], }, { - type: 'specialBackground', + type: 'background', name: '$devui-embed-search-bg-hover', light: '#eef0f5', dark: '#3D3E40', description: values.colorSource['devui-embed-search-bg-hover'], }, { - type: 'specialBackground', + type: 'background', name: '$devui-float-block-shadow', light: 'rgba(94, 124, 224, 0.3)', dark: 'rgba(94, 124, 224, 0.3)', description: values.colorSource['devui-float-block-shadow'], }, { - type: 'specialBackground', + type: 'background', name: '$devui-highlight-overlay', light: 'rgba(255, 255, 255, 0.8)', dark: 'rgba(255, 255, 255, 0.1)', description: values.colorSource['devui-highlight-overlay'], }, { - type: 'specialBackground', + type: 'background', name: '$devui-range-item-hover-bg', light: '#e9edfa', dark: '#454545', description: values.colorSource['devui-range-item-hover-bg'], }, - { type: 'button', name: '$devui-primary', light: '#5e7ce0', dark: '#5e7ce0', description: values.colorSource['devui-primary'] }, + { type: 'status', name: '$devui-primary', light: '#5e7ce0', dark: '#5e7ce0', description: values.colorSource['devui-primary'] }, { - type: 'button', + type: 'status', name: '$devui-primary-hover', light: '#7693f5', dark: '#425288', description: values.colorSource['devui-primary-hover'], }, { - type: 'button', + type: 'status', name: '$devui-primary-active', light: '#344899', dark: '#344899', description: values.colorSource['devui-primary-active'], }, { - type: 'button', + type: 'status', name: '$devui-contrast-hover', light: '#D64A52', dark: '#D64A52', description: values.colorSource['devui-contrast-hover'], }, { - type: 'button', + type: 'status', name: '$devui-contrast-active', light: '#B12220', dark: '#B12220', @@ -491,15 +525,12 @@ export class ColorComponent implements OnInit, OnDestroy { { type: 'status', name: '$devui-default-bg', light: '#f3f6f8', dark: '#383838', description: values.colorSource['devui-default-bg'] }, ]; - this.catalogs = [ - { name: values.catalogs.basic, type: 'basic', expand: true }, - { name: values.catalogs.icon, type: 'icon', expand: true }, - { name: values.catalogs.form, type: 'form', expand: true }, - { name: values.catalogs.list, type: 'list', expand: true }, - { name: values.catalogs.disable, type: 'disable', expand: true }, - { name: values.catalogs.specialBackground, type: 'specialBackground', expand: true }, - { name: values.catalogs.button, type: 'button', expand: true }, - { name: values.catalogs.status, type: 'status', expand: true }, + this.catalogsList = [ + { name: values.catalogsList.theme, type: 'theme', expand: true }, + { name: values.catalogsList.text, type: 'text', expand: true }, + { name: values.catalogsList.border, type: 'border', expand: true }, + { name: values.catalogsList.background, type: 'background', expand: true }, + { name: values.catalogsList.status, type: 'status', expand: true }, ]; this.colors = [ @@ -756,17 +787,31 @@ export class ColorComponent implements OnInit, OnDestroy { }, ]; + this.colorList = [ + ['#f2f5fc', '#e9edfa', '#beccfa', '#96adfa', '#7693f5', '#5e7ce0', '#526ecc', '#465eb8', '#3c51a6', '#344899', '#2a3c85'], + ['#ebf6ff', '#d1ebff', '#b8e0ff', '#9ed5ff', '#85caff', '#6cbfff', '#4ea6e6', '#3590cc', '#207ab3', '#0f6999', '#035880'], + ['#edfff9', '#cffcee', '#acf2dc', '#8be8cb', '#6ddebb', '#50d4ab', '#3ac295', '#27b080', '#169e6c', '#088c58', '#007a45'], + ['#f0ffe6', '#e5ffd4', '#d8fcc0', '#c5f2a7', '#b3e890', '#a6dd82', '#92cc68', '#7eba50', '#6ca83b', '#5e9629', '#518519'], + ['#fffbf0', '#fff1c2', '#ffe794', '#ffdc66', '#ffd138', '#fac20a', '#e3aa00', '#cc9600', '#b58200', '#9e6f00', '#875c00'], + ['#fff3e8', '#ffe1c7', '#ffd0a6', '#ffbf85', '#ffad63', '#fa9841', '#e37d29', '#cc6414', '#b54e04', '#9e3f00', '#873400'], + ['#ffeeed', '#ffd5d4', '#ffbcba', '#ffa4a1', '#ff8b87', '#f66f6a', '#de504e', '#c73636', '#b02121', '#991111', '#820404'], + ['#ffedf3', '#ffd4e3', '#ffbad2', '#ffa1c2', '#fc86b0', '#f3689a', '#db4d83', '#c4356e', '#ad215b', '#96114d', '#800440'], + ['#f5f0ff', '#e7d9ff', '#d8c2ff', '#caabff', '#bc94ff', '#a97af8', '#8a5ce0', '#6f42c9', '#572db3', '#3f1a9c', '#2a0c85'], + ]; + this.setDataList(); } setDataList() { const currentDataList = this.activeTab === 'tab1' ? 'colorSource' : 'colors'; const result = []; - this.catalogs.forEach((catalog, catalogIndex) => { - result.push(catalog); - if (catalog.expand && !this.catalogs[catalogIndex + 1]?.hasOwnProperty('description')) { + this.catalogsList.forEach((catalog, catalogIndex) => { + if (catalog.expand && !Object.prototype.hasOwnProperty.call( + this.catalogsList[catalogIndex + 1] || {}, 'description')) { const insertItems = this[currentDataList].filter((color) => color.type === catalog.type); - result.push(...insertItems); + this[`${insertItems[0].type}ColorSource`].push(...insertItems); + this.tableList.push(this[`${insertItems[0].type}ColorSource`]); + result.push(this[`${insertItems[0].type}ColorSource`]); } }); this.catalogs = result; diff --git a/devui/design-token/font/demo/font/font.component.html b/devui/design-token/font/demo/font/font.component.html index 4f65d045..29dcf21a 100644 --- a/devui/design-token/font/demo/font/font.component.html +++ b/devui/design-token/font/demo/font/font.component.html @@ -9,57 +9,49 @@

    {{ 'components.design-font.fontDemo.instance.title' |

    {{ 'components.design-font.fontDemo.instance.tableTitle' | translate }}

    - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + diff --git a/devui/design-token/shadow/demo/shadow/shadow.component.html b/devui/design-token/shadow/demo/shadow/shadow.component.html index 02e00ccc..7e6dc8fe 100644 --- a/devui/design-token/shadow/demo/shadow/shadow.component.html +++ b/devui/design-token/shadow/demo/shadow/shadow.component.html @@ -1,63 +1,99 @@

    {{ 'components.design-shadow.shadowDemo.instance.title' | translate }}

    +box-shadow: $devui-shadow-length-base $devui-shadow;

    {{ 'components.design-shadow.shadowDemo.instance.description' | translate }}

    - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + +

    {{ 'components.design-shadow.shadowDemo.instance.description2' | translate }}

    + +
    + + + + + + + + + + + + + + + + + + + + diff --git a/devui/design-token/shadow/demo/shadow/shadow.component.scss b/devui/design-token/shadow/demo/shadow/shadow.component.scss index f2323914..c7710a10 100644 --- a/devui/design-token/shadow/demo/shadow/shadow.component.scss +++ b/devui/design-token/shadow/demo/shadow/shadow.component.scss @@ -5,3 +5,22 @@ width: 100px; box-shadow: $devui-shadow-length-fullscreen-overlay $devui-light-shadow; } + +code { + display: block; + margin: 20px 0; +} + +.color-name { + display: inline-block; + width: 120px; + vertical-align: middle; +} + +.color-cube { + height: 20px; + width: 20px; + display: inline-block; + vertical-align: middle; + box-shadow: $devui-shadow-length-base $devui-light-shadow; +} diff --git a/devui/design-token/shadow/demo/shadow/shadow.component.ts b/devui/design-token/shadow/demo/shadow/shadow.component.ts index d73b9ed5..b3b9871e 100644 --- a/devui/design-token/shadow/demo/shadow/shadow.component.ts +++ b/devui/design-token/shadow/demo/shadow/shadow.component.ts @@ -14,6 +14,7 @@ export class ShadowComponent implements OnInit, OnDestroy { subs: Subscription = new Subscription(); shadows = []; oldShadows = []; + shadowColor = []; activeTab: string | number = 'curShadow'; @@ -30,8 +31,13 @@ export class ShadowComponent implements OnInit, OnDestroy { } changeValueInTable = () => { + this.changeValue('shadows'); + this.changeValue('shadowColor'); + }; + + changeValue(type) { const theme = this.themeService.currentTheme; - this.shadows.map((obj) => { + this[type].map((obj) => { const nameArr = obj.name.split('$'); if (nameArr.length === 2) { const match = theme.data[nameArr[1]]; @@ -42,8 +48,8 @@ export class ShadowComponent implements OnInit, OnDestroy { } } }); - this.shadows = cloneDeep(this.shadows); - }; + this[type] = cloneDeep(this[type]); + } setI18n() { this.subs.add( @@ -164,6 +170,21 @@ export class ShadowComponent implements OnInit, OnDestroy { }, ]; + this.shadowColor = [ + { + name: '$devui-shadow', + light: 'rgba(0, 0, 0, 0.2)', + dark: 'rgba(17, 18, 19, 0.4)', + description: values.shadowColor['devui-shadow'], + }, + { + name: '$devui-light-shadow', + light: 'rgba(0, 0, 0, 0.1)', + dark: 'rgba(17, 18, 19, 0.5)', + description: values.shadowColor['devui-light-shadow'], + }, + ]; + if (this.themeService) { this.changeValueInTable(); } diff --git a/devui/design-token/z-index/demo/design-z-index-demo.component.html b/devui/design-token/z-index/demo/design-z-index-demo.component.html new file mode 100644 index 00000000..82aa956d --- /dev/null +++ b/devui/design-token/z-index/demo/design-z-index-demo.component.html @@ -0,0 +1,30 @@ +
    + +
    +
    {{ 'components.design-z-index.ZIndexDemo.title' | translate }}
    +
    + {{ 'components.design-z-index.ZIndexDemo.description1' | translate }}
    + {{ 'components.design-z-index.ZIndexDemo.description2' | translate }}
    + {{ 'components.design-z-index.ZIndexDemo.description3' | translate }}
    + {{ 'components.design-z-index.ZIndexDemo.description4' | translate }}
    + {{ 'components.design-z-index.ZIndexDemo.description5' | translate }}
    + {{ 'components.design-z-index.ZIndexDemo.description6' | translate }} +
    + +
    {{ 'components.design-z-index.ZIndexDemo.title2' | translate }}
    +
    {{ 'components.design-z-index.ZIndexDemo.description7' | translate }}
    +

    {{ 'components.design-z-index.ZIndexDemo.subTitle1' | translate }}

    +
    + {{ 'components.design-z-index.ZIndexDemo.description8' | translate }}
    + {{ 'components.design-z-index.ZIndexDemo.description9' | translate }} +
    +

    {{ 'components.design-z-index.ZIndexDemo.subTitle2' | translate }}

    +
    + {{ 'components.design-z-index.ZIndexDemo.description10' | translate }} +
    +

    {{ 'components.design-z-index.ZIndexDemo.subTitle3' | translate }}

    +
    + {{ 'components.design-z-index.ZIndexDemo.description11' | translate }} +
    +
    +
    diff --git a/devui/design-token/z-index/demo/design-z-index-demo.component.ts b/devui/design-token/z-index/demo/design-z-index-demo.component.ts new file mode 100644 index 00000000..44ba00d9 --- /dev/null +++ b/devui/design-token/z-index/demo/design-z-index-demo.component.ts @@ -0,0 +1,46 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { TranslateService, TranslationChangeEvent } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'd-design-z-index-demo', + templateUrl: './design-z-index-demo.component.html', + styles: [` + .devui-demo-title { + margin-top: 20px + } + `] +}) +export class DesignZIndexDemoComponent implements OnInit, OnDestroy { + navItems = []; + subs: Subscription = new Subscription(); + constructor(private translate: TranslateService) {} + + ngOnInit() { + this.subs.add( + this.translate.get('components.design-z-index.anchorLinkValues').subscribe((res) => { + this.setNavValues(res); + }) + ); + + this.subs.add( + this.translate.onLangChange.subscribe((event: TranslationChangeEvent) => { + const values = this.translate.instant('components.design-z-index.anchorLinkValues'); + this.setNavValues(values); + }) + ); + } + + setNavValues(values) { + this.navItems = [ + { dAnchorLink: 'z-index', value: values['z-index'] } + ]; + } + + ngOnDestroy() { + if (this.subs) { + this.subs.unsubscribe(); + } + } + +} diff --git a/devui/design-token/z-index/demo/design-z-index-demo.module.ts b/devui/design-token/z-index/demo/design-z-index-demo.module.ts new file mode 100644 index 00000000..a50b4892 --- /dev/null +++ b/devui/design-token/z-index/demo/design-z-index-demo.module.ts @@ -0,0 +1,33 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { DataTableModule } from 'ng-devui/data-table'; +import { DevUIApiComponent } from 'ng-devui/shared/devui-api/devui-api.component'; +import { DevUIApiModule } from 'ng-devui/shared/devui-api/devui-api.module'; +import { DevUICodeboxModule } from 'ng-devui/shared/devui-codebox'; +import { TabsModule } from 'ng-devui/tabs'; +import { TranslateModule } from '@ngx-translate/core'; +import { DDemoNavModule } from 'src/app/component/d-demo-nav.module'; +import { DesignZIndexDemoComponent } from './design-z-index-demo.component'; +import { ZIndexComponent } from './z-index/z-index.component'; +@NgModule({ + declarations: [DesignZIndexDemoComponent, ZIndexComponent], + imports: [ + TranslateModule, + CommonModule, + DevUIApiModule, + DevUICodeboxModule, + DataTableModule, + DDemoNavModule, + TabsModule, + RouterModule.forChild([ + { path: '', redirectTo: 'demo' }, + { path: 'demo', component: DesignZIndexDemoComponent}, + { path: 'api', component: DevUIApiComponent, data: { + 'zh-cn': require('!html-loader!markdown-loader!../doc/api-cn.md'), + 'en-us': require('!html-loader!markdown-loader!../doc/api-en.md') + }} + ]) + ] +}) +export class DesignZIndexDemoModule { } diff --git a/devui/design-token/z-index/demo/z-index/z-index.component.html b/devui/design-token/z-index/demo/z-index/z-index.component.html new file mode 100644 index 00000000..d7c7c6e3 --- /dev/null +++ b/devui/design-token/z-index/demo/z-index/z-index.component.html @@ -0,0 +1,16 @@ +

    {{ 'components.design-z-index.ZIndexDemo.instance.tableTitle' | translate }}

    + + + + + + + diff --git a/devui/design-token/z-index/demo/z-index/z-index.component.ts b/devui/design-token/z-index/demo/z-index/z-index.component.ts new file mode 100644 index 00000000..2310cf46 --- /dev/null +++ b/devui/design-token/z-index/demo/z-index/z-index.component.ts @@ -0,0 +1,54 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { ThemeService } from 'ng-devui/theme'; +import { TranslateService, TranslationChangeEvent } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'd-z-index', + templateUrl: './z-index.component.html', +}) +export class ZIndexComponent implements OnInit, OnDestroy { + themeService: ThemeService; + subs: Subscription = new Subscription(); + zIndex = []; + + constructor(private translate: TranslateService) { } + + ngOnInit() { + if (typeof window !== undefined) { + this.setI18n(); + } + } + + setI18n() { + this.subs.add( + this.translate.get('components.design-z-index.ZIndexDemo.instance').subscribe((res) => { + this.setValues(res); + }) + ); + + this.subs.add( + this.translate.onLangChange.subscribe((event: TranslationChangeEvent) => { + const values = this.translate.instant('components.design-z-index.ZIndexDemo.instance'); + this.setValues(values); + }) + ); + } + + setValues(values) { + this.zIndex = [ + { name: '$devui-z-index-full-page-overlay', value: '1080', description: values.zIndex['devui-z-index-full-page-overlay'] }, + { name: '$devui-z-index-pop-up', value: '1060', description: values.zIndex['devui-z-index-pop-up'] }, + { name: '$devui-z-index-dropdown', value: '1052', description: values.zIndex['devui-z-index-dropdown'] }, + { name: '$devui-z-index-modal', value: '1050', description: values.zIndex['devui-z-index-modal'] }, + { name: '$devui-z-index-drawer', value: '1040', description: values.zIndex['devui-z-index-drawer'] }, + { name: '$devui-z-index-framework', value: '1000', description: values.zIndex['devui-z-index-framework'] }, + ]; + } + + ngOnDestroy() { + if (this.subs) { + this.subs.unsubscribe(); + } + } +} diff --git a/devui/design-token/z-index/doc/api-cn.md b/devui/design-token/z-index/doc/api-cn.md new file mode 100644 index 00000000..b6d572fb --- /dev/null +++ b/devui/design-token/z-index/doc/api-cn.md @@ -0,0 +1 @@ +具体使用方式参考demo及描述信息 \ No newline at end of file diff --git a/devui/design-token/z-index/doc/api-en.md b/devui/design-token/z-index/doc/api-en.md new file mode 100644 index 00000000..49bd13e8 --- /dev/null +++ b/devui/design-token/z-index/doc/api-en.md @@ -0,0 +1 @@ +For details, please see the demo and description. \ No newline at end of file diff --git a/devui/dragdrop/demo/batch-drag/batch-drag.component.ts b/devui/dragdrop/demo/batch-drag/batch-drag.component.ts index bda614c0..5a0b086f 100644 --- a/devui/dragdrop/demo/batch-drag/batch-drag.component.ts +++ b/devui/dragdrop/demo/batch-drag/batch-drag.component.ts @@ -14,7 +14,7 @@ export class BatchDragComponent { { name: 'WebStorm', isSelected: false }, { name: 'Sublime Text', isSelected: false }, { name: 'Atom', isSelected: false }, - { name: 'Notepad++', isSelected: false }, + { name: 'Notepad++', isSelected: false } ], }, { @@ -35,7 +35,7 @@ export class BatchDragComponent { { name: 'Windows', isSelected: false }, { name: 'Mac OS', isSelected: false }, { name: 'DOS', isSelected: false }, - { name: 'Chrome OS', isSelected: false }, + { name: 'Chrome OS', isSelected: false } ], }, { @@ -44,7 +44,7 @@ export class BatchDragComponent { { name: 'Android', isSelected: false }, { name: 'IOS', isSelected: false }, { name: 'BlackBerry', isSelected: false }, - { name: 'Symbian', isSelected: false }, + { name: 'Symbian', isSelected: false } ], }, { @@ -116,10 +116,6 @@ export class BatchDragComponent { } cleanBatch() { - this.lists.forEach((list) => - list.list.forEach((item) => { - item['isSelected'] = false; - }) - ); + this.lists.forEach((list) => list.list.forEach((item) => {item['isSelected'] = false;})); } } diff --git a/devui/dragdrop/doc/api-cn.md b/devui/dragdrop/doc/api-cn.md index 4b5074aa..875bfd16 100644 --- a/devui/dragdrop/doc/api-cn.md +++ b/devui/dragdrop/doc/api-cn.md @@ -23,8 +23,8 @@ import { DragDropModule } from 'ng-devui/dragdrop'; | dragHandleClass | `string` | 'drag-handle' | 可选, 会给可拖动内容的应用的 css 选择器命中的元素添加的 css 类名, 第一个匹配 css 选择器的会被加上该 css 类 | [基本用法](demo#basic-usage) | | disabled | `boolean` | false | 可选,控制当前元素是否可拖动 false 为可以,true 为不可以 | [基本用法](demo#basic-usage) | | enableDragFollow | `boolean` | false | 可选,是否启用实体元素跟随(可以添加更多特效,如阴影等) | [拖拽实体元素跟随](demo#drag-entity-elements-to-follow) | -| dragFollowOption | `{appendToBody?: boolean}` | -- | 可选,用于控制实体拖拽的一些配置 | [拖拽实体元素跟随](demo#drag-entity-elements-to-follow) | -| dragFollowOption.appendToBody | `boolean` | false | 可选,用于控制实体拖拽的克隆元素插入的位置。默认 false 会插入到源元素父元素所有子的最后,设置为 true 会附着到。见说明 1 | [拖拽实体元素跟随](demo#drag-entity-elements-to-follow) | +| dragFollowOptions | `{appendToBody?: boolean}` | -- | 可选,用于控制实体拖拽的一些配置 | [拖拽实体元素跟随](demo#drag-entity-elements-to-follow) | +| dragFollowOptions.appendToBody | `boolean` | false | 可选,用于控制实体拖拽的克隆元素插入的位置。默认 false 会插入到源元素父元素所有子的最后,设置为 true 会附着到。见说明 1 | [拖拽实体元素跟随](demo#drag-entity-elements-to-follow) | | originPlaceholder | `{show?: boolean; tag?: string; style?: {cssProperties: string]: string}; text?: string; removeDelay?: number;}` | -- | 可选,设置源占位符号,用于被拖拽元素原始位置占位 | [源占位符](demo#source-placeholder) | | originPlaceholder.show | `boolean` | true | 可选,是否显示,默认 originPlaceholder 有 Input 则显示,特殊情况可以关闭 | | originPlaceholder.tag | `string` | 'div' | 可选,使用 tag 名,默认 originPlaceholder 使用'div',特殊情况可以置换 | @@ -85,6 +85,8 @@ Drag DOM Events 详情: [DragEvent](https://developer.mozilla.org/en-US/docs/Web | defaultDropPosition | `'closest' \| 'before' \| 'after'` | 'closest' | 可选,设置拖拽到可放置区域但不在列表区域的放置位置,`'closest'` 为就近放下, `'before'`为加到列表头部, `'after'`为加到列表尾部 | [外部放置位置](demo#external-location) | | dropSortCountSelector | `string` | -- | 可选,带有 sortable 的容器的情况下排序,计数的内容的选择器名称,可以用于过滤掉不应该被计数的元素 | | dropSortVirtualScrollOption | `{totalLength?: number; startIndex?: number;}` | -- | 可选,用于虚拟滚动列表中返回正确的 dropIndex 需要接收 totalLength 为列表的真实总长度, startIndex 为当前排序区域显示的第一个 dom 的在列表内的 index 值 | +| switchWhileCrossEdge | `boolean` | false | 可选,是否启用越过立即交换位置的算法, 不能与allowDropOnItem一起用,allowDropOnItem为true时,此规则无效 | +| placeholderTag | `string` | 'div' | 可选,占位显示的元素标签 | ### dDroppable 事件 diff --git a/devui/dragdrop/doc/api-en.md b/devui/dragdrop/doc/api-en.md index e21000d7..0b202c83 100644 --- a/devui/dragdrop/doc/api-en.md +++ b/devui/dragdrop/doc/api-en.md @@ -23,8 +23,8 @@ Provides the dDraggable and dDroppable(dSortable) instructions. | dragHandleClass | `string` | 'drag-handle' | CSS class name added to the element hit by the CSS selector of the application of dragable content. The CSS class is added to the first matching CSS selector. | [Basic Usage](demo#basic-usage) | | | disabled | `boolean` | false | Optional. Specifies whether the current element can be dragged. false: yes; true: no. | [Basic Usage](demo#basic-usage) | | enableDragFollow | `boolean` | false | Optional. Whether to enable entity element follow (more special effects such as shadow can be added) | [Drag Entity Element to Follow](demo#drag-entity-elements-to-follow) | -| dragFollowOption | `{appendToBody?: boolean}` | -- | Optional. It is used to control some configuration of entity dragging. | [Drag Entity Element to Follow](demo#drag-entity-elements-to-follow) | -| dragFollowOption.appendToBody | `boolean` | false | Optional. controls the position of the clone element to be inserted in entity dragging. The default value false is inserted at the end of all children of the source element's parent element, and the value true is attached to. See Note 1 | [Drag Entity Element to Follow](demo#drag-entity-elements-to-follow) | +| dragFollowOptions | `{appendToBody?: boolean}` | -- | Optional. It is used to control some configuration of entity dragging. | [Drag Entity Element to Follow](demo#drag-entity-elements-to-follow) | +| dragFollowOptions.appendToBody | `boolean` | false | Optional. controls the position of the clone element to be inserted in entity dragging. The default value false is inserted at the end of all children of the source element's parent element, and the value true is attached to. See Note 1 | [Drag Entity Element to Follow](demo#drag-entity-elements-to-follow) | | originPlaceholder | `{show?: boolean; tag?: string; style?: {cssProperties: string]: string}; text?: string; removeDelay?: number;}` | -- | Optional. Sets the Source Placeholder for the original position of the dragged element. | [Source Placeholder](demo#source-placeholder) | | originPlaceholder.show | `boolean` | true | Optional. It indicates whether to display the Source Placeholder. By default, the Source Placeholder is displayed if there is an input. You can disable the Source Placeholder in special cases. | | originPlaceholder.tag | `string` | 'div' | Optional. Whether to display originPlaceholder. By default, originPlaceholder is displayed if there is an input. This parameter can be disabled in special cases. | @@ -85,6 +85,8 @@ Note 2: The default value of `batchDragLastOneAutoActiveEventKeys` is ['ctrlKey' | defaultDropPosition | `'closest' \| 'before' \| 'after'` | `'closest'` | Optional. Sets the position where a device can be dragged to a place that is not in the list area, `closest'` indicates the nearest place, `before'` indicates the place to be added to the list header, and `after'` indicates the place to be added to the list tail. | [External Placement Position](demo#external-location) | | dropSortCountSelector | `string` | -- | Optional. This parameter specifies the name of the selector for counting content in the case of sortable containers. It can be used to filter out elements that should not be counted. | | dropSortVirtualScrollOption | `{totalLength?: number; startIndex?: number;}` | -- | Optional. It is used to return a correct dropIndex in the virtual scrolling list. The value of totalLength is the actual total length of the list, and the value of startIndex is the index value of the first dom displayed in the current sorting area in the list. | +| switchWhileCrossEdge | `boolean` | false | Optional. Indicates whether to enable the algorithm for overriding immediate location swap. This rule cannot be used together with allowDropOnItem. This rule is invalid when allowDropOnItem is set to true. | +| placeholderTag | `string` | 'div' | Optional. Element Labels for Placeholder Display. | ### dDroppable Event diff --git a/devui/dragdrop/shared/utils.ts b/devui/dragdrop/shared/utils.ts index 58197b51..cbbb2d26 100755 --- a/devui/dragdrop/shared/utils.ts +++ b/devui/dragdrop/shared/utils.ts @@ -98,7 +98,7 @@ export class Utils { public static addElStyles(el: any, styles: any) { if (styles instanceof Object) { for (const s in styles) { - if (styles.hasOwnProperty(s)) { + if (Object.prototype.hasOwnProperty.call(styles, s)) { if (Array.isArray(styles[s])) { // 用于支持兼容渐退 styles[s].forEach(val => { diff --git a/devui/dragdrop/touch-support/dragdrop-touch.ts b/devui/dragdrop/touch-support/dragdrop-touch.ts index e7281ded..d87bb4ab 100644 --- a/devui/dragdrop/touch-support/dragdrop-touch.ts +++ b/devui/dragdrop/touch-support/dragdrop-touch.ts @@ -1,6 +1,5 @@ /** * 2020.03.23-Modified from https://github.com/Bernardo-Castilho/dragdroptouch, license: MIT,reason:Converting .js file to .ts file - * Huawei Technologies Co.,Ltd. */ export class DragDropTouch { static readonly THRESHOLD = 5; // pixels to move before drag starts @@ -220,7 +219,6 @@ export class DragDropTouch { if (!this.img) { this.dragSource = null; // browser will dispatch click event after trigger touchend, since touchstart didn't preventDefault - // this._dispatchEvent(this._lastTouch, 'click', e.target); this.lastClick = Date.now(); } // finish dragging diff --git a/devui/drawer/doc/api-cn.md b/devui/drawer/doc/api-cn.md index 7fffbb40..d4faa83b 100644 --- a/devui/drawer/doc/api-cn.md +++ b/devui/drawer/doc/api-cn.md @@ -62,6 +62,7 @@ openDrawer() { | position | `string` | 'right' | 可选,抽屉板出现的位置,'left'或者'right' | [基本用法](demo#basic-usage) | | bodyScrollable | `boolean` | true | 可选,drawer 打开后,body 是否可滚动,默认为可滚动,false 时隐藏滚动,隐藏滚动条可能会产生抖动,可以通过设置外层 fixed 来同时避免滚动与抖动,可参考 modal 的解决方案 | [解决抖动滚动问题](demo#template-fixed) | | showAnimation | `boolean` | true | 可选,是否开启动效 | +| id | `string` | -- | 可选,窗口的id | ## IDrawerOpenResult 参数 diff --git a/devui/drawer/doc/api-en.md b/devui/drawer/doc/api-en.md index 3214fdcb..dc4e4821 100644 --- a/devui/drawer/doc/api-en.md +++ b/devui/drawer/doc/api-en.md @@ -59,6 +59,7 @@ Note: Components passed to drawerContentComponent in the API need to be register | position | `string` | 'right' | Optional. The value can be left or right. | [Basic Usage](demo#basic-usage) | | bodyScrollable | `boolean` | true | Optional. Whether the body can be scrolled when the drawer opens. The default value is false. If the scroll bar is hidden, the scroll bar may jitter. You need to resolve the problem in the page layout. |s | showAnimation | `boolean` | true | optional. Whether to enable animation. | +| id | `string` | -- | Optional. Id of the drawer. | ## IDrawerOpenResult Parameter diff --git a/devui/drawer/drawer.component.scss b/devui/drawer/drawer.component.scss index 0a982c1b..e1a8b151 100755 --- a/devui/drawer/drawer.component.scss +++ b/devui/drawer/drawer.component.scss @@ -1,6 +1,4 @@ @import '../style/theme/color'; -@import '../style/theme/variables'; -@import '../style/mixins/index'; @import '../style/theme/shadow'; @import '../style/theme/corner'; @import '../style/theme/z-index'; diff --git a/devui/drawer/drawer.component.ts b/devui/drawer/drawer.component.ts index f223d0bc..b085426d 100755 --- a/devui/drawer/drawer.component.ts +++ b/devui/drawer/drawer.component.ts @@ -33,9 +33,9 @@ export class DrawerComponent implements OnInit, OnDestroy { @Input() width = '300px'; @Input() zIndex: number; @Input() isCover = true; - /* - @deprecated - */ + /** + * @deprecated + */ @Input() fullScreen = false; @Input() showAnimation = true; @ViewChild(DrawerContentDirective, { static: true }) drawerContentHost: DrawerContentDirective; @@ -45,7 +45,7 @@ export class DrawerComponent implements OnInit, OnDestroy { @Input() clickDoms: any = []; // Will overwrite by drawer service @Input() afterOpened: Function; - @Input() position: 'right' | 'left' = 'left'; + @Input() position: 'right' | 'left' = 'right'; @Input() bodyScrollable = true; // drawer打开body是否可滚动 @ViewChild('drawerContainer', { static: true }) drawerContainer: ElementRef; _width: string; diff --git a/devui/dropdown/doc/api-cn.md b/devui/dropdown/doc/api-cn.md index 03142ba1..9be51cb5 100644 --- a/devui/dropdown/doc/api-cn.md +++ b/devui/dropdown/doc/api-cn.md @@ -12,14 +12,14 @@ import { DropDownModule } from ' ng-devui/dropdown'; ### dDropDown 参数 -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo |全局配置项| -| :----------------: | :-------------------: | :----------------------------: | :-----: | :-------------------------------------------------------------------------------------------------------------: | ------------------------------------------------------ | -| isOpen | `boolean` | false | 可选,可以显示指定 dropdown 是否打开 | [设置 isOpen 控制下拉](demo#dropdown-set-is-open) | +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :-------------------: | :----------------------------: | :-----: | :-------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------: | ---------- | +| isOpen | `boolean` | false | 可选,可以显示指定 dropdown 是否打开 | [设置 isOpen 控制下拉](demo#dropdown-set-is-open) | | disabled | `boolean` | false | 可选,设置为 true 禁用 dropdown | -| trigger | `'click'\|'hover'\|'manually'` | 'click' | 可选,dropdown 触发方式, click 为点击,hover 为悬停(也包含点击)、manually 为完全手动控制 | [悬浮下拉](demo#suspension-drop-down) | +| trigger | `'click'\|'hover'\|'manually'` | 'click' | 可选,dropdown 触发方式, click 为点击,hover 为悬停(也包含点击)、manually 为完全手动控制 | [悬浮下拉](demo#suspension-drop-down) | | closeScope | `'all'\|'blank'\|'none'` | 'all' | 可选,点击关闭区域,blank 点击非菜单空白才关闭, all 点击菜单内外都关闭,none 菜单内外均不关闭仅下拉按键可以关闭 | [关闭触发点设置](demo#turn-off-trigger-point-settings) | -| closeOnMouseLeaveMenu | `boolean` | false | 可选,是否进入菜单后离开菜单的时候关闭菜单 | [多级下拉菜单](demo#multi-level-drop-down-menu) | -| showAnimation | `boolean` | true | 可选,是否开启动画 | | ✔ | +| closeOnMouseLeaveMenu | `boolean` | false | 可选,是否进入菜单后离开菜单的时候关闭菜单 | [多级下拉菜单](demo#multi-level-drop-down-menu) | +| showAnimation | `boolean` | true | 可选,是否开启动画 | | ✔ | ### dDropDown 事件 @@ -43,12 +43,12 @@ npm install @angular/cdk --save ``` ```TypeScript -import { ScrollDispatchModule } from '@angular/cdk/scrolling'; +import { ScrollingModule } from '@angular/cdk/scrolling'; @NgModule({ imports: [ // ... - ScrollDispatchModule, + ScrollingModule, // ... ] }) diff --git a/devui/dropdown/doc/api-en.md b/devui/dropdown/doc/api-en.md index 00b29c91..6c0f9e77 100644 --- a/devui/dropdown/doc/api-en.md +++ b/devui/dropdown/doc/api-en.md @@ -12,14 +12,14 @@ import { DropDownModule } from ' ng-devui/dropdown'; ### dDropDown Parameter -| Parameter | Type | Default | Description | Jump to Demo |Global Config| -| :----------------: | :-------------------: | :---------------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------------------------- | -| isOpen | `boolean` | false | Optional. It indicates whether dropdown is enabled. | [Control dropdown meanu with isOpen](demo#dropdown-set-is-open) | +| Parameter | Type | Default | Description | Jump to Demo | Global Config | +| :-------------------: | :---------------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------: | ------------- | +| isOpen | `boolean` | false | Optional. It indicates whether dropdown is enabled. | [Control dropdown meanu with isOpen](demo#dropdown-set-is-open) | | disabled | `boolean` | false | Optional. Set this parameter to true to disable dropdown. | -| trigger | `click'\|'hover'\|'manually'` | 'click' | Optional. Dropdown trigger mode. Click indicates click, hover indicates hover (including click), and manually indicates manual control. | [Hover dropdown](demo#suspension-drop-down) | +| trigger | `click'\|'hover'\|'manually'` | 'click' | Optional. Dropdown trigger mode. Click indicates click, hover indicates hover (including click), and manually indicates manual control. | [Hover dropdown](demo#suspension-drop-down) | | closeScope | `'all'\|'blank'\|'none'` | 'all' | Optional. Click the blank area to close the blank area. Click all to close the blank area, the none menu can be closed either inside or outside. Only the drop-down button can be closed. | [Close Trigger Point Settings](demo#turn-off-trigger-point-settings) | -| closeOnMouseLeaveMenu | `boolean` | false | Optional. Whether to close the menu when you exit the menu after entering the menu | [Multi-level drop-down menu](demo#multi-level-drop-down-menu) | -| showAnimation | `boolean` | true | optional. Whether to enable animation. | | ✔ | +| closeOnMouseLeaveMenu | `boolean` | false | Optional. Whether to close the menu when you exit the menu after entering the menu | [Multi-level drop-down menu](demo#multi-level-drop-down-menu) | +| showAnimation | `boolean` | true | optional. Whether to enable animation. | | ✔ | ### dDropDown Event @@ -43,13 +43,14 @@ npm install @angular/cdk --save ``` ```TypeScript -import {ScrollDispatchModule} from '@angular/cdk/scrolling'; +import { ScrollingModule } from '@angular/cdk/scrolling'; + @NgModule({ -imports: [ -//... -ScrollDispatchModule, -//... -] + imports: [ + // ... + ScrollingModule, + // ... + ] }) ``` diff --git a/devui/dropdown/dropdown.directive.ts b/devui/dropdown/dropdown.directive.ts index 7017fbb2..9181dcee 100755 --- a/devui/dropdown/dropdown.directive.ts +++ b/devui/dropdown/dropdown.directive.ts @@ -112,7 +112,7 @@ export class DropDownDirective implements OnDestroy, OnChanges, AfterContentInit } ngOnChanges(changes: SimpleChanges) { - if (changes.hasOwnProperty('trigger')) { + if (Object.prototype.hasOwnProperty.call(changes,'trigger')) { this.handleHoverSubscriptionIfTriggerIsHover(); } } diff --git a/devui/editable-select/demo/basic/with-source.component.html b/devui/editable-select/demo/basic/with-source.component.html index 75813255..04544eea 100644 --- a/devui/editable-select/demo/basic/with-source.component.html +++ b/devui/editable-select/demo/basic/with-source.component.html @@ -4,6 +4,7 @@ [source]="languages" [maxHeight]="300" [(ngModel)]="selectItem1" + (toggleChange)="toggleChange($event)" name="multiple-auto" placeholder="Search" > diff --git a/devui/editable-select/demo/basic/with-source.component.ts b/devui/editable-select/demo/basic/with-source.component.ts index 2e7c0385..1b883000 100644 --- a/devui/editable-select/demo/basic/with-source.component.ts +++ b/devui/editable-select/demo/basic/with-source.component.ts @@ -1,7 +1,4 @@ -import { - Component, - OnInit -} from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'd-with-source', @@ -11,18 +8,29 @@ import { section { width: 50%; } - ` - ] + `, + ], }) -export class WithSourceComponent implements OnInit { +export class WithSourceComponent { selectItem1; + languages = [ + 'C#', + 'C', + 'C++', + 'CPython', + 'Java', + 'JavaScript', + 'Go', + 'Python', + 'Ruby', + 'F#', + 'TypeScript', + 'SQL', + 'LiveScript', + 'CoffeeScript', + ]; - languages = ['C#', 'C', 'C++', 'CPython', 'Java', 'JavaScript', 'Go', 'Python', 'Ruby', 'F#', 'TypeScript', 'SQL', - 'LiveScript', 'CoffeeScript']; - - constructor() { - } - - ngOnInit() { + toggleChange(event) { + console.log('isOpen:', event); } } diff --git a/devui/editable-select/doc/api-cn.md b/devui/editable-select/doc/api-cn.md index 0e485c9f..3af8d48e 100644 --- a/devui/editable-select/doc/api-cn.md +++ b/devui/editable-select/doc/api-cn.md @@ -35,9 +35,10 @@ import { EditableSelectModule } from 'ng-devui/editable-select'; ## d-editable-select 事件 -| 事件 | 类型 | 说明 | 跳转 Demo | -| :------: | :------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------- | -| loadMore | `EventEmitter>` | 懒加载触发事件,配合`enableLazyLoad`使用,使用`$event.loadFinish()`关闭 loading 状态,其中\$event 为 AutoCompletePopupComponent 的实例 | [数据懒加载](demo#lazy-load) | +| 事件 | 类型 | 说明 | 跳转 Demo | +| :----------: | :------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------- | +| loadMore | `EventEmitter>` | 懒加载触发事件,配合`enableLazyLoad`使用,使用`$event.loadFinish()`关闭 loading 状态,其中\$event 为 AutoCompletePopupComponent 的实例 | [数据懒加载](demo#lazy-load) | +| toggleChange | `EventEmitter` | 可选,输出函数,下拉打开关闭 toggle 事件 | [基本用法](demo#basic-usage) | # 接口 & 类型定义 diff --git a/devui/editable-select/doc/api-en.md b/devui/editable-select/doc/api-en.md index af910a19..8e9c10dc 100644 --- a/devui/editable-select/doc/api-en.md +++ b/devui/editable-select/doc/api-en.md @@ -19,7 +19,7 @@ On the page | Parameter | Type | Default | Description | Jump to Demo | Global Config | | :--------------------: | :-------------------------------------------------: | :-------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------- | ------------- | | appendToBody | `boolean` | false | Optional. Whether to appendToBody in the drop-down list box | [Basic usage](demo#basic-usage) | -| appendToBodyDirections | `Array` | `['rightDown','leftDown','rightUp','leftUp']` | Optional. The first position in the array is preferred for the direction array, for details about AppendToBodyDirection and ConnectedPosition, see dropdown | [Basic usage](demo#basic-usage) | +| appendToBodyDirections | `Array` | `['rightDown','leftDown',`
    `'rightUp','leftUp']` | Optional. The first position in the array is preferred for the direction array, for details about AppendToBodyDirection and ConnectedPosition, see dropdown | [Basic usage](demo#basic-usage) | | width | `number` | -- | Optional. Controls the width of the drop-down list box. This parameter is used with appendToBody (`px`) | | ngModel | `any` | -- | Optional. Selected objects can be bound in both directions. | [Basic usage](demo#basic-usage) | | source | `Array` | -- | Required. Data list | [Basic usage](demo#basic-usage) | @@ -35,9 +35,10 @@ On the page ## d-editable-select event -| Event | Type | Description | Jump to Demo | -| :------: | :------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------------- | -| loadMore | `EventEmitter>` | lazy loading trigger event. This event is used together with `enableLazyLoad' to disable the loading status. \$event indicates the instance of AutoCompletePopupComponent | [Enable lazy load](demo#lazy-load) | +| Event | Type | Description | Jump to Demo | +| :----------: | :------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------------- | +| loadMore | `EventEmitter>` | Optional. lazy loading trigger event. This event is used together with `enableLazyLoad' to disable the loading status. \$event indicates the instance of AutoCompletePopupComponent | [Enable lazy load](demo#lazy-load) | +| toggleChange | `EventEmitter` | Optional. output function. It is optional. It is used to enable or disable the toggle event. | [Basic usage](demo#basic-usage) | # Interface & Type Definition diff --git a/devui/editable-select/editable-select.component.html b/devui/editable-select/editable-select.component.html index cea02245..6cf00916 100755 --- a/devui/editable-select/editable-select.component.html +++ b/devui/editable-select/editable-select.component.html @@ -26,10 +26,11 @@ [sceneType]="'select'" [dAutoCompleteWidth]="width" dAutoComplete - [showAnimation]="showAnimation" - (selectValue)="selectValue($event)" [enableLazyLoad]="enableLazyLoad" + [showAnimation]="showAnimation" + (toggleChange)="toggleChangeHandler($event)" (loadMore)="loadMoreEvent($event)" + (selectValue)="selectValue($event)" />
    # {{ colOption.header }}
    + + + {{ rowIndex + 1 }} {{ colOption.fieldType === 'date' ? (rowItem[colOption.field] | i18nDate: 'short':false) : rowItem[colOption.field] }} diff --git a/devui/data-table/demo/mutil-styles/mutil-styles.component.ts b/devui/data-table/demo/mutil-styles/mutil-styles.component.ts index 7bb11740..6a1c1a61 100644 --- a/devui/data-table/demo/mutil-styles/mutil-styles.component.ts +++ b/devui/data-table/demo/mutil-styles/mutil-styles.component.ts @@ -84,6 +84,10 @@ export class MutilStylesComponent implements OnInit { }; tableWidthConfig: TableWidthConfig[] = [ + { + field: 'checkbox', + width: '50px' + }, { field: '#', width: '50px' @@ -114,6 +118,10 @@ export class MutilStylesComponent implements OnInit { this.tableWidthConfig = []; } else { this.tableWidthConfig = [ + { + field: 'checkbox', + width: '50px' + }, { field: '#', width: '50px' diff --git a/devui/data-table/doc/api-cn.md b/devui/data-table/doc/api-cn.md index 712befa2..f3e2f2d4 100644 --- a/devui/data-table/doc/api-cn.md +++ b/devui/data-table/doc/api-cn.md @@ -22,6 +22,7 @@ import { DataTableModule } from 'ng-devui/data-table'; | scrollable | `boolean` | -- | 可选,表格在超出容器时,是否可以通过滚动查看表格内容 | [表格交互](demo#table-interaction) | | maxWidth | `string px` | -- | 可选,限制表格最大宽度,默认撑满父容器 | | maxHeight | `string px` | -- | 可选,限制最大高度,默认 | [表头固定](demo#table-fixing) | +| minHeight | `string px` | -- | 可选,限制最小高度 | -- | | size | `'sm'\|'md'\|'lg'` | 'sm' | 可选,表格大小,分别对应行高40px,48px,56px |[表格样式](demo#mutil-styles) | | rowHoveredHighlight | `boolean` | true | 可选,鼠标悬浮行时是否高亮,默认高亮认 | | generalRowHoveredData | `boolean` | false | 可选,使用配置column方式实现table,鼠标悬浮行时$hovered是否记录到rowItem中,默认不记录 | @@ -31,11 +32,11 @@ import { DataTableModule } from 'ng-devui/data-table'; | containFixHeaderHeight | `boolean` | false | 可选,固定表头指定的高度是否包含表头高度,`tableHeight`设置的高度默认是表格body的高度 | [固定表头虚拟滚动](demo#fixed-virtual-scroll) | | fixHeader | `boolean` | false | 可选,表头是否固定 | [固定表头虚拟滚动](demo#fixed-virtual-scroll) | | checkableRelation | [`CheckableRelation`](#checkablerelation) | -- | 可选,配置树形表格的父子选中是否互相关联 | [树形表格](demo#tree-form) | -| loadChildrenTable | `Promise` | -- | 可选,展开子表格的回调,用于异步加载子表格 | [树形表格](demo#tree-form) | -| loadAllChildrenTable | `Promise` | -- | 可选,表头展开所有子表格的回调,用于异步加载所有子表格 | [树形表格](demo#tree-form) | +| loadChildrenTable | `(rowItem: any) => Promise` | -- | 可选,展开子表格的回调,用于异步加载子表格 | [树形表格](demo#tree-form) | +| loadAllChildrenTable | `() => Promise` | -- | 可选,表头展开所有子表格的回调,用于异步加载所有子表格 | [树形表格](demo#tree-form) | | colDraggable | `boolean` | false | 可选,表格列是否可拖动排序 | [列拖拽](demo#column-dragging) | | colDropFreezeTo | `number` | 0 | 可选,表格列可拖动排序时配置前n列不可拖动 | [列拖拽](demo#column-dragging) | -| virtualScroll | `boolean` | false | 可选,是否开启虚拟滚动 | [虚拟滚动](demo#virtual-scroll) | +| virtualScroll | `boolean` | false | 可选,是否开启虚拟滚动,虚拟滚动参数对树形表格不生效 | [虚拟滚动](demo#virtual-scroll) | | virtualItemSize | `number` | 40 | 可选,虚拟滚动时每一行的高度,默认为表格默认行高40`px` | [虚拟滚动](demo#virtual-scroll) | | virtualMinBufferPx | `number` | 80 | 可选,虚拟滚动时缓冲区最小像素高度,低于该值时将加载新结构 | [虚拟滚动](demo#virtual-scroll) | | virtualMaxBufferPx | `number` | 200 | 可选,虚拟滚动时缓冲区最大像素高度 | [虚拟滚动](demo#virtual-scroll) | @@ -51,11 +52,11 @@ import { DataTableModule } from 'ng-devui/data-table'; | hideColumn | `string[]` | -- | 可选,用于隐藏列,传入对应的field字段 | | pageAllChecked | `boolean` | -- | 可选,选中当前页所有row | | onlyOneColumnSort | `boolean` | -- | 可选,是否限制多列排序的输出限制为一项 | [表格交互](demo#table-interaction) | -| multiSort | [`SortEventArg[]`](#sorteventarg) | [] | 可选,多列选择数组,用来指导那几列会被排序 | [表格交互](demo#table-interaction) | +| multiSort | [`SortEventArg[]`](#sorteventarg) | [] | 可选,多列选择数组,用来指导那几列会被排序,仅column模式下有效 | [表格交互](demo#table-interaction) | | resizeable | `boolean` | -- | 可选,是否可以拖拽调整列宽 | [表格交互](demo#table-interaction) | | timeout | `number` | 300 | 可选,同时绑定单击、双击事件时,用于区分点击的时间间隔, 默认300`ms`,两个事件不同时使用可以指定为0 | | headerExpandConfig | [`TableExpandConfig`](#tableexpandconfig) | -- | 可选,配置header下的额外内容 | [扩展行](demo#expand-row) | -| beforeCellEdit | `Promise` | -- | 可选,单元格编辑前的拦截方法,
    resolve(extraOptions)将更新该列的extraOptions | [编辑单元格](demo#edit-cell) | +| beforeCellEdit | `(rowItem: any, column: any) => Promise` | -- | 可选,单元格编辑前的拦截方法,
    resolve(extraOptions)将更新该列的extraOptions | [编辑单元格](demo#edit-cell) | | headerBg | `boolean` | false | 可选,表头是否显示背景色 | [表格样式](demo#mutil-styles) | | tableLayout | `'fixed'\|'auto'` | 'fixed' | 可选,表格布局 | [表格样式](demo#mutil-styles) | | borderType | `''\|'bordered'\|'borderless'` | '' | 可选,表格边框类型,默认有行边框,bordered:全边框,borderless:无边框 | [表格样式](demo#mutil-styles) | @@ -70,7 +71,7 @@ import { DataTableModule } from 'ng-devui/data-table'; | resize | `EventEmitter` | 列宽变化事件,返回单元格信息 | [表格交互](demo#table-interaction) | | childrenTableClose | `EventEmitter` | 子列表关闭事件,返回列表行信息 | | allChildrenTableClose | `EventEmitter` | 全部子列表关闭事件 | -| multiSortChange | `EventEmitter` | 多列选择Change事件,用来更新多列选择数组,返回单元格信息 | [表格交互](demo#table-interaction) | +| multiSortChange | `EventEmitter` | 多列选择Change事件,用来更新多列选择数组,返回单元格信息, 仅column模式下生效 | [表格交互](demo#table-interaction) | | cellClick | `EventEmitter` | 表格单元格点击事件,返回单元格信息 | [表格交互](demo#table-interaction) | | cellDBClick | `EventEmitter` | 表格单元格双击事件,返回单元格信息 | [表格交互](demo#table-interaction) | | rowClick | `EventEmitter` | 表格行点击事件,返回行信息 | [表格交互](demo#table-interaction) | @@ -80,6 +81,7 @@ import { DataTableModule } from 'ng-devui/data-table'; | cellEditEnd | `EventEmitter` | 表格单元格结束编辑事件,返回单元格信息 | [编辑单元格](demo#edit-cell) | | tableScrollEvent | `EventEmitter` | 表格内部滚动事件 | | | columnDragEnd | `EventEmitter<{form: index, to: index}>` | 列拖拽结束事件 | [列拖拽](demo#column-dragging) | +| loadMore | `EventEmitter<{any}>` | 延迟懒加载完成事件 | [懒加载](demo#lazy-loading-of-list-data) | ### d-data-table 公共方法 @@ -121,7 +123,7 @@ import { DataTableModule } from 'ng-devui/data-table'; | resizeEnabled | `boolean` | -- | 可选,该列宽度是否可调整 | [表格交互](demo#table-interaction) | | maxWidth | `string` | -- | 可选,拖动调整宽度时的最大宽度,单位`px` | | minWidth | `string` | -- | 可选,拖动调整宽度时的最小宽度,单位`px` | -| filterable | `boolean` | -- | 可选,该列宽度是否可过滤 | [表格交互](demo#table-interaction) | +| filterable | `boolean` | -- | 可选,该列是否可过滤 | [表格交互](demo#table-interaction) | | closeFilterWhenScroll | `boolean` | -- | 可选,表格或者body滚动时是否关闭过滤框 | [表格交互](demo#table-interaction) | | customFilterTemplate | `TemplateRef` | -- | 可选,过滤弹出框的自定义模板 | [表格交互](demo#table-interaction) | | extraFilterTemplate | `TemplateRef` | -- | 可选,过滤弹出框扩展区域自定义模板 | [表格交互](demo#table-interaction) | @@ -130,12 +132,12 @@ import { DataTableModule } from 'ng-devui/data-table'; | filterMultiple | `boolean` | -- | 可选,设置该列为多选或单选, true为多选,false为单选 | [表格交互](demo#table-interaction) | | filterBoxWidth | `string` | -- | 过滤弹出框的宽度,如:‘300px’ | | filterBoxHeight | `string` | -- | 过滤弹出框的高度,如:‘400px’ | -| beforeFilter | `function\|Promise\|Observable` | -- | 可选,表格过滤弹出框弹出前的回调函数,返回false可阻止弹框弹出 | [表格交互](demo#table-interaction) | +| beforeFilter | `(value) => boolean \| Promise \| Observable` | -- | 可选,表格过滤弹出框弹出前的回调函数,返回false可阻止弹框弹出 | [表格交互](demo#table-interaction) | | sortable | `boolean` | -- | 可选,该列是否可排序 | [表格交互](demo#table-interaction) | | sortDirection | `SortDirection` | -- | 可选,设置该列的已排序状态 | [表格交互](demo#table-interaction) | | nestedColumn | `boolean` | -- | 可选,是否展示树形表格的表头展开\折叠图标 | [树形表格](demo#tree-form) | -| iconFoldTable | `DOMString` | -- | 可选,自定义树形表格的折叠图标 | [树形表格](demo#tree-form) | -| iconUnFoldTable | `DOMString` | -- | 可选,自定义树形表格的展开图标 | [树形表格](demo#tree-form) | +| iconFoldTable | `DOMString` | -- | 可选,自定义树形表格的折叠图标,传入自定义html字符串 | [树形表格](demo#tree-form) | +| iconUnFoldTable | `DOMString` | -- | 可选,自定义树形表格的展开图标,传入自定义html字符串 | [树形表格](demo#tree-form) | | fixedLeft | `string` | -- | 可选,该列固定到左侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | | fixedRight | `string` | -- | 可选,该列固定到右侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | | showSortIcon | `boolean` | fasle | 可选,是否显示排序未激活图标,默认不显示 | [表格交互](demo#table-interaction) | @@ -145,12 +147,13 @@ import { DataTableModule } from 'ng-devui/data-table'; | 事件 | 类型 | 描述 | 跳转 Demo | | :----------------------: | :-----------------: | :-------------------------------------------------: | :------------------------------------------------------- | -| filterChange | `FilterConfig[]` | 确认筛选回调事件,返回选中的筛选数组 | [表格交互](demo#table-interaction) | -| sortChange | `SortEventArg` | 排序回调事件,返回该列排序信息 | [表格交互](demo#table-interaction) | -| resizeStartEvent | `MouseEvent` | 该列宽度调整开始时的事件 | -| resizingEvent | `{ width: string }` | 该列宽度调整进行中的事件 | -| resizeEndEvent | `{ width: string }` | 该列宽度调整结束时的事件 | [表格交互](demo#table-interaction) | -| toggleChildrenTableEvent | `boolean` | 所有子表格展开收起事件,true表示展开,false表示收起 | +| filterChange | `EventEmitter` | 确认筛选回调事件,返回选中的筛选数组 | [表格交互](demo#table-interaction) | +| sortChange | `EventEmitter` | 排序回调事件,返回该列排序信息 | [表格交互](demo#table-interaction) | +| resizeStartEvent | `EventEmitter` | 该列宽度调整开始时的事件 | +| resizingEvent | `EventEmitter<{ width: string }>` | 该列宽度调整进行中的事件 | +| resizeEndEvent | `EventEmitter<{ width: string }>` | 该列宽度调整结束时的事件 | [表格交互](demo#table-interaction) | +| toggleChildrenTableEvent | `EventEmitter` | 所有子表格展开收起事件,true表示展开,false表示收起 | | +| sortDirectionChange | `EventEmitter` | 排序顺序方向变化事件 | # dTableCell @@ -177,8 +180,8 @@ import { DataTableModule } from 'ng-devui/data-table'; | 事件 | 类型 | 描述 | 跳转 Demo | | :-------------------: | :-------: | :-----------------------------------------------------: | :------------------------------------------------- | -| editStatusEvent | `boolean` | 单元格编辑状态事件 | [编辑单元格](demo#edit-cell) | -| toggleChildTableEvent | `boolean` | 当前行的子表格展开收起事件,true表示展开,false表示收起 | [树形表格](demo#tree-form) | +| editStatusEvent | `EventEmitter` | 单元格编辑状态事件 | [编辑单元格](demo#edit-cell) | +| toggleChildTableEvent | `EventEmitter` | 当前行的子表格展开收起事件,true表示展开,false表示收起 | [树形表格](demo#tree-form) | #### 使用自定义模板方式时配置dTableBody的行模板 @@ -340,15 +343,17 @@ export enum SortDirection { | closeFilterWhenScroll | `boolean` | -- | 可选,表格或者body滚动时是否关闭过滤框 | [表格交互](demo#table-interaction) | | filterList | `array` | -- | 传入需要操作的筛选列表,当filterable为true时必选 | [表格交互](demo#table-interaction) | | filterMultiple | `boolean` | true | 可选,选择筛选列表为多选或单选, true为多选,false为单选 | [表格交互](demo#table-interaction) | +| filterIconActive | `boolean` | false | 可选,主动设置filter 图标是否激活 | [表格交互](demo#table-interaction) | | customFilterTemplate | `TemplateRef` | -- | 可选,表格过滤弹出框的自定义模板,参考DOC下‘自定义过滤弹出框’使用 | [表格交互](demo#table-interaction) | | extraFilterTemplate | `TemplateRef` | -- | 可选,表格过滤弹出框扩展区域自定义模板 | [表格交互](demo#table-interaction) | -| beforeFilter | `function、Promise、Observable` | -- | 可选,表格过滤弹出框弹出前的回调函数,返回false可阻止弹框弹出 | [表格交互](demo#table-interaction) | +| beforeFilter | `(value) => boolean \| Promise \| Observable` | -- | 可选,表格过滤弹出框弹出前的回调函数,返回false可阻止弹框弹出 | [表格交互](demo#table-interaction) | | cellClass | `string` | -- | 该列单元格自定义class | | fixedLeft | `string` | -- | 该列固定到左侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | | fixedRight | `string` | -- | 该列固定到右侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | | filterBoxWidth | `any` | -- | 过滤弹出框的宽度,如:‘300px’ | | filterBoxHeight | `any` | -- | 过滤弹出框的高度,如:‘400px’ | | nestedColumnIndent | `number` | 16 | 单元格中子表格的缩进距离,单位px | [树形表格](demo#tree-form) | +| advancedHeader | `advancedHeader` | -- | column类型的表格中实现表头单元格合并 | [树形表格](demo#tree-form) | ## d-column 事件 @@ -446,4 +451,4 @@ advancedHeader: Array < { } ``` -注意: 空单元格也需要表示,并根据内容把rowspan/colspan置为0,如果同时使用列宽拖拽和多行表头,请为列内容附上宽度width,如果第一行的列宽度不正确,请手动为advancedHeader[rowNumber]增加一个属性$width \ No newline at end of file +注意: 空单元格也需要表示,并根据内容把rowspan/colspan置为0,如果同时使用列宽拖拽和多行表头,请为列内容附上宽度width,如果第一行的列宽度不正确,请手动为advancedHeader[rowNumber]增加一个属性$width diff --git a/devui/data-table/doc/api-en.md b/devui/data-table/doc/api-en.md index 318eca60..76ac9a5f 100644 --- a/devui/data-table/doc/api-en.md +++ b/devui/data-table/doc/api-en.md @@ -22,6 +22,7 @@ On the page: | scrollable | `boolean` | -- | Optional. Whether the table content can be viewed by scrolling when the table exceeds the container. | [Table interaction](demo#table-interaction) | | maxWidth | `string px` | -- | Optional. Limit the maximum table width. By default, the parent container is full. | | maxHeight | `string px` | -- | Optional. The maximum height is limited. The default value is | [fixed table header](demo#table-fixing) | +| minHeight | `string px` | -- | Optional, limit the minimum height | -- | | size | `'sm'\|'md'\|'lg'`| 'sm' | Optional. Specifies the table size, which corresponds to 40 px, 48 px, and 56 px respectively | [Table style](demo#mutil-styles) | | rowHoveredHighlight | `boolean` | true | Optional. Indicating whether to highlight a line when the cursor is hovering. The default value is highlighted. | | generalRowHoveredData | `boolean` | false | Optional. It is used to configure columns to implement the table. When the cursor is moved to a row, $hovered is recorded to the row item. By default, $hovered is not recorded. | @@ -31,11 +32,11 @@ On the page: | containFixHeaderHeight | `boolean` | false | Optional. whether the height specified by the fixed header includes the height of the header, the height set by tableHeight is the height of the table body by default | [Fixed table header virtual scrolling](demo#fixed-virtual-scroll) | | fixHeader | `boolean` | false | Optional. Whether the table header is fixed | [Fixed table header virtual scrolling](demo#fixed-virtual-scroll) | | checkableRelation | [`CheckableRelation`](#checkablerelation) | -- | Optional. This parameter specifies whether the parent and child selections in the tree table are associated. | [Tree table](demo#tree-form) | -| loadChildrenTable | `Promise` | -- | Optional. It is the callback of subtable expansion, which is used to asynchronously load subtables. | [Tree table](demo#tree-form) | -| loadAllChildrenTable | `Promise` | -- | Optional. It is the callback for expanding all subtables in the table header. It is used to asynchronously load all subtables. | [Tree table](demo#tree-form) | +| loadChildrenTable | ``(rowItem: any) => Promise` | -- | Optional. It is the callback of subtable expansion, which is used to asynchronously load subtables. | [Tree table](demo#tree-form) | +| loadAllChildrenTable | `() => Promise` | -- | Optional. It is the callback for expanding all subtables in the table header. It is used to asynchronously load all subtables. | [Tree table](demo#tree-form) | | colDraggable | `boolean` | false | Optional. Whether columns can be dragged or sorted | [Column dragging](demo#column-dragging) | | colDropFreezeTo | `number` | 0 | Optional. The first n columns cannot be dragged when the table columns can be sorted. | [Column dragging](demo#column-dragging) | -| virtualScroll | `boolean` | false | Optional. Specifies whether to enable virtual scrolling. | [Virtual scrolling](demo#virtual-scroll) | +| virtualScroll | `boolean` | false | Optional. Specifies whether to enable virtual scrolling. Virtual scrolling parameters do not take effect for tree tables. | [Virtual scrolling](demo#virtual-scroll) | | virtualItemSize | `number` | 40 | Optional. Height of each row during virtual scrolling. The default value is 40`px`. | [Virtual scrolling](demo#virtual-scroll) | | virtualMinBufferPx | `number` | 80 | Optional. Minimum pixel height of the buffer during virtual scrolling. If the pixel height is less than this value, the new structure is loaded. | [Virtual scrolling](demo#virtual-scroll) | | virtualMaxBufferPx | `number` | 200 | Optional. Maximum pixel height of the buffer during virtual scrolling | [virtual scrolling](demo#virtual-scroll) | @@ -51,11 +52,11 @@ On the page: | hideColumn | `string[]` | -- | Optional. Used to hide columns, Transfer the corresponding field. | | pageAllChecked | `boolean` | -- | Optional. Select all rows on the current page. | | onlyOneColumnSort | `boolean` | -- | Optional. Whether to restrict the output of multi-column sorting to one item | [Table interaction](demo#table-interaction) | -| multiSort | [`SortEventArg[]`](#sorteventarg) | [] | Optional. It is a multi-column selection array, which is used to guide the columns to be sorted. | [Table interaction](demo#table-interaction) | +| multiSort | [`SortEventArg[]`](#sorteventarg) | [] | Optional. It is a multi-column selection array, which is used to guide the columns to be sorted.This parameter is valid only in column mode. | [Table interaction](demo#table-interaction) | | resizeable | `boolean` | -- | Optional. Whether the column width can be adjusted by dragging. | [Table interaction](demo#table-interaction) | | timeout | `number` | 300 | Optional. This parameter is used to distinguish the click interval when the click and double-click events are bound at the same time. The default value is 300`ms`. You can set this parameter to 0 when the two events are used at the same time. | | headerExpandConfig | [`TableExpandConfig`](#tableexpandconfig) | -- | Optional. Extra content under the header | [Extended line](demo#expand-row) | -| beforeCellEdit | `Promise` | -- | Optional. Interception method before cell editing.
    resolve(extraOptions) updates extraOptions of the column. | [edit cell](demo#edit-cell) | +| beforeCellEdit | `(rowItem: any, column: any) => Promise` | -- | Optional. Interception method before cell editing.
    resolve(extraOptions) updates extraOptions of the column. | [edit cell](demo#edit-cell) | | headerBg | `boolean` | false | Optional. Indicating whether to display the background color in the table header | [Table style](demo#mutil-styles) | | tableLayout | `'fixed'\|'auto'` | 'fixed' | Optional. Table layout | [Table style](demo#mutil-styles) | | borderType | `''\|'bordered'\|'borderless'` | '' | Optional. Table border type. The default value is row border. The options are bordered (full border) and borderless (no border). | [Table style](demo#mutil-styles) | @@ -70,7 +71,7 @@ On the page: | resize | `EventEmitter` | Column Width Change Event, Returning Cell Information | [Table Interaction](demo#table-interaction) | | childrenTableClose | `EventEmitter` | Event for closing a sublist. The list row information is returned. | | allChildrenTableClose | `EventEmitter` | All Sublist Close Event | -| multiSortChange | `EventEmitter` | Change event, which is used to update the multi-column selection array and return cell information. | [Table interaction](demo#table-interaction) | +| multiSortChange | `EventEmitter` | Change event, which is used to update the multi-column selection array and return cell information.This parameter is valid only in column mode. | [Table interaction](demo#table-interaction) | | cellClick | `EventEmitter` | Cell Click Event, Returning Cell Information | [Table Interaction](demo#table-interaction) | | cellDBClick | `EventEmitter` | Cell Double-click Event, Returning Cell Information | [Table Interaction](demo#table-interaction) | | rowClick | `EventEmitter` | Table row click event, which returns row information | [Table interaction](demo#table-interaction) | @@ -80,6 +81,7 @@ On the page: | cellEditEnd | `EventEmitter` | Table cell editing end event. Cell information is returned. | [Edit cell](demo#edit-cell) | | tableScrollEvent | `EventEmitter` | Table Internal Rolling Event | | | columnDragEnd | `EventEmitter<{form: index, to: index}>` | Column Drag End Event | [Column dragging](demo#column-dragging) | +| loadMore | `EventEmitter<{any}>` | Lazy Loading Completion Event|[Lazy Loading](demo#lazy-loading-of-list-data) | ## d-data-table public method @@ -129,7 +131,7 @@ On the page: | filterMultiple | `boolean` | -- | Optional. Sets the column to be selected. true indicates that multiple choices are selected, and false indicates that only one choice is selected. | [Table interaction](demo#table-interaction) | | filterBoxWidth | `string` | -- | Optional. Width of the filter dialog box, for example, 300px. | | filterBoxHeight | `string` | -- | Optional. Height of the filter dialog box, for example, 400px. | -| beforeFilter | `function\|Promise\|Observable` | -- | Optional. Callback function before the table filtering dialog box is displayed. If false is returned, the dialog box is blocked. | [Table interaction](demo#table-interaction) | +| beforeFilter | `(value) => boolean \| Promise \| Observable` | -- | Optional. Callback function before the table filtering dialog box is displayed. If false is returned, the dialog box is blocked. | [Table interaction](demo#table-interaction) | | sortable | `boolean` | -- | Optional. Whether the column can be sorted | [Table interaction](demo#table-interaction) | | sortDirection | `SortDirection` | -- | Optional. Sets the sorting status of the column. | [Table interaction](demo#table-interaction) | | nestedColumn | `boolean` | -- | Optional. Indicates whether to display the expand or collapse icon of the table header in the tree table. | [Tree table](demo#tree-form) | @@ -144,19 +146,20 @@ On the page: | Event | Type | Description | Jump to Demo | | :----------------------: | :-----------------: | :-------------------------------------------------: | :------------------------------------------------------- | -| filterChange | `FilterConfig[]` | Callback event for confirming the filtering and returning the selected filtering array. | [Table interaction](demo#table-interaction) | -| sortChange | `SortEventArg` | Sorting callback event, which returns the sorting information of the column. | [Table interaction](demo#table-interaction) | -| resizeStartEvent | `MouseEvent` | Event when the column width adjustment starts | -| resizingEvent | `{width: string}` | Event that the column width is being adjusted | -| resizeEndEvent | `{width: string}` | Event when the column width adjustment ends | [Table interaction](demo#table-interaction) | -| toggleChildrenTableEvent | `boolean` | Event for expanding and collapsing all subtables. The value true indicates expanding, and the value false indicates collapse. | +| filterChange | `EventEmitter` | Callback event for confirming the filtering and returning the selected filtering array. | [Table interaction](demo#table-interaction) | +| sortChange | `EventEmitter` | Sorting callback event, which returns the sorting information of the column. | [Table interaction](demo#table-interaction) | +| resizeStartEvent | `EventEmitter` | Event when the column width adjustment starts | +| resizingEvent | `EventEmitter<{ width: string }>` | Event that the column width is being adjusted | +| resizeEndEvent | `EventEmitter<{ width: string }>` | Event when the column width adjustment ends | [Table interaction](demo#table-interaction) | +| toggleChildrenTableEvent | `EventEmitter` | Event for expanding and collapsing all subtables. The value true indicates expanding, and the value false indicates collapse. | +| sortDirectionChange | `EventEmitter` | Sort Order Direction Change Event| # dTableCell ## dTableCell Parameter -| Parameter name | Type | Default value | Description | Jump to Demo |Global Config| -| :-------------: | :-----------------------------: | :----- | :------------------------------------------------------------: | :------------------------------------------------- | +| Parameter name | Type | Default value | Description | Jump to Demo | +| :-------------: | :-----------------------------: | :-----: | :------------------------------------------------: | :----------------------: | | editable | `boolean` | -- | Optional. Whether a cell can be edited | [edit cell](demo#edit-cell) | | editableTip | `'hover'\|'btn'` | -- | Optional. This parameter indicates the editing prompt. The background color of the hover changes. The edit button is displayed in the btn. | [edit cell](demo#edit-cell) | | nestedColumn | `boolean` | -- | Optional. Display the expansion and collapse icons when the row in the tree table contains subtables. | [Tree table](demo#tree-form) | @@ -176,8 +179,8 @@ On the page: | Event | Type | Description | Jump to Demo | | :-------------------: | :-------: | :-----------------------------------------------------: | :------------------------------------------------- | -| editStatusEvent | `boolean` | Cell editing status event | [edit cell](demo#edit-cell) | -| toggleChildTableEvent | `boolean` | Event for expanding and collapsing the subtable in the current row. The options are true and false. | [Tree table](demo#tree-form) | +| editStatusEvent | `EventEmitter` | Cell editing status event | [edit cell](demo#edit-cell) | +| toggleChildTableEvent | `EventEmitter` | Event for expanding and collapsing the subtable in the current row. The options are true and false. | [Tree table](demo#tree-form) | #### Configure the row template of the dTableBody when the user-defined template is used. @@ -432,249 +435,3 @@ colspan: number; } ``` Note: Empty cells also need to be indicated. Set rowspan/colspan to 0 based on the content. If column width dragging and multi-row headers are used at the same time, attach the width to the column content. If the column width of the first row is incorrect, manually add the $width attribute for advancedHeader[rowNumber]. - -#### Tree table with a large amount of data - -## virtual-scroll-tree-table parameter -| Parameter name | Type | Default value | Description | Jump to Demo | -| :---------------: | :-----------------: | :----- | :-------------------------------------------------------------------------------------------------------: |:-----------------: | -| dataSource | `any[]` | -- | Required. It is a data source used to render table data. |[Tree table with a large amount of data](demo#virtual-scroll-tree-table)| -| editOption | `any[]` | -- | Optional. Used to configure the resource of the drop-down list box during modification. |[Tree table with a large amount of data](demo#virtual-scroll-tree-table)| -| showRowIndex | `number` | 10 | Optional. Used to configure the initial number of rows to be displayed in a table. |[Tree table with a large amount of data](demo#virtual-scroll-tree-table)| -| dataTableProperties | [`DataTableProperiesInterface`](#DataTableProperiesInterface) | -- | Optional. Support for original parameters of dataTable, Parameters defined in DataTableProperiesInterface can be supported. |[Tree table with a large amount of data](demo#virtual-scroll-tree-table)| - -## virtual-scroll-tree-table event -| Event | Type | Description | Jump to Demo | -| :-------------------: | :------------------------------------: | :------------------------------------------------------: | :------------------------------------------------------: | -| save | `EventEmitter` | Returns the data after the operation is changed. | [Tree table with a large amount of data](demo#virtual-scroll-tree-table) | - -## Customizing Templates and Operation Columns in d-column Mode - -``` xml - - - - {{ rowItem.category }} - - - - -
    - - -
    -
    -
    -
    - - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -``` - -## Expanding or collapsing a tree table with a large amount of data - -Use @ViewChild to invoke the expand/collapse all function - -``` xml - -Expand All -Fold All -``` - -``` javascript -@ViewChild('VirtualTableTree') VirtualTableTree: VirtualScrollTreeTableComponent; - -toggleAllNodesExpand(e) { - this.VirtualTableTree.toggleAllNodesExpand(e); - this.isOpenAll = e; -} - -// Use @ViewChild to call toggleAllNodesExpand method in VirtualScrollTreeTableComponent -``` - -## Tree table search for a large amount of data - -Use @ViewChild to invoke the search function - -``` xml -
    - -
    - -``` - -``` javascript -@ViewChild('VirtualTableTree') VirtualTableTree: VirtualScrollTreeTableComponent; - -searchSelectChange() { - this.BigTableTree.searchAttr = this.searchAttr; - this.BigTableTree.searchSelectChange(); -} - -search(event) { - this.VirtualTableTree.search(event); - if(event) { - this.isSearch = true; - } else { - this.isSearch = false; - } -} - -// Call the searchSelectChange and search methods in VirtualScrollTreeTableComponent using @ViewChild -``` - -## Adding a large amount of data to a tree table - -Use @ViewChild to invoke the add function - -``` xml -// Global Add -Add Node -Add Folder - -// Add Operation Column -
    -
    -
    -
    -``` - -``` javascript -@ViewChild('VirtualTableTree') VirtualTableTree: VirtualScrollTreeTableComponent; - -// Users can customize data templates. -addTemplate: any = { - "property": "addPro", - "description": "addDes", - "category": "Dynamic" -} - -// Global Add -addGolbal(status) { - this.isAddGolbalData = true; - this.VirtualTableTree.addGolbal(status, this.addTemplate); - this.isAddGolbalData = false; -} - -// Call the addGolbal method in VirtualScrollTreeTableComponent using @ViewChild - -// Add Operation Column -addOperation(rowItem, status) { - this.VirtualTableTree.addOperation(rowItem, status, this.addTemplate); -} - -// Call the addOperation method in VirtualScrollTreeTableComponent using @ViewChild -``` - -## Copying and Pasting Tree Tables with a Large Amount of Data - -Use @ViewChild to invoke the copying and pasting function - -``` xml -
    -
    -
    -
    -``` - -``` javascript -@ViewChild('VirtualTableTree') VirtualTableTree: VirtualScrollTreeTableComponent; - -copyAndCut(rowItem, status) { - this.saveCopyClickNode = rowItem.node_id; - if(status === 'cut') { - this.isCut = true; - } - this.VirtualTableTree.copyAndCut(rowItem, status); -} - -paste(rowItem, status) { - this.VirtualTableTree.paste(rowItem, status); - if(this.isCut) { - this.saveCopyClickNode = ""; - this.isCut = false; - } -} - -// Use @ViewChild to call copyAndCut and paste methods in VirtualScrollTreeTableComponent -``` - -## Removing a large amount of data from a tree table - -Use @ViewChild to invoke the delete function -``` xml -
    -``` - -``` javascript -@ViewChild('VirtualTableTree') VirtualTableTree: VirtualScrollTreeTableComponent; - -delete(rowItem) { - this.VirtualTableTree.delete(rowItem); -} - -// Call the delete method in VirtualScrollTreeTableComponent using @ViewChild -``` - -## DataTableProperiesInterface - -```ts -export interface DataTableProperiesInterface { - maxWidth?: string; - maxHeight?: string; - size?: string; - rowHoveredHighlight?: boolean; - generalRowHoveredData?: boolean; - cssClass?: string; - tableWidth?: string; - fixHeader?: boolean; - colDraggable?: boolean; - colDropFreezeTo?: number; - tableWidthConfig?: TableWidthConfig[]; - showSortIcon?: boolean; - showFilterIcon?: boolean; - showOperationArea?: boolean; - hideColumn?: string[]; - pageAllChecked?: boolean; - onlyOneColumnSort?: boolean; - multiSort?: any; - resizeable?: boolean; - timeout?: number; - beforeCellEdit?: any; - headerBg?: boolean; - tableLayout?: string; - borderType?: string; - striped?: boolean; -} -``` \ No newline at end of file diff --git a/devui/data-table/public-api.ts b/devui/data-table/public-api.ts index 5b4fc8a7..ee70c1de 100755 --- a/devui/data-table/public-api.ts +++ b/devui/data-table/public-api.ts @@ -2,10 +2,11 @@ export * from './data-table-body.component'; export * from './data-table-cell.component'; export * from './data-table-head.component'; export * from './data-table-row.component'; +export * from './data-table-row.token'; export * from './data-table.component'; export * from './data-table.model'; export * from './data-table.module'; -export * from './dataTableProperties.interface'; +export * from './data-table.token'; export * from './display-cell-value.pipe'; export * from './editor-host.directive'; export * from './table/body/tbody.component'; @@ -21,5 +22,4 @@ export * from './tmpl/data-table-cell-tmpl.component'; export * from './tmpl/data-table-cell-view-tmpl.component'; export * from './tmpl/data-table-column-tmpl.component'; export * from './tmpl/data-table-head-cell-tmpl.component'; -export * from './virtualScrollTreeTable.component'; - +export * from './utils/utils'; diff --git a/devui/data-table/table/body/td/td.component.ts b/devui/data-table/table/body/td/td.component.ts index 80a381de..d1b0915e 100644 --- a/devui/data-table/table/body/td/td.component.ts +++ b/devui/data-table/table/body/td/td.component.ts @@ -34,8 +34,11 @@ export class TableTdComponent implements OnInit, OnChanges, OnDestroy { @Input() beforeEditEnd: (rowItem, field) => boolean | Promise | Observable; @Output() toggleChildTableEvent = new EventEmitter(); @Input() editing: boolean; - @Output() editingChange = new EventEmitter(); @Output() editStatusEvent = new EventEmitter(); + /** + * 编辑状态调整 @deprecated + */ + @Output() editingChange = new EventEmitter(); private documentClickSubscription: Subscription; private tdMousedownSubscription: Subscription; diff --git a/devui/data-table/table/head/th/filter/filter.component.html b/devui/data-table/table/head/th/filter/filter.component.html index dd563217..24c51c52 100644 --- a/devui/data-table/table/head/th/filter/filter.component.html +++ b/devui/data-table/table/head/th/filter/filter.component.html @@ -38,7 +38,6 @@ [ngStyle]="{ 'min-height': filterBoxHeight ? filterBoxHeight : '60px' }" > item.node_id !== ""); - } - return arr; - } -} - - -// 新增 -export class VirtualScrollTreeTableAdd { - findChild: any; - - addGolbal(status, treeTableArray, addTemplate?) { - if(addTemplate) { - treeTableArray = this.addData(status, treeTableArray, addTemplate); - } else { - treeTableArray = this.addData(status, treeTableArray); - } - return treeTableArray; - } - - addOperation(rowItem, status, treeTableArray, addTemplate?) { - let dataObj: any; - if(addTemplate) { - dataObj = this.addData(status, treeTableArray, addTemplate); - } else { - dataObj = this.addData(status, treeTableArray); - } - const lastDataObj = this.getoperationAddData(status, rowItem, dataObj); - this.changeOperationAdd(lastDataObj, treeTableArray); - return treeTableArray; - } - - addData(type, treeTableArray, addTemplate?) { - const newType = (type==='node' || type==='addDataNode' || type==='insertDataNode') ? "node" : "folder"; - const properties = this.getAddDataProperties(newType, treeTableArray); - let obj: any = {}; - if(addTemplate) { - obj = {...properties, ...addTemplate}; - } else { - obj = { - "id": properties.id, - "type": properties.type, - "name": properties.name, - "property": "", - "description": "", - "locked": 0, - "create_user": "张三", - "create_time": "2021-08-31T00:00:00.000+00:00", - "update_user": "李四", - "update_time": "2021-08-31T00:00:00.000+00:00", - "node_type": properties.node_type, - "node_id": properties.node_id, - "by_order": properties.by_order, - "category": "Static", - "update_time_string": "2021-08-31 00:00:00", - "create_time_string": "2021-08-31 00:00:00" - }; - } - if(type === 'node' || type === 'folder') { - treeTableArray.push(obj); - return treeTableArray; - } else { - return obj; - } - } - - getAddDataProperties(type, treeTableArray) { - return { - id: generateId(), - node_id: generateId(), - node_type: type === 'node' ? 0 : 1, - type: type === 'node'? 'String' : '', - name: this.getAddName(type, treeTableArray), - by_order: treeTableArray.length + 1 - }; - } - - getAddName(type, treeTableArray) { - let name = ""; - const namePrefix = type === 'node'? 'New_Variable_' : 'New_Folder_'; - const arr = treeTableArray; - const newDataArr = highPerformanceFilter(arr, item => { - if(item.name.includes(namePrefix)) {return item;} - }); - if(newDataArr.length > 0) { - const newDataNumArr = []; - newDataArr.forEach(item => { - newDataNumArr.push(Number(item.name.split('_')[2])); - }); - newDataNumArr.sort((a, b) => { - return a - b; - }); - name = namePrefix + (newDataNumArr[newDataNumArr.length - 1] + 1).toString(); - } else { - name = namePrefix + "1"; - } - return name; - } - - getoperationAddData(type, rowItem, dataObj) { - const parent_node_id = this.getAddParentId(type, rowItem); - if(parent_node_id) { - dataObj.parent_node_id = parent_node_id; - } else { - dataObj.posId = rowItem.node_id; - } - dataObj.by_order = 0; - return dataObj; - } - - getAddParentId(type, rowItem) { - let parent_node_id = ""; - if(type === 'addDataNode' || type === 'addDataFolder') { - parent_node_id = rowItem.node_id; - } else { - if(rowItem.parent_node_id) { - parent_node_id = rowItem.parent_node_id; - } - } - return parent_node_id; - } - - changeOperationAdd(data, treeTableArray) { - const parent_node_id = data.parent_node_id; - let pos; - if(parent_node_id) { - pos = treeTableArray.findIndex((v) => v.node_id === parent_node_id); - } else { - const posId = data.posId; - pos = treeTableArray.findIndex((v) => v.node_id === posId); - } - this.insertData(data, pos, treeTableArray); - } - - insertData(data, pos, treeTableArray) { - if(pos !== -1) { - this.findChild = new FindChild(); - const allChildCol = this.findChild.getAllChildrenOfItem(treeTableArray[pos], treeTableArray); - const childData = distinct(allChildCol, []); - if(childData.length > 0) { - const realPos = pos + childData.length; - if(Array.isArray(data)) { - for(let i=0; i 0) { - copyStatus = 'cut'; - } else { - copyStatus = 'copy'; - } - this.saveCopyNode.push(this.changeCopyNodeName(this.saveCopyClickNode[0], copyStatus)); - this.saveCopyNode = this.saveCopyNode.flat(Infinity); - } - - changeCopyNodeName(rowItem, status) { - const copyRowItem = simDeepClone(rowItem); - if(copyRowItem.node_type) { - let copyRows; - if(this.isAgainCopy) { - copyRows = this.getCopyRows(copyRowItem); - this.saveCopyRowChild = copyRows; - } else { - copyRows = this.saveCopyRowChild; - } - if(status === 'copy') { - const newRows = this.changeCopyDataParent(copyRows); - return newRows; - } else { - copyRows.forEach(arr => { - arr.by_order = 0; - }); - return copyRows; - } - } else { - if(status === 'copy') { - this.changeCopyData(copyRowItem); - } else { - copyRowItem["by_order"] = 0; - } - return copyRowItem; - } - } - - getCopyRows(copyRowItem) { - this.findChild = new FindChild(); - const allChildCol = this.findChild.getAllChildrenOfItem(copyRowItem, this.treeTableArray); - const allChildLen = distinct(allChildCol, []).length; - const slicePos = (this.treeTableArray.findIndex((v) => v.node_id === copyRowItem.node_id)); - const copyRows = simDeepClone(this.treeTableArray.slice(slicePos, slicePos + allChildLen)); - return copyRows; - } - - - changeCopyDataParent(copyRows) { - const newRows = simDeepClone(copyRows); - for(let i=0; i { - if(item.parent_node_id === copyRows[i].node_id) { - newRows[index].parent_node_id = newRows[i].node_id; - } - }); - } - return newRows; - } - - changeCopyData(rowData) { - rowData["id"] = generateId(); - rowData["name"] = this.getCopyName(rowData['name']); - rowData["node_id"] = generateId(); - rowData["by_order"] = 0; - } - - getCopyName(name) { - let newName = name + '_'; - const newDataArr = highPerformanceFilter(this.treeTableArray, item => { - if(item.name.includes(newName)) {return item;} - }); - if(newDataArr.length > 0) { - const newDataNumArr = []; - newDataArr.forEach(arr => { - const numArr = arr.name.split('_'); - let num = Number(numArr[numArr.length - 1]); - if(!num) { - num = 0; - } - newDataNumArr.push(num); - }); - newDataNumArr.sort((a, b) => { - return a - b; - }); - newName = newName + (newDataNumArr[newDataNumArr.length - 1] + 1).toString(); - } else { - newName = newName + '1'; - } - return newName; - } - - pastData(rowItem, status) { - if(this.saveCutNode.length > 0) { - const cutPos = this.treeTableArray.findIndex((v) => v.node_id === this.saveCutNode[0].node_id); - this.findChild = new FindChild(); - const allChildCol = this.findChild.getAllChildrenOfItem(this.treeTableArray[cutPos], this.treeTableArray); - const childData = distinct(allChildCol, []); - for(let i=0; i v.node_id === childData[i].node_id); - if(pos !== -1) { - this.treeTableArray.splice(pos, 1); - } - } - this.spliceArr = this.deleteAllRecord(childData, this.spliceArr); - - this.pastPublicOperation(rowItem, status); - this.saveCopyClickNode = []; - this.copyRowNodeId = ""; - } else { - this.pastPublicOperation(rowItem, status); - } - } - - pastPublicOperation(rowItem, status) { - if(status === 'paste') { - this.pastChangeCopyData(rowItem); - } else { - this.pastToRootChangeCopyData(); - } - } - - pastChangeCopyData(rowItem) { - this.saveCopyNode[0].parent_node_id = rowItem.node_id; - const pos = this.treeTableArray.findIndex((v) => v.node_id === rowItem.node_id); - this.insertData(this.saveCopyNode, pos); - } - - insertData(data, pos) { - if(pos !== -1) { - this.findChild = new FindChild(); - const allChildCol = this.findChild.getAllChildrenOfItem(this.treeTableArray[pos], this.treeTableArray); - const childData = distinct(allChildCol, []); - if(childData.length > 0) { - const realPos = pos + childData.length; - if(Array.isArray(data)) { - for(let i=0; i 0) { - const allChildNodeId = allChild.map(item => item.node_id); - let node_id; - for(let i=0; i -1) { - arr[i].node_id = ""; - } - } - arr = highPerformanceFilter(arr, item => item.node_id !== ""); - } - return arr; - } -} - -// 拖拽 -export class VirtualScrollTreeTableDrop { - findChild: any; - - visibleNodes: any; - itemCount: any; - expandArr: any; - treeTableArray: any; - - onDrop(e: any, visibleNodes, itemCount, treeTableArray, expandArr) { - this.visibleNodes = visibleNodes; - this.itemCount = itemCount; - this.expandArr = expandArr; - this.treeTableArray = treeTableArray; - - const dragFromIndex = e.dragFromIndex; - let dropIndex = e.dropIndex; let realToIndex; - - if(dropIndex < 0) { - dropIndex = 0; - } else if(dropIndex > itemCount) { - dropIndex = itemCount; - } - - if (dropIndex < dragFromIndex) { - dropIndex++; - } - - const realFromIndex = getNodeIndex(e.dragData.node_id, this.treeTableArray); - realToIndex = dropIndex < this.itemCount ? - getNodeIndex(this.visibleNodes[dropIndex].node_id, this.treeTableArray) - : getNodeIndex(this.visibleNodes[dropIndex - 1].node_id, this.treeTableArray); - if (realToIndex > realFromIndex && dropIndex < dragFromIndex) { - realToIndex--; - } - if (realToIndex < realFromIndex && dropIndex > dragFromIndex) { - realToIndex++; - } - const newDropParentNode = this.visibleNodes[dropIndex - 1]; - this.changeNodeInfoByDrop(newDropParentNode, realFromIndex); - - const moveCount = dragFromIndex === dropIndex ? 0 - : !this.visibleNodes[dropIndex] || realToIndex > realFromIndex ? 1 - : getNodeIndex(this.visibleNodes[dropIndex].node_id, this.treeTableArray) - - getNodeIndex(this.visibleNodes[dropIndex - 1].node_id, this.treeTableArray); - const targetIndex = dropIndex < this.itemCount ? realToIndex - moveCount : realToIndex; - this.treeTableArray.splice( - targetIndex, - 0, - realFromIndex === -1 ? e.dragData : this.treeTableArray.splice(realFromIndex, 1)[0] - ); - - return {expandArr: this.expandArr, treeTableArray: this.treeTableArray}; - } - - changeNodeInfoByDrop(newDropParentNode, realFromIndex) { - const findIndex = this.expandArr.findIndex(value => value.node_id === this.treeTableArray[realFromIndex].node_id); - if (!newDropParentNode || !newDropParentNode.parent_node_id) { - this.dropToRoot(findIndex, realFromIndex, newDropParentNode); - } else if (newDropParentNode.parent_node_id) { - this.dropToChild(findIndex, realFromIndex, newDropParentNode); - } - } - - dropToRoot(findIndex, realFromIndex, newDropParentNode) { - if (newDropParentNode?.node_type === 1 && newDropParentNode?.expand) { - this.treeTableArray[realFromIndex].parent_node_id = newDropParentNode.node_id; - findIndex > -1 ? - this.expandArr[findIndex].parent_node_id = newDropParentNode.node_id - : - this.expandArr.push(this.treeTableArray[realFromIndex]); - } else { - if (this.treeTableArray[realFromIndex].parent_node_id) { - delete this.treeTableArray[realFromIndex].parent_node_id; - if (findIndex > -1) { - this.expandArr.splice(findIndex, 1); - } - } - } - } - - dropToChild(findIndex, realFromIndex, newDropParentNode) { - if (newDropParentNode.node_type === 1 && newDropParentNode.expand) { - this.treeTableArray[realFromIndex].parent_node_id = newDropParentNode.node_id; - findIndex > -1 ? - this.expandArr[findIndex].parent_node_id = newDropParentNode.node_id - : - this.expandArr.push(this.treeTableArray[realFromIndex]); - } else { - this.treeTableArray[realFromIndex].parent_node_id = newDropParentNode.parent_node_id; - if (findIndex > -1) { - this.expandArr[findIndex].parent_node_id = newDropParentNode.parent_node_id; - } - } - } -} - -// 搜索 -export class VirtualScrollTreeTableSearch { - beforeSearchTarget: any; - searchRes: Array = []; - searchArr: Array = []; - isSearch = false; - searchKeyArr: Array = []; - parentData: Array = []; - searchAttr: any = {}; - treeTableArray: any; - - search(searchTarget, searchAttr, treeTableArray) { - this.searchAttr = searchAttr; - this.treeTableArray = treeTableArray; - - this.beforeSearchTarget = searchTarget; - this.searchRes = []; - this.searchArr = []; - if (searchTarget) { - this.isSearch = true; - const attr = this.searchAttr.value; - if (this.treeTableArray.length < 100) { - this.getSearchDataLittle(this.treeTableArray, searchTarget, attr); - } else { - this.getSearchData(this.treeTableArray, this.treeTableArray.length, searchTarget, attr); - } - this.searchKeyArr = []; - } else { - this.isSearch = false; - } - - return {beforeSearchTarget: this.beforeSearchTarget, searchRes: this.searchRes, searchArr: this.searchArr, isSearch: this.isSearch}; - } - - getSearchDataLittle(data, searchTarget, attr) { - const lowSearchTarget = searchTarget.toLowerCase(); - if(attr === 'all') { - for(let i=0; i= loopNum) { - i += loopNum; - } else { - i = len; - } - } - } - - sliceToGroupData(data, groupNum, len, num, attr, lowSearchTarget) { - let sliceNum = groupNum; - if (len - num < groupNum) { - sliceNum = 0; - } - const preparationData = this.batchFilterData(data, num, sliceNum, attr, lowSearchTarget); - return preparationData; - } - - batchFilterData(data, num, sliceNum, attr, lowSearchTarget) { - const rtnData = []; - let everySearchData; - if (sliceNum > 0) { - everySearchData = data.slice(num, num + sliceNum); - } else { - everySearchData = data.slice(num); - } - let everySearchDataAttr; - if(attr === 'all') { - everySearchDataAttr = everySearchData.filter( - item => highPerformanceExpandObjectInArray(item, ['name', 'property', 'category', 'description']).join("丅") - ); - } else { - everySearchDataAttr = everySearchData.filter(item => highPerformanceExpandObjectInArray(item, [attr]).join("丅")); - } - const inArr = (JSON.stringify(everySearchDataAttr).toLowerCase()).includes(lowSearchTarget); - rtnData.push(everySearchData, inArr); - return rtnData; - } - - getLastSearchData(lastSearchData, attr, searchTarget, lowSearchTarget) { - let searchRes = []; - if(attr === 'all') { - for (let m = 0; m < lastSearchData.length; m++) { - const searchProper = highPerformanceExpandObjectInArray( - lastSearchData[m], ['name', 'property', 'category', 'description'] - ).join("丅"); - const searchScope = JSON.stringify(searchProper).toLowerCase().includes(lowSearchTarget); - searchRes = this.searchResData(searchTarget, searchScope, lastSearchData[m], searchRes); - } - } else { - for (let m = 0; m < lastSearchData.length; m++) { - const searchProper = highPerformanceExpandObjectInArray(lastSearchData[m], [attr]).join("丅"); - const searchScope = JSON.stringify(searchProper).toLowerCase().includes(lowSearchTarget); - searchRes = this.searchResData(searchTarget, searchScope, lastSearchData[m], searchRes); - } - } - return searchRes; - } - - searchResData(searchTarget, searchScope, data, searchRes?) { - if (searchTarget && searchScope) { - this.getLastSearchParentData(data); - if (this.parentData.length > 0) { - if(searchRes) { - searchRes = [...searchRes, ...this.parentData]; - } else { - this.searchRes = [...this.searchRes, ...this.parentData]; - } - this.parentData = []; - } - if (this.searchKeyArr.indexOf(data.node_id) === -1) { - if(searchRes) { - searchRes.push(data); - } else { - this.searchRes.push(data); - } - this.searchKeyArr.push(data.node_id); - } - } - if(searchRes) { - return searchRes; - } - } - - getLastSearchParentData(data) { - const parent_node_id = data.parent_node_id; - if (parent_node_id) { - const getData = highPerformanceFilter(this.treeTableArray, item => item.node_id === parent_node_id); - if (this.searchKeyArr.indexOf(getData[0].node_id) === -1) { - this.parentData.push(getData[0]); - this.searchKeyArr.push(getData[0].node_id); - } - if (getData[0].parent_node_id) { - this.getLastSearchParentData(getData[0]); - } else { - this.parentData.reverse(); - } - } - } - - calculationDataNum(len) { - const lenStr = len.toString(); - const countNum = lenStr.substr(0, 1); - const remainderNum = lenStr.substr(1, lenStr.length - 1); - let loopNum = '1'; - if (Number(remainderNum) === 0 && Number(countNum) === 1) { - for (let i = 0; i < remainderNum.length - 1; i++) { - loopNum += '0'; - } - } else { - for (let i = 0; i < remainderNum.length; i++) { - loopNum += '0'; - } - } - return Number(loopNum); - } -} diff --git a/devui/data-table/virtualScrollTreeTable.component.html b/devui/data-table/virtualScrollTreeTable.component.html deleted file mode 100644 index c2f2f3cb..00000000 --- a/devui/data-table/virtualScrollTreeTable.component.html +++ /dev/null @@ -1,17 +0,0 @@ -
    -
    - -
    -
    - - -
    -
    diff --git a/devui/data-table/virtualScrollTreeTable.component.scss b/devui/data-table/virtualScrollTreeTable.component.scss deleted file mode 100644 index 169fc1b3..00000000 --- a/devui/data-table/virtualScrollTreeTable.component.scss +++ /dev/null @@ -1,17 +0,0 @@ -.devui-cdk-scroll-container { - position: relative; - - #data-table-virtual-tree-scroll { - width: calc(100% - 3px); - } - - #data-table-virtual-tree { - position: absolute; - z-index: 1; - left: 0; - top: 0; - right: 5px; - bottom: 0; - width: calc(100% - 8px); - } -} diff --git a/devui/data-table/virtualScrollTreeTable.component.ts b/devui/data-table/virtualScrollTreeTable.component.ts deleted file mode 100644 index f87aef83..00000000 --- a/devui/data-table/virtualScrollTreeTable.component.ts +++ /dev/null @@ -1,779 +0,0 @@ -import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; -import { - AfterContentInit, ChangeDetectorRef, Component, ContentChildren, - EventEmitter, Input, OnChanges, OnInit, Output, QueryList, ViewChild -} from '@angular/core'; -import { DataTableComponent } from './data-table.component'; -import { DataTableProperiesInterface } from './dataTableProperties.interface'; -import { DataTableColumnTmplComponent } from './tmpl/data-table-column-tmpl.component'; -import { - distinct, FindChild, highPerformanceFilter, highPerformanceMap, simDeepClone -} from './utils/utils'; -import { - VirtualScrollTreeTableAdd, VirtualScrollTreeTableCopy, - VirtualScrollTreeTableDelete, VirtualScrollTreeTableDrop, VirtualScrollTreeTableSearch -} from './utils/virtualScrollTreeTable.factory'; - -export interface TreeNodeInterface { - key: string; - title: string; - level: number; - parentKey?: string; - expand?: boolean; - isLeaf: boolean; - isDelete?: boolean; - isMatch?: boolean; - _children?: string[]; - [prop: string]: any; -} - -@Component({ - selector: 'd-virtual-scroll-tree-table', - templateUrl: './virtualScrollTreeTable.component.html', - styleUrls: ['./virtualScrollTreeTable.component.scss'] -}) -export class VirtualScrollTreeTableComponent implements OnInit, AfterContentInit, OnChanges { - @ContentChildren(DataTableColumnTmplComponent) columns: QueryList; - @ViewChild('dataTable', { static: true }) dataTable: DataTableComponent; - - @Input() dataSource: any; - @Input() editOption: any; - @Input() showRowIndex = 10; - @Input() dataTableProperties: DataTableProperiesInterface; - - @Output() save = new EventEmitter(); - - virtualScrollTreeTableDelete: any; - virtualScrollTreeTableAdd: any; - virtualScrollTreeTableCopy: any; - virtualScrollTreeTableDrop: any; - virtualScrollTreeTableSearch: any; - - findChild: any; - itemSize = 40; - itemCount = 10; - virtualScrollPadding = ''; - - get initData() { - return highPerformanceFilter(this.treeTableArray, item => !item.parent_node_id); - } - get allTableData() { - return highPerformanceFilter(this.treeTableArray, item => item); - } - get copySearchRes() { - return highPerformanceFilter(this.searchRes, item => item); - } - get dataTableEvent() { - return this.dataTable; - } - isOpenAll = false; - treeTableMap: { [key: string]: TreeNodeInterface } = {}; - treeTableArray: TreeNodeInterface[] = []; - visibleNodes: TreeNodeInterface[] = []; - iconParentOpen: string; - iconParentClose: string; - basicDataSource: any = []; - expandArr: Array = []; - expandClickArr: Array = []; - expandItemKeys: Array = []; - toggledArr: Array = []; - toggledClickArr: Array = []; - toggledItemKeys: Array = []; - countNum: any = 0; - totleItem: Number = 0; - scrollArray: Array = []; - @ViewChild(CdkVirtualScrollViewport) viewPort: CdkVirtualScrollViewport; - - isSearch = false; - searchRes: Array = []; - searchAttr: any = { - name: '全部', - value: 'all' - }; - beforeSearchTarget: any; - parentData: Array = []; - searchKeyArr: Array = []; - searchArr: Array = []; - - itemLevel: any = 1; - peersNum = 0; - - allChildCol: Array = []; - - saveCopyClickNode: any = []; - saveCopyNode: any = []; - copyRowNodeId = ''; - saveCutNode: any = []; - saveCopyRowChild: any = []; - - isAgainCopy = false; - - isDragMove = false; - dragLine: any; - dragMouseTipWidth: any; - - constructor(private ref: ChangeDetectorRef) { } - - ngAfterContentInit() { - this.dataTable.columns = this.columns; - this.dataTable.updateColumns(); - setTimeout(() => { - const dataTableHead = this.dataTable.fixHeaderContainerRefElement.nativeElement.clientHeight; - this.virtualScrollPadding = dataTableHead + 'px'; - }); - } - - ngOnChanges(changes): void { - if(this.dataSource) { - new Promise((resolve, reject) => { - try { - this.basicDataSource = this.dataSource; - this.basicDataSource = simDeepClone(this.basicDataSource); - this.treeTableArray = this.basicDataSource; - this.totleItem = this.treeTableArray.length; - this.countNum = this.initData.length; - this.scrollArray = Array.from(this.initData.keys()); - this.itemCount = this.showRowIndex; - resolve(true); - } catch (error) { - reject(error); - } - }).then(() => { - this.visibleNodes = simDeepClone(this.initData.slice(0, this.itemCount)); - this.visibleNodes.forEach(arr => { - arr.expand = false; - }); - this.getVisibleDataOrder(this.visibleNodes); - this.getVisibleDataLevel(this.visibleNodes); - }); - } else { - this.treeTableArray = []; - this.visibleNodes = []; - } - - if ( - (changes['dataTableProperties']) - ) { - const params = changes['dataTableProperties']['currentValue']; - this.copyAttribute(this.dataTable, params); - } - } - - ngOnInit() { - this.virtualScrollTreeTableDelete = new VirtualScrollTreeTableDelete(); - this.virtualScrollTreeTableAdd = new VirtualScrollTreeTableAdd(); - this.virtualScrollTreeTableCopy = new VirtualScrollTreeTableCopy(); - this.virtualScrollTreeTableDrop = new VirtualScrollTreeTableDrop(); - this.virtualScrollTreeTableSearch = new VirtualScrollTreeTableSearch(); - this.findChild = new FindChild(); - } - - copyAttribute(target, updateParams) { - if(!target) {return;} - const updateKeys = Object.keys(updateParams); - if(updateKeys.length) { - updateKeys.forEach(key => { - if(key === 'size') { - if(updateParams[key] === 'md') { - this.itemSize = 48; - } else if(updateParams[key] === 'lg') { - this.itemSize = 56; - } else { - this.itemSize = 40; - } - } - target[key] = updateParams[key]; - }); - } - } - - batchUpdateTable(key, val) { - const saveArr = this.treeTableArray; - if(saveArr.length) { - highPerformanceMap(saveArr, obj => { - obj[key] = val; - }); - } - this.getVisiableNodes(); - } - - updateRowData(id, key, val) { - for (let i = 0; i < this.visibleNodes.length; i++) { - if(this.visibleNodes[i].node_id === id) { - this.visibleNodes[i][key] = val; - } - } - - const pos = this.treeTableArray.findIndex((v) => v.node_id === id); - if(pos !== -1) { - this.treeTableArray[pos][key] = val; - } - } - - removeAll() { - this.expandArr = []; - this.toggledArr = []; - this.expandClickArr = []; - this.toggledClickArr = []; - this.searchRes = []; - this.searchArr = []; - } - - setScrollLength(countNum) { - this.countNum = countNum; - this.scrollArray = Array.from(new Array(this.countNum).keys()); - } - setVisibleNodes(data, flag) { - this.visibleNodes = simDeepClone(data); - for (let i = 0; i < this.visibleNodes.length; i++) { - this.visibleNodes[i].expand = flag; - } - } - getVisiableNodes() { - const scrollOffset = this.viewPort.measureScrollOffset(); - const firstVisibleIndex = Math.ceil(scrollOffset / this.itemSize); - const originalDataLength = this.treeTableArray.length; - if (this.isSearch) { - if (this.searchArr.length > 0) { - this.setScrollLength(this.searchRes.length - this.searchArr.length); - const newSearchRes = this.assemblyToggledData(this.copySearchRes, this.searchArr); - this.setVisibleNodes(newSearchRes.slice(firstVisibleIndex, firstVisibleIndex + this.itemCount), true); - this.singleExpend(this.searchArr, 'search'); - } else { - this.setScrollLength(this.searchRes.length); - this.setVisibleNodes(this.searchRes.slice(firstVisibleIndex, firstVisibleIndex + this.itemCount), true); - } - } else { - if (this.isOpenAll) { - this.expandArr = []; - this.expandClickArr = []; - if (this.toggledClickArr.length > 0) { - const newTreeTableArray = this.assemblyToggledData(this.allTableData, this.toggledArr); - this.setScrollLength(originalDataLength - this.toggledArr.length); - this.setVisibleNodes(newTreeTableArray.slice(firstVisibleIndex, firstVisibleIndex + this.itemCount), true); - this.singleExpend(this.toggledClickArr, 'away'); - } else { - this.setScrollLength(this.treeTableArray.length); - this.setVisibleNodes(this.treeTableArray.slice(firstVisibleIndex, firstVisibleIndex + this.itemCount), true); - } - } else { - this.toggledArr = []; - this.toggledClickArr = []; - if (this.expandClickArr.length > 0) { - const newInitData = this.assemblyExpandData(this.initData, this.expandArr); - this.setScrollLength(this.initData.length + this.expandArr.length); - this.visibleNodes = simDeepClone(newInitData.slice(firstVisibleIndex, firstVisibleIndex + this.itemCount)); - this.singleToggled(); - } else { - this.setScrollLength(this.initData.length); - this.setVisibleNodes(this.initData.slice(firstVisibleIndex, firstVisibleIndex + this.itemCount), false); - } - } - } - - this.getVisibleDataOrder(this.visibleNodes); - this.getVisibleDataLevel(this.visibleNodes); - this.dataTable.cancelEditingStatus(); - } - - getVisibleDataOrder(visibleNodes) { - for (let i = 0; i < visibleNodes.length; i++) { - const index = this.treeTableArray.findIndex((v) => v.node_id === visibleNodes[i].node_id); - visibleNodes[i].by_order = index + 1; - } - } - - getVisibleDataLevel(visibleNodes) { - visibleNodes.forEach(arr => { - this.itemLevel = 1; - if (arr.parent_node_id) { - this.getParentNodeLevel(arr.parent_node_id, 1); - arr.level = this.itemLevel; - } else { - arr.level = 1; - } - }); - } - - getParentNodeLevel(parent_node_id, level) { - this.itemLevel = level + 1; - const data: any = highPerformanceFilter(this.treeTableArray, item => item.node_id === parent_node_id); - if (data.length > 0) { - this.getParentNodeLevel(data[0].parent_node_id, this.itemLevel); - } - } - - singleExpend(recordArr, status) { - const keyArr = []; - for (let i = 0; i < recordArr.length; i++) { - if (status === 'search') { - keyArr.push(recordArr[i].parent_node_id); - } else { - keyArr.push(recordArr[i].node_id); - } - } - for (let i = 0; i < this.visibleNodes.length; i++) { - if (keyArr.includes(this.visibleNodes[i].node_id)) { this.visibleNodes[i].expand = false; } - } - } - - singleToggled() { - const visibleNodesKeys = this.visibleNodes.map(item => item.node_id); - let node_id; - for (let i = 0; i < this.expandClickArr.length; i++) { - node_id = this.expandClickArr[i].node_id; - if (node_id && visibleNodesKeys.indexOf(node_id) > -1) { - this.visibleNodes.filter(o => o.node_id === node_id)[0].expand = true; - } - } - } - - assemblyExpandData(InitData, expandArr) { - const newExpandArr = []; - let parent_node_id; - for (let i = 0; i < expandArr.length; i++) { - parent_node_id = expandArr[i].parent_node_id; - const pos = InitData.findIndex((v) => v.node_id === parent_node_id); - if (pos !== -1) { - this.getPeersDataNum(InitData, pos, parent_node_id); - const realDataPos = this.treeTableArray.findIndex((v) => v.node_id === expandArr[i].node_id); - if (realDataPos !== -1) { - const realExpandData = this.treeTableArray[realDataPos]; - InitData.splice(pos + 1 + this.peersNum, 0, realExpandData); - this.peersNum = 0; - } - } else { - newExpandArr.push(expandArr[i]); - } - } - if (newExpandArr.length > 0) { - this.assemblyExpandData(InitData, newExpandArr); - } else { - return InitData; - } - } - - getPeersDataNum(InitData, pos, parent_node_id) { - const checkDataPos = pos + 1; - if (InitData[checkDataPos]) { - const checkDataParent = InitData[checkDataPos].parent_node_id; - if (checkDataParent === parent_node_id) { - this.peersNum++; - this.getPeersDataNum(InitData, checkDataPos, parent_node_id); - } else { - return; - } - } else { - return; - } - } - - assemblyToggledData(arrayData, toggledArr) { - let node_id; - for (let i = 0; i < toggledArr.length; i++) { - node_id = toggledArr[i].node_id; - const pos = arrayData.findIndex((v) => v.node_id === node_id); - if (pos !== -1) { - arrayData.splice(pos, 1); - } - } - return arrayData; - } - - scroll(e) { - e.preventDefault(); - const event = e; - const wheelDelta = event.wheelDelta; - const step = (wheelDelta === 0 ? 0 : wheelDelta / Math.abs(wheelDelta)) * (-this.itemSize); - document.getElementById('data-table-virtual-tree-scroll').scrollBy(0, step); - } - onBodyScroll() { - this.getVisiableNodes(); - } - toggleAllNodesExpand(e) { - this.isOpenAll = e; - this.getVisiableNodes(); - } - - - toggleNodeExpand(node: TreeNodeInterface, $event: boolean, isRefresh = true): void { - if (this.isSearch) { - this.operationSearchArr(node, $event ? 'add' : 'del'); - } else { - this.isOpenAll ? this.operationToggledArr(node, $event ? 'add' : 'del') : this.operationExpandArr(node, $event ? 'add' : 'del'); - } - isRefresh && this.getVisiableNodes(); - - if (!node.expand && node.node_id === this.visibleNodes[this.visibleNodes.length - 1].node_id) { - this.scrollToLastItem(); - } - } - - scrollToLastItem() { - document.getElementById('data-table-virtual-tree-scroll').scrollBy(0, this.itemSize * (this.itemCount - 1)); - } - - operationSearchArr(node, status) { - if (status === 'add') { - this.publicSingleRecordAdd(node, this.searchArr); - } else { - this.publicSingleRecordDel(node, 'search'); - } - } - - operationExpandArr(node, status) { - if (status === 'add') { - const showNodes = this.findChild.getChildrenOfItem(node, this.treeTableArray); - this.expandArr = distinct(this.expandArr, showNodes); - this.expandClickArr = distinct(this.expandClickArr, [node]); - } else { - const inNodeData = []; - inNodeData.push(node); - this.spliceExpandArrData(inNodeData); - const allChild = this.getAllChildArr(node); - let node_id; - for (let i = 0; i < allChild.length; i++) { - node_id = allChild[i].node_id; - const pos = this.expandClickArr.findIndex((v) => v.node_id === node_id); - if (pos !== -1) { - this.expandClickArr.splice(pos, 1); - } - } - } - } - - spliceExpandArrData(inNodeData) { - let nodeChildData = []; - for (let i = 0; i < inNodeData.length; i++) { - const selectData = this.expandArr.filter(item => { - if (item.parent_node_id === inNodeData[i].node_id) { - return item; - } - }); - nodeChildData = [...nodeChildData, ...selectData]; - } - if (nodeChildData.length > 0) { - for (let i = 0; i < nodeChildData.length; i++) { - const node_id = nodeChildData[i].node_id; - const index = this.expandArr.findIndex((v) => v.node_id === node_id); - this.expandArr.splice(index, 1); - } - this.spliceExpandArrData(nodeChildData); - } else { - return; - } - } - - operationToggledArr(node, status) { - if (status === 'add') { - this.publicSingleRecordAdd(node, this.toggledArr); - for (let i = 0; i < this.toggledClickArr.length; i++) { - if (node.node_id === this.toggledClickArr[i].node_id) { - this.toggledClickArr.splice(i, 1); - } - } - } else { - this.publicSingleRecordDel(node, 'away'); - const allChild = this.getAllChildArr(node); - this.toggledClickArr = distinct(this.toggledClickArr, allChild); - } - } - - getAllChildArr(node) { - const allChildCol = this.findChild.getAllChildrenOfItem(node, this.treeTableArray); - let allChild = distinct(allChildCol, []); - allChild = allChild.filter(item => item.node_type === 1); - return allChild; - } - - publicSingleRecordAdd(node, recordArr) { - const showNodes = this.findChild.getChildrenOfItem(node, this.treeTableArray); - const toggledArrKey = recordArr.map(item => item.node_id); - let node_id; - for (let i = 0; i < showNodes.length; i++) { - node_id = showNodes[i].node_id; - if (node_id && toggledArrKey.indexOf(node_id) > -1) { - const index = recordArr.findIndex((v) => v.node_id === node_id); - recordArr.splice(index, 1); - } - } - } - - publicSingleRecordDel(node, status) { - const inNodeData = []; - inNodeData.push(node); - this.spliceToggledArrData(inNodeData, status); - } - - spliceToggledArrData(inNodeData, status) { - let nodeChild = []; - for (let i = 0; i < inNodeData.length; i++) { - const inNodeDataChild = this.findChild.getChildrenOfItem(inNodeData[i], this.treeTableArray); - if (status === 'away') { - nodeChild = this.toggledArrChange(inNodeDataChild, nodeChild); - } else { - nodeChild = this.searchArrChange(inNodeDataChild, nodeChild); - } - } - - if (nodeChild.length > 0) { - this.spliceToggledArrData(nodeChild, status); - } else { - return; - } - } - - toggledArrChange(inNodeDataChild, nodeChild) { - this.toggledArr = distinct(this.toggledArr, inNodeDataChild); - nodeChild = this.getNodeChild(inNodeDataChild, nodeChild); - return nodeChild; - } - - searchArrChange(inNodeDataChild, nodeChild) { - const searchNode = []; - for (let k = 0; k < inNodeDataChild.length; k++) { - const node_id = inNodeDataChild[k].node_id; - const pos = this.searchRes.findIndex((v) => v.node_id === node_id); - if (pos !== -1) { - searchNode.push(inNodeDataChild[k]); - } - } - this.searchArr = distinct(this.searchArr, searchNode); - nodeChild = this.getNodeChild(searchNode, nodeChild); - return nodeChild; - } - - getNodeChild(childData, nodeChild) { - for (let k = 0; k < childData.length; k++) { - if (childData[k].node_type) { - nodeChild.push(childData[k]); - } - } - return nodeChild; - } - - beforeEditStart = (rowItem, field) => { - return true; - }; - - beforeEditEnd = (rowItem, field) => { - return rowItem && rowItem[field].length >= 3; - }; - - onEditEnd(rowItem, field) { - const cloneRow = simDeepClone(rowItem); - - const editSelectField = []; - Object.keys(this.editOption).forEach(arr => { - editSelectField.push(arr + 'Edit'); - }); - - if (editSelectField.includes(field)) { - this.dataTable.cancelEditingStatus(); - } - - const treeTablePos = this.treeTableArray.findIndex((v) => v.node_id === cloneRow.node_id); - this.treeTableArray.splice(treeTablePos, 1, cloneRow); - } - - searchSelectChange() { - this.search(this.beforeSearchTarget); - } - - search(searchTarget) { - const res = this.virtualScrollTreeTableSearch.search(searchTarget, this.searchAttr, this.treeTableArray); - this.beforeSearchTarget = res.beforeSearchTarget; - this.searchRes = res.searchRes; - this.searchArr = res.searchArr; - this.isSearch = res.isSearch; - this.getVisiableNodes(); - } - - addGolbal(status, addTemplate?) { - event.stopPropagation(); - if(addTemplate) { - this.treeTableArray = this.virtualScrollTreeTableAdd.addGolbal(status, this.treeTableArray, addTemplate); - } else { - this.treeTableArray = this.virtualScrollTreeTableAdd.addGolbal(status, this.treeTableArray); - } - this.getVisiableNodes(); - setTimeout(() => { - this.addAutoScroll(); - }); - } - - addOperation(rowItem, status, addTemplate?) { - if(addTemplate) { - this.treeTableArray = this.virtualScrollTreeTableAdd.addOperation(rowItem, status, this.treeTableArray, addTemplate); - } else { - this.treeTableArray = this.virtualScrollTreeTableAdd.addOperation(rowItem, status, this.treeTableArray); - } - this.getVisiableNodes(); - - if (!this.isOpenAll) { - const changeStatus = (status === 'addDataFolder' || status === 'addDataNode') ? 'add' : 'insert'; - this.againExpandNode(changeStatus, rowItem); - } - } - - againExpandNode(changeStatus, rowItem) { - let recordExpNode = []; - if (changeStatus === 'add') { - recordExpNode = this.recordExpandChild(rowItem); - this.changeSingleExpand(rowItem); - } else { - const parent_node_id = rowItem.parent_node_id; - if (parent_node_id) { - const pos = this.treeTableArray.findIndex((v) => v.node_id === parent_node_id); - recordExpNode = this.recordExpandChild(this.treeTableArray[pos]); - this.changeSingleExpand(this.treeTableArray[pos]); - } - } - - for (let i = 0; i < recordExpNode.length; i++) { - this.toggleNodeExpand(recordExpNode[i], true); - } - } - - changeSingleExpand(row) { - this.toggleNodeExpand(row, false); - this.toggleNodeExpand(row, true); - } - - recordExpandChild(row) { - const recordExpNode = []; - const allChildCol = this.findChild.getAllChildrenOfItem(row, this.treeTableArray); - const allChild = highPerformanceFilter(distinct(allChildCol, []), item => (item.node_id !== row.node_id && item.node_type)); - const allChildNodeId = allChild.map(item => item.node_id); - for (let i = 0; i < this.expandClickArr.length; i++) { - const node_id = this.expandClickArr[i].node_id; - if (node_id && allChildNodeId.indexOf(node_id) > -1) { - recordExpNode.push(this.expandClickArr[i]); - } - } - return recordExpNode; - } - - addAutoScroll() { - document.getElementById('data-table-virtual-tree-scroll').scrollTo(0, (this.itemSize * this.scrollArray.length)); - } - - copyAndCut(rowItem, status) { - this.saveCopyClickNode = []; - this.saveCutNode = []; - const res = this.virtualScrollTreeTableCopy.copyAndCut(rowItem, status); - this.saveCopyClickNode = res.saveCopyClickNode; - this.saveCutNode = res.saveCutNode; - this.copyRowNodeId = res.copyRowNodeId; - } - - paste(rowItem, status) { - const spliceArr = { - expandArr: this.expandArr, - toggledArr: this.toggledArr, - expandClickArr: this.expandClickArr, - toggledClickArr: this.toggledClickArr, - searchRes: this.searchRes, - searchArr: this.searchArr - }; - - const res = this.virtualScrollTreeTableCopy.paste(rowItem, status, this.treeTableArray, spliceArr); - this.saveCopyClickNode = res.saveCopyClickNode; - this.copyRowNodeId = res.copyRowNodeId; - this.treeTableArray = res.treeTableArray; - - if (this.saveCutNode.length > 0) { - this.expandArr = res.spliceArr.expandArr; - this.toggledArr = res.spliceArr.toggledArr; - this.expandClickArr = res.spliceArr.expandClickArr; - this.toggledClickArr = res.spliceArr.toggledClickArr; - this.searchRes = res.spliceArr.searchRes; - this.searchArr = res.spliceArr.searchArr; - } - - this.getVisiableNodes(); - if (status === 'paste') { - this.changeSingleExpand(rowItem); - } else { - setTimeout(() => { - this.addAutoScroll(); - }); - } - } - - delete(rowItem) { - const spliceArr = { - expandArr: this.expandArr, - toggledArr: this.toggledArr, - expandClickArr: this.expandClickArr, - toggledClickArr: this.toggledClickArr, - searchRes: this.searchRes, - searchArr: this.searchArr - }; - const res = this.virtualScrollTreeTableDelete.delete(rowItem, this.treeTableArray, spliceArr); - this.treeTableArray = res.treeTableArray; - this.expandArr = res.spliceArr.expandArr; - this.toggledArr = res.spliceArr.toggledArr; - this.expandClickArr = res.spliceArr.expandClickArr; - this.toggledClickArr = res.spliceArr.toggledClickArr; - this.searchRes = res.spliceArr.searchRes; - this.searchArr = res.spliceArr.searchArr; - this.getVisiableNodes(); - } - - onDragOver(e: any) { - const scrollBoxY = document.getElementById('data-table-virtual-tree-scroll').getBoundingClientRect().y; - if (scrollBoxY - e.y > 0) { - document.getElementById('data-table-virtual-tree-scroll').scrollBy(0, -this.itemSize); - } - if (e.y - scrollBoxY > this.itemSize * (this.itemCount - 1) - 10) { - document.getElementById('data-table-virtual-tree-scroll').scrollBy(0, this.itemSize); - } - } - - onDrop(e: any) { - const res = this.virtualScrollTreeTableDrop.onDrop(e, this.visibleNodes, this.itemCount, this.treeTableArray, this.expandArr); - this.expandArr = res.expandArr; - this.treeTableArray = res.treeTableArray; - - const newDropParentNode = this.visibleNodes[e.dropIndex - 1]; - if (!newDropParentNode || !newDropParentNode.parent_node_id) { - if (newDropParentNode ?.node_type === 1 && newDropParentNode ?.expand) { - this.dropUpdateExpandFolder(newDropParentNode, true); - } else { - this.getVisiableNodes(); - } - } else if (newDropParentNode.parent_node_id) { - if (newDropParentNode.node_type === 1 && newDropParentNode.expand) { - this.dropUpdateExpandFolder(newDropParentNode, true); - } else { - this.dropUpdateExpandFolder(newDropParentNode, false); - } - } - } - - dropUpdateExpandFolder(newDropParentNode, isParent) { - setTimeout(() => { - let recordExpNode = []; - if (!isParent) { - const parent_node_id = newDropParentNode.parent_node_id; - if (parent_node_id) { - const pos = this.treeTableArray.findIndex((v) => v.node_id === parent_node_id); - recordExpNode = this.recordExpandChild(this.treeTableArray[pos]); - this.changeSingleExpand(this.treeTableArray[pos]); - } - } else { - recordExpNode = this.recordExpandChild(newDropParentNode); - this.changeSingleExpand(newDropParentNode); - } - - for (let i = 0; i < recordExpNode.length; i++) { - this.toggleNodeExpand(recordExpNode[i], true); - } - }); - } - - saveBtn() { - this.save.emit(this.treeTableArray); - } -} diff --git a/devui/datepicker-pro/datepicker-pro-calendar.component.html b/devui/datepicker-pro/datepicker-pro-calendar.component.html index 9f038e52..8c5cb690 100644 --- a/devui/datepicker-pro/datepicker-pro-calendar.component.html +++ b/devui/datepicker-pro/datepicker-pro-calendar.component.html @@ -1,4 +1,4 @@ -
    +
    -
    +
    ; @ContentChild('footerTemplate') footerTemplate: TemplateRef; @ContentChild('hostTemplate') hostTemplate: TemplateRef; + @ContentChild('markDateInfoTemplate') set markDateInfoTemplate(tmp: TemplateRef) { + this.pickerSrv.markDateInfoTemplate = tmp; + }; @ViewChild('dateInput') datepickerInput: ElementRef; private i18nLocale: I18nInterface['locale']; @@ -224,12 +233,12 @@ export class DatepickerProComponent implements OnInit, AfterViewInit, OnDestroy, return this.datepickerConvert.format(date, this.curFormat); } - clear(event?: MouseEvent) { + clear(event?: MouseEvent, isHandle?: boolean) { if (event) { event.stopPropagation(); } - if (this.disabled) { + if (this.disabled && isHandle) { return; } this.pickerSrv.updateDateValue.next({ diff --git a/devui/datepicker-pro/datepicker-pro.module.ts b/devui/datepicker-pro/datepicker-pro.module.ts index eac31c28..ff67915a 100644 --- a/devui/datepicker-pro/datepicker-pro.module.ts +++ b/devui/datepicker-pro/datepicker-pro.module.ts @@ -4,6 +4,7 @@ import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { ButtonModule } from 'ng-devui/button'; import { DropDownModule } from 'ng-devui/dropdown'; +import { PopoverModule } from 'ng-devui/popover'; import { DatepickerPanelComponent } from './datepicker-panel.component'; import { DatepickerProCalendarComponent } from './datepicker-pro-calendar.component'; import { DatepickerProComponent } from './datepicker-pro.component'; @@ -21,7 +22,8 @@ import { RangeDatepickerProComponent } from './range-datepicker-pro.component'; FormsModule, DropDownModule, ScrollingModule, - ButtonModule + ButtonModule, + PopoverModule ], exports: [ DatepickerProComponent, diff --git a/devui/datepicker-pro/datepicker-pro.service.ts b/devui/datepicker-pro/datepicker-pro.service.ts index 4a29debc..ced2a3c9 100644 --- a/devui/datepicker-pro/datepicker-pro.service.ts +++ b/devui/datepicker-pro/datepicker-pro.service.ts @@ -1,5 +1,5 @@ import { DOCUMENT } from '@angular/common'; -import { Inject, Injectable, OnDestroy } from '@angular/core'; +import { Inject, Injectable, OnDestroy, TemplateRef } from '@angular/core'; import { Subject } from 'rxjs'; @Injectable() @@ -9,6 +9,9 @@ export class DatepickerProService implements OnDestroy { curHoverDate: Date; startIndexOfWeek: number; isRange: boolean; + markedRangeDateList: Date[][]; + markDateInfoTemplate: TemplateRef; + markedDateList: Date[]; showTime: boolean; calendarRange = [1970, 2099]; currentActiveInput: 'start' | 'end' = 'start'; @@ -218,6 +221,37 @@ export class DatepickerProService implements OnDestroy { } } + isInSuggestList(date: Date): boolean { + if (!this.markedRangeDateList) { + return false; + } + + for (let index = 0; index < this.markedRangeDateList.length; index++) { + const range = this.markedRangeDateList[index]; + if ( + range[0]?.getTime() < date.getTime() && range[1]?.getTime() > date.getTime() + ) { + return true; + } + + if ( + range[0]?.toDateString() === date.toDateString() || range[1]?.toDateString() === date.toDateString() + ) { + return true; + } + } + return false; + } + + isMarkedDate(date: Date): boolean { + for (let index = 0; index < this.markedDateList?.length; index++) { + if (this.markedDateList[index]?.toDateString() === date.toDateString()) { + return true; + } + } + return false; + } + mearsureStrWidth(str: string): number { const mearsureDom = this.document.createElement('span'); mearsureDom.innerText = str; diff --git a/devui/datepicker-pro/demo/datepicker-pro-demo.component.html b/devui/datepicker-pro/demo/datepicker-pro-demo.component.html index 01567357..33787b2a 100644 --- a/devui/datepicker-pro/demo/datepicker-pro-demo.component.html +++ b/devui/datepicker-pro/demo/datepicker-pro-demo.component.html @@ -7,6 +7,13 @@
    +
    +
    {{ 'components.datepicker-pro.markedTypeDemo.title' | translate }}
    + + + +
    +
    {{ 'components.datepicker-pro.showTimeDemo.title' | translate }}
    diff --git a/devui/datepicker-pro/demo/datepicker-pro-demo.component.ts b/devui/datepicker-pro/demo/datepicker-pro-demo.component.ts index 3e9c8b82..4b9f2b28 100644 --- a/devui/datepicker-pro/demo/datepicker-pro-demo.component.ts +++ b/devui/datepicker-pro/demo/datepicker-pro-demo.component.ts @@ -17,6 +17,11 @@ export class DatepickerProDemoComponent implements OnInit, OnDestroy { { title: 'TS', language: 'typescript', code: require('./show-time/show-time-picker.component.ts?raw') }, ]; + markedTypeSource: Array = [ + { title: 'HTML', language: 'xml', code: require('./marked-type/marked-type.component.html?raw') }, + { title: 'TS', language: 'typescript', code: require('./marked-type/marked-type.component.ts?raw') }, + ]; + templateSource: Array = [ { title: 'HTML', language: 'xml', code: require('./template/datepicker-template.component.html?raw') }, { title: 'SCSS', language: 'css', code: require('./template/datepicker-template.component.scss?raw') }, @@ -83,6 +88,7 @@ export class DatepickerProDemoComponent implements OnInit, OnDestroy { setNavValues(values) { this.navItems = [ { dAnchorLink: 'basic-usage', value: values['basic-usage'] }, + { dAnchorLink: 'date-marked', value: values['mark-type'] }, { dAnchorLink: 'show-time', value: values['show-time'] }, { dAnchorLink: 'template', value: values['template'] }, { dAnchorLink: 'monthYear', value: values['monthYear'] }, diff --git a/devui/datepicker-pro/demo/datepicker-pro-demo.module.ts b/devui/datepicker-pro/demo/datepicker-pro-demo.module.ts index ee02b5f3..ad9785e7 100644 --- a/devui/datepicker-pro/demo/datepicker-pro-demo.module.ts +++ b/devui/datepicker-pro/demo/datepicker-pro-demo.module.ts @@ -18,6 +18,7 @@ import { DDemoNavModule } from 'src/app/component/d-demo-nav.module'; import { BasicDatepickerProComponent } from './basic/basic-datepicker-pro.component'; import { DatepickerProDemoComponent } from './datepicker-pro-demo.component'; import { DatepickerProHostComponent } from './host-template/datepicker-host-template.component'; +import { MarkedTypeDemoComponent } from './marked-type/marked-type.component'; import { MonthYearDatepickerProComponent } from './month-year-picker/month-year-picker.component'; import { RangeTemplatePickerComponent } from './range-template/range-template.component'; import { RangeTypepickerProComponent } from './range-type/range-type-picker.component'; @@ -68,7 +69,8 @@ import { DatepickerProTemplateComponent } from './template/datepicker-template.c RangeTemplatePickerComponent, DatepickerProStaticPanelComponent, SelectDatepickerDemoComponent, - DatepickerProTabTypeComponent + DatepickerProTabTypeComponent, + MarkedTypeDemoComponent ], providers: [], diff --git a/devui/datepicker-pro/demo/marked-type/marked-type.component.html b/devui/datepicker-pro/demo/marked-type/marked-type.component.html new file mode 100644 index 00000000..ea62d120 --- /dev/null +++ b/devui/datepicker-pro/demo/marked-type/marked-type.component.html @@ -0,0 +1,16 @@ + + + + 标记点起始日期信息 + + + 标记点结束日期信息 + + + diff --git a/devui/datepicker-pro/demo/marked-type/marked-type.component.ts b/devui/datepicker-pro/demo/marked-type/marked-type.component.ts new file mode 100644 index 00000000..98aaa991 --- /dev/null +++ b/devui/datepicker-pro/demo/marked-type/marked-type.component.ts @@ -0,0 +1,22 @@ +import { + Component +} from '@angular/core'; + +@Component({ + selector: 'd-marked-type-demo', + templateUrl: './marked-type.component.html', +}) +export class MarkedTypeDemoComponent { + value = new Date('2021/11/01'); + list = [new Date('2021/11/01'), new Date('2021/11/10')]; + markRange = [[new Date('2021/11/01'), new Date('2021/11/10')]]; + + onChange(date) { + console.log(date); + } + + isStart(date: Date) { + return date.toDateString() === new Date('2021/11/01').toDateString(); + } + +} diff --git a/devui/datepicker-pro/demo/static-panel/datepicker-pro-static-panel.component.html b/devui/datepicker-pro/demo/static-panel/datepicker-pro-static-panel.component.html index 8e93b4e8..cca16192 100644 --- a/devui/datepicker-pro/demo/static-panel/datepicker-pro-static-panel.component.html +++ b/devui/datepicker-pro/demo/static-panel/datepicker-pro-static-panel.component.html @@ -1,5 +1,5 @@

    single calendar panel

    - +
    diff --git a/devui/datepicker-pro/demo/tab-type/datepicker-pro-tab-type.component.html b/devui/datepicker-pro/demo/tab-type/datepicker-pro-tab-type.component.html index 58fbeac2..b36b1a87 100644 --- a/devui/datepicker-pro/demo/tab-type/datepicker-pro-tab-type.component.html +++ b/devui/datepicker-pro/demo/tab-type/datepicker-pro-tab-type.component.html @@ -15,42 +15,36 @@
    - - -
    - - -
    -
    + +
    + + +
    - - - - - + + + - - -
    - last: - - -
    - -
    + +
    + last: + - Ensure +
    +
    - + + Ensure +
    diff --git a/devui/datepicker-pro/doc/api-cn.md b/devui/datepicker-pro/doc/api-cn.md index faf29dec..afbf0282 100644 --- a/devui/datepicker-pro/doc/api-cn.md +++ b/devui/datepicker-pro/doc/api-cn.md @@ -28,6 +28,8 @@ import { DatepickerProModule } from 'ng-devui/datepicker-pro'; | showAnimation | `boolean` | true | 可选,是否开启动画 | | | width | `string` | - | 可设置选择器的宽度 | | | mode | `'year' \| 'month' \| 'date'` | 'date' | 面板模式 | [年月选择器](demo#monthYear)| +| markedDateList | `Date[]` | [] | 标记日期列表,可以配合MarkDateInfoTemplate模板展示提示信息 | [标记信息](demo#date-marked)| +| markedRangeDateList | `Date[][]` | [] | 标记范围日期列表 | [标记信息](demo#date-marked)| ## d-datepicker-pro 事件 @@ -55,6 +57,8 @@ import { DatepickerProModule } from 'ng-devui/datepicker-pro'; | width | `string` | - | 可设置范围选择器的宽度 | | | mode | `'year' \| 'month' \| 'date' \| 'week'` | 'date' | 面板模式 | [范围选择器](demo#range-picker)| | startIndexOfWeek | `number` | 0 | 周选择时候,每周的开始时间,0表示周日,6表示周六,与Date.getDay()相同 | [范围选择器](demo#range-picker)| +| markedDateList | `Date[]` | [] | 标记日期列表,可以配合MarkDateInfoTemplate模板展示提示信息 | [标记信息](demo#date-marked)| +| markedRangeDateList | `Date[][]` | [] | 标记范围日期列表 | [标记信息](demo#date-marked)| ## d-range-datepicker-pro 事件 @@ -75,6 +79,8 @@ import { DatepickerProModule } from 'ng-devui/datepicker-pro'; | activeRangeType | `'start' \| 'end'` | 'start' | 可选,范围模式下激活开始或者结束日期 | | | showRangeHeader | `boolean` | 'true' | 可选,在范围模式下是否显示header头来展示范围切换的input | | | splitter | `string` | '-' | 可选,在范围模式下的日期分隔符 | | +| markedDateList | `Date[]` | [] | 标记日期列表,可以配合MarkDateInfoTemplate模板展示提示信息 | [标记信息](demo#date-marked)| +| markedRangeDateList | `Date[][]` | [] | 标记范围日期列表 | [标记信息](demo#date-marked)| ## d-datepicker-static-panel 事件 @@ -98,3 +104,4 @@ ngModelChange 可监听其变化。 | customTemplate | `TemplateRef` | -- | 可选,右侧区域自定义模板 | [传入模板](demo#template) | | footerTemplate | `TemplateRef` | -- | 可选,footer自定义模板 | [传入模板](demo#template) | | hostTemplate | `TemplateRef` | -- | 可选,datepicker宿主的自定义模板 | [传入模板](demo#host-template) | +| markDateInfoTemplate | `TemplateRef` | -- | 可选,标记日期的提示信息模板,信息会以popover展示 | [标记信息](demo#date-marked) | diff --git a/devui/datepicker-pro/doc/api-en.md b/devui/datepicker-pro/doc/api-en.md index 12dc3e42..0cffe1d7 100644 --- a/devui/datepicker-pro/doc/api-en.md +++ b/devui/datepicker-pro/doc/api-en.md @@ -28,6 +28,8 @@ In the page: | showAnimation | `boolean` | true | (optional) Whether to enable animation | | | width | `string` | - | Width of the selector. | | | mode | `'year' \| 'month' \| 'date'` | 'date' | panel mode | [year and month selector](demo#monthYear)| +| markedDateList | `Date[]` | [] | Marked date list, which can be used with the MarkDateInfoTemplate template to display prompt information | [mark information](demo#date-marked)| +| markedRangeDateList | `Date[][]` | [] | Marking Range Date List|[Marking Information](demo#date-marked)| ## d-datepicker-pro event @@ -55,6 +57,8 @@ Triggered when the | dropdownToggle | `EventEmitter` | -- | drop-down p | width | `string` | - | Width of the range selector. | | | mode | `year' \| 'month' \| 'date'\| 'week'`| 'date' | panel mode | [range selector](demo#range-picker)| | startIndexOfWeek | `number` | 0 |: start time of a week. 0 indicates Sunday and 6 indicates Saturday, which is the same as Date.getDay().|[range selector](demo#range-picker)| +| markedDateList | `Date[]` | [] | Marked date list, which can be used with the MarkDateInfoTemplate template to display prompt information | [mark information](demo#date-marked)| +| markedRangeDateList | `Date[][]` | [] | Marking Range Date List|[Marking Information](demo#date-marked)| ## d-range-datepicker-pro event @@ -75,6 +79,8 @@ Triggered when the | dropdownToggle | `EventEmitter` | -- | drop-down p | activeRangeType | `start' \| 'end'`|'start' | Optional. Activation start or end date in range mode | | | showRangeHeader | `boolean` | 'true' | Indicates whether to display the header to display the input of range switching in range mode. | | | Splitter | `string` | '-' | Optional, date separator in range mode | | +| markedDateList | `Date[]` | [] | Marked date list, which can be used with the MarkDateInfoTemplate template to display prompt information | [mark information](demo#date-marked)| +| markedRangeDateList | `Date[][]` | [] | Marking Range Date List|[Marking Information](demo#date-marked)| ## d-datepicker-static-panel event @@ -97,3 +103,4 @@ ngModelChange can listen to the change. | customTemplate | `TemplateRef` | -- |: optional. Customize a template in the right pane. | [Input template](demo#template) | | footerTemplate | `TemplateRef` | -- |: optional. Footer customized template | [Input template](demo#template) | | hostTemplate | `TemplateRef` | -- | Optional. Custom template of the datepicker host | [Incoming template] (demo#host-template) | +| markDateInfoTemplate | `TemplateRef` | -- | Optional, Template for marking date prompt information. The information is displayed in popover format.|[mark information](demo#date-marked)| diff --git a/devui/datepicker-pro/lib/calendar-panel.component.html b/devui/datepicker-pro/lib/calendar-panel.component.html index f513dd9c..8ed0ccb1 100644 --- a/devui/datepicker-pro/lib/calendar-panel.component.html +++ b/devui/datepicker-pro/lib/calendar-panel.component.html @@ -52,13 +52,21 @@ 'devui-table-date-start': isStartDate(day.date), 'devui-table-date-end': isEndDate(day.date), 'devui-table-date-in-selected-range': isDateInSelectRange(day.date), - 'devui-table-date-active-type': isActiveTypeDate(day.date) + 'devui-table-date-active-type': isActiveTypeDate(day.date), + 'devui-table-date-suggested': isDateSuggest(day.date), + 'devui-table-date-marked': isDateMarked(day.date) }" *ngFor="let day of week" + dPopover + [content]="markDate" + [visible]="isPopoverShow(day)" (click)="selectDate(day)" (mouseenter)="setHoverTarget(day.date, day.inMonth)" > {{ day.inMonth ? day.day : '' }} + + +
    {{ 'components.design-color.colorDemo.instance.defaultTable.colorVar' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.normalColor' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.darkColor' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.themeValue' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.description' | translate }}
    -
    - - -
    -
    {{ rowItem?.name }} -
    - {{ rowItem?.light }} -
    -
    -
    -
    - {{ rowItem?.dark }} -
    -
    -
    -
    - {{ rowItem?.themeValue }} -
    -
    -
    {{ rowItem?.description }}{{ 'components.design-color.colorDemo.instance.defaultTable.colorVar' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.normalColor' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.darkColor' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.themeValue' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.description' | translate }}
    +
    + + +
    +
    {{ rowItem?.name }} +
    + {{ rowItem?.light }} +
    +
    +
    +
    + {{ rowItem?.dark }} +
    +
    +
    +
    + {{ rowItem?.themeValue }} +
    +
    +
    {{ rowItem?.description }}
    {{ 'components.design-color.colorDemo.instance.defaultTable.colorVar' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.normalColor' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.darkColor' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.themeValue' | translate }}{{ 'components.design-color.colorDemo.instance.defaultTable.description' | translate }}
    +
    + + +
    +
    {{ rowItem?.name }} +
    + {{ rowItem?.light }} +
    +
    +
    +
    + {{ rowItem?.dark }} +
    +
    +
    +
    + {{ rowItem?.themeValue }} +
    +
    +
    {{ rowItem?.description }}
    {{ 'components.design-shadow.shadowDemo.instance.colorTable.colorVar' | translate }}{{ 'components.design-shadow.shadowDemo.instance.colorTable.normalColor' | translate }}{{ 'components.design-shadow.shadowDemo.instance.colorTable.darkColor' | translate }}{{ 'components.design-shadow.shadowDemo.instance.colorTable.themeValue' | translate }}{{ 'components.design-shadow.shadowDemo.instance.colorTable.description' | translate }}
    {{ rowItem?.name }} +
    + {{ rowItem?.light }} +
    +
    +
    +
    + {{ rowItem?.dark }} +
    +
    +
    +
    + {{ rowItem?.themeValue }} +
    +
    +
    {{ rowItem?.description }}