@progress/kendo-angular-treelist 13.0.0-develop.2 → 13.0.0-develop.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/binding-directives/base-binding.directive.d.ts +5 -1
  2. package/binding-directives/data-bound-tree-component.d.ts +9 -0
  3. package/binding-directives/flat-binding.directive.d.ts +14 -3
  4. package/binding-directives/hierarchy-binding.directive.d.ts +12 -3
  5. package/columns/column-base.d.ts +4 -0
  6. package/columns/rowreorder-column.component.d.ts +19 -0
  7. package/esm2020/binding-directives/base-binding.directive.mjs +9 -3
  8. package/esm2020/binding-directives/flat-binding.directive.mjs +56 -6
  9. package/esm2020/binding-directives/hierarchy-binding.directive.mjs +46 -6
  10. package/esm2020/columns/column-base.mjs +4 -0
  11. package/esm2020/columns/rowreorder-column.component.mjs +47 -0
  12. package/esm2020/index.mjs +2 -0
  13. package/esm2020/localization/messages.mjs +3 -1
  14. package/esm2020/package-metadata.mjs +2 -2
  15. package/esm2020/rendering/cell.component.mjs +47 -16
  16. package/esm2020/rendering/constants.mjs +4 -0
  17. package/esm2020/rendering/table-body.component.mjs +5 -3
  18. package/esm2020/row-reordering/flat-reorder.service.mjs +48 -0
  19. package/esm2020/row-reordering/hierarchical-reorder.service.mjs +55 -0
  20. package/esm2020/row-reordering/row-reorder.service.mjs +220 -0
  21. package/esm2020/row-reordering/types.mjs +5 -0
  22. package/esm2020/row-reordering/utils.mjs +129 -0
  23. package/esm2020/shared.module.mjs +8 -3
  24. package/esm2020/treelist.component.mjs +161 -23
  25. package/esm2020/treelist.module.mjs +71 -66
  26. package/fesm2015/progress-kendo-angular-treelist.mjs +808 -62
  27. package/fesm2020/progress-kendo-angular-treelist.mjs +799 -62
  28. package/index.d.ts +2 -0
  29. package/localization/messages.d.ts +5 -1
  30. package/package.json +16 -15
  31. package/rendering/cell.component.d.ts +6 -1
  32. package/rendering/constants.d.ts +4 -0
  33. package/row-reordering/flat-reorder.service.d.ts +16 -0
  34. package/row-reordering/hierarchical-reorder.service.d.ts +16 -0
  35. package/row-reordering/row-reorder.service.d.ts +61 -0
  36. package/row-reordering/types.d.ts +39 -0
  37. package/row-reordering/utils.d.ts +85 -0
  38. package/schematics/ngAdd/index.js +3 -3
  39. package/shared.module.d.ts +5 -4
  40. package/treelist.component.d.ts +42 -2
  41. package/treelist.module.d.ts +68 -66
@@ -4,34 +4,38 @@
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { Component, HostBinding, Input } from '@angular/core';
6
6
  import { EditService } from '../editing/edit.service';
7
- import { isSpanColumn, isCheckboxColumn } from '../columns/column-base';
7
+ import { isSpanColumn, isCheckboxColumn, isRowReorderColumn } from '../columns/column-base';
8
8
  import { isColumnComponent } from '../columns/column.component';
9
9
  import { columnsToRender } from "../columns/column-common";
10
10
  import { isNullOrEmptyString, extractFormat, isColumnEditable } from '../utils';
11
11
  import { FocusGroup } from '../navigation/focus-group';
12
- import { caretAltDownIcon, caretAltRightIcon } from '@progress/kendo-svg-icons';
12
+ import { caretAltDownIcon, caretAltRightIcon, reorderIcon } from '@progress/kendo-svg-icons';
13
+ import { LocalizationService } from "@progress/kendo-angular-l10n";
13
14
  import * as i0 from "@angular/core";
14
15
  import * as i1 from "../editing/edit.service";
15
- import * as i2 from "../navigation/focus-group";
16
- import * as i3 from "@progress/kendo-angular-icons";
17
- import * as i4 from "@progress/kendo-angular-inputs";
18
- import * as i5 from "@progress/kendo-angular-dateinputs";
19
- import * as i6 from "@angular/common";
20
- import * as i7 from "../navigation/focusable.directive";
21
- import * as i8 from "@angular/forms";
22
- import * as i9 from "./common/level-items.pipe";
23
- import * as i10 from "./common/field-accessor.pipe";
16
+ import * as i2 from "@progress/kendo-angular-l10n";
17
+ import * as i3 from "../navigation/focus-group";
18
+ import * as i4 from "@progress/kendo-angular-icons";
19
+ import * as i5 from "@progress/kendo-angular-inputs";
20
+ import * as i6 from "@progress/kendo-angular-dateinputs";
21
+ import * as i7 from "@angular/common";
22
+ import * as i8 from "../navigation/focusable.directive";
23
+ import * as i9 from "@angular/forms";
24
+ import * as i10 from "./common/level-items.pipe";
25
+ import * as i11 from "./common/field-accessor.pipe";
24
26
  /**
25
27
  * @hidden
26
28
  */
27
29
  export class CellComponent {
28
- constructor(editService, focusGroup) {
30
+ constructor(editService, localization, focusGroup) {
29
31
  this.editService = editService;
32
+ this.localization = localization;
30
33
  this.focusGroup = focusGroup;
31
34
  this.isNew = false;
32
35
  this.level = 0;
33
36
  this.caretAltDownIcon = caretAltDownIcon;
34
37
  this.caretAltRightIcon = caretAltRightIcon;
38
+ this.reorderIcon = reorderIcon;
35
39
  this.cellContext = {};
36
40
  this._templateContext = {};
37
41
  this._editTemplateContext = {};
@@ -47,6 +51,12 @@ export class CellComponent {
47
51
  get textNoWrapClass() {
48
52
  return this.column.expandable;
49
53
  }
54
+ get dragHandleCellClass() {
55
+ return isRowReorderColumn(this.column);
56
+ }
57
+ get dragRowHandleLabel() {
58
+ return isRowReorderColumn(this.column) ? this.localization.get('dragRowHandleLabel') : undefined;
59
+ }
50
60
  set viewItem(value) {
51
61
  this._viewItem = value;
52
62
  this.cellContext.viewItem = this.viewItem;
@@ -114,8 +124,8 @@ export class CellComponent {
114
124
  context.rowIndex = this.viewItem.rowIndex;
115
125
  }
116
126
  }
117
- CellComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: CellComponent, deps: [{ token: i1.EditService }, { token: i2.FocusGroup }], target: i0.ɵɵFactoryTarget.Component });
118
- CellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.12", type: CellComponent, selector: "[kendoTreeListCell]", inputs: { column: "column", columnIndex: "columnIndex", isNew: "isNew", level: "level", hasChildren: "hasChildren", isExpanded: "isExpanded", loading: "loading", expandIcons: "expandIcons", selected: "selected", dataItem: "dataItem", viewItem: "viewItem" }, host: { properties: { "class.k-command-cell": "this.commandCellClass", "class.k-checkbox-cell": "this.isCheckboxColumn", "class.k-text-nowrap": "this.textNoWrapClass" } }, ngImport: i0, template: `
127
+ CellComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: CellComponent, deps: [{ token: i1.EditService }, { token: i2.LocalizationService }, { token: i3.FocusGroup }], target: i0.ɵɵFactoryTarget.Component });
128
+ CellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.12", type: CellComponent, selector: "[kendoTreeListCell]", inputs: { column: "column", columnIndex: "columnIndex", isNew: "isNew", level: "level", hasChildren: "hasChildren", isExpanded: "isExpanded", loading: "loading", expandIcons: "expandIcons", selected: "selected", dataItem: "dataItem", viewItem: "viewItem" }, host: { properties: { "class.k-command-cell": "this.commandCellClass", "class.k-checkbox-cell": "this.isCheckboxColumn", "class.k-text-nowrap": "this.textNoWrapClass", "class.k-drag-cell": "this.dragHandleCellClass", "class.k-touch-action-none": "this.dragHandleCellClass", "attr.aria-label": "this.dragRowHandleLabel" } }, ngImport: i0, template: `
119
129
  <ng-container [ngSwitch]="isEdited">
120
130
  <ng-container *ngSwitchCase="false">
121
131
  <ng-container *ngIf="column.expandable">
@@ -144,6 +154,12 @@ CellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version:
144
154
  class="k-checkbox k-checkbox-md k-rounded-md"
145
155
  [checked]="selected" />
146
156
  </ng-template>
157
+ <ng-container *ngIf="column.isRowReorderColumn && !isNew">
158
+ <kendo-icon-wrapper
159
+ name="reorder"
160
+ [svgIcon]="reorderIcon">
161
+ </kendo-icon-wrapper>
162
+ </ng-container>
147
163
  </ng-container>
148
164
  <ng-container *ngSwitchCase="true">
149
165
  <ng-container
@@ -184,7 +200,7 @@ CellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version:
184
200
  </ng-container>
185
201
  </ng-container>
186
202
  </ng-container>
187
- `, isInline: true, components: [{ type: i3.IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass"], exportAs: ["kendoIconWrapper"] }, { type: i4.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode"], outputs: ["valueChange", "focus", "blur"], exportAs: ["kendoNumericTextBox"] }, { type: i5.DatePickerComponent, selector: "kendo-datepicker", inputs: ["focusableId", "cellTemplate", "monthCellTemplate", "yearCellTemplate", "decadeCellTemplate", "centuryCellTemplate", "weekNumberTemplate", "headerTitleTemplate", "navigationItemTemplate", "activeView", "bottomView", "topView", "calendarType", "animateCalendarNavigation", "disabled", "readonly", "readOnlyInput", "popupSettings", "navigation", "min", "max", "incompleteDateValidation", "focusedDate", "value", "format", "twoDigitYearMax", "formatPlaceholder", "placeholder", "tabindex", "tabIndex", "disabledDates", "title", "subtitle", "rangeValidation", "disabledDatesValidation", "weekNumber", "size", "rounded", "fillMode", "adaptiveMode"], outputs: ["valueChange", "focus", "blur", "open", "close"], exportAs: ["kendo-datepicker"] }], directives: [{ type: i6.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i6.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i7.FocusableDirective, selector: "[kendoTreeListFocusable],\n [kendoTreeListAddCommand],\n [kendoTreeListEditCommand],\n [kendoTreeListRemoveCommand],\n [kendoTreeListSaveCommand],\n [kendoTreeListCancelCommand]\n ", inputs: ["kendoTreeListFocusable", "enabled", "kendoTreeListAddCommand", "kendoTreeListEditCommand", "kendoTreeListRemoveCommand", "kendoTreeListSaveCommand", "kendoTreeListCancelCommand"] }, { type: i8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i8.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i8.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { type: i6.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { type: i8.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }], pipes: { "levelItems": i9.LevelItemsPipe, "valueOf": i10.FieldAccessorPipe } });
203
+ `, isInline: true, components: [{ type: i4.IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass"], exportAs: ["kendoIconWrapper"] }, { type: i5.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode"], outputs: ["valueChange", "focus", "blur"], exportAs: ["kendoNumericTextBox"] }, { type: i6.DatePickerComponent, selector: "kendo-datepicker", inputs: ["focusableId", "cellTemplate", "monthCellTemplate", "yearCellTemplate", "decadeCellTemplate", "centuryCellTemplate", "weekNumberTemplate", "headerTitleTemplate", "navigationItemTemplate", "activeView", "bottomView", "topView", "calendarType", "animateCalendarNavigation", "disabled", "readonly", "readOnlyInput", "popupSettings", "navigation", "min", "max", "incompleteDateValidation", "focusedDate", "value", "format", "twoDigitYearMax", "formatPlaceholder", "placeholder", "tabindex", "tabIndex", "disabledDates", "title", "subtitle", "rangeValidation", "disabledDatesValidation", "weekNumber", "size", "rounded", "fillMode", "adaptiveMode"], outputs: ["valueChange", "focus", "blur", "open", "close"], exportAs: ["kendo-datepicker"] }], directives: [{ type: i7.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i7.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i7.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i8.FocusableDirective, selector: "[kendoTreeListFocusable],\n [kendoTreeListAddCommand],\n [kendoTreeListEditCommand],\n [kendoTreeListRemoveCommand],\n [kendoTreeListSaveCommand],\n [kendoTreeListCancelCommand]\n ", inputs: ["kendoTreeListFocusable", "enabled", "kendoTreeListAddCommand", "kendoTreeListEditCommand", "kendoTreeListRemoveCommand", "kendoTreeListSaveCommand", "kendoTreeListCancelCommand"] }, { type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i9.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i9.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { type: i7.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }], pipes: { "levelItems": i10.LevelItemsPipe, "valueOf": i11.FieldAccessorPipe } });
188
204
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: CellComponent, decorators: [{
189
205
  type: Component,
190
206
  args: [{
@@ -218,6 +234,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
218
234
  class="k-checkbox k-checkbox-md k-rounded-md"
219
235
  [checked]="selected" />
220
236
  </ng-template>
237
+ <ng-container *ngIf="column.isRowReorderColumn && !isNew">
238
+ <kendo-icon-wrapper
239
+ name="reorder"
240
+ [svgIcon]="reorderIcon">
241
+ </kendo-icon-wrapper>
242
+ </ng-container>
221
243
  </ng-container>
222
244
  <ng-container *ngSwitchCase="true">
223
245
  <ng-container
@@ -260,7 +282,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
260
282
  </ng-container>
261
283
  `
262
284
  }]
263
- }], ctorParameters: function () { return [{ type: i1.EditService }, { type: i2.FocusGroup }]; }, propDecorators: { commandCellClass: [{
285
+ }], ctorParameters: function () { return [{ type: i1.EditService }, { type: i2.LocalizationService }, { type: i3.FocusGroup }]; }, propDecorators: { commandCellClass: [{
264
286
  type: HostBinding,
265
287
  args: ['class.k-command-cell']
266
288
  }], isCheckboxColumn: [{
@@ -269,6 +291,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
269
291
  }], textNoWrapClass: [{
270
292
  type: HostBinding,
271
293
  args: ['class.k-text-nowrap']
294
+ }], dragHandleCellClass: [{
295
+ type: HostBinding,
296
+ args: ['class.k-drag-cell']
297
+ }, {
298
+ type: HostBinding,
299
+ args: ['class.k-touch-action-none']
300
+ }], dragRowHandleLabel: [{
301
+ type: HostBinding,
302
+ args: ['attr.aria-label']
272
303
  }], column: [{
273
304
  type: Input
274
305
  }], columnIndex: [{
@@ -22,3 +22,7 @@ export const ICON_CLASS = 'k-icon k-svg-icon';
22
22
  * @hidden
23
23
  */
24
24
  export const IGNORE_CONTAINER_CLASSES = 'k-treelist-ignore-click';
25
+ /**
26
+ * @hidden
27
+ */
28
+ export const DRAG_HANDLE_CLASS = 'k-drag-cell';
@@ -18,7 +18,7 @@ import { Keys } from '@progress/kendo-angular-common';
18
18
  import { defaultTrackBy } from '../common/default-track-by';
19
19
  import { ExpandStateService } from '../expand-state/expand-state.service';
20
20
  import { SelectionService } from '../selection/selection.service';
21
- import { NON_DATA_CELL_CLASSES, NON_DATA_ROW_CLASSES, IGNORE_CONTAINER_CLASSES, ICON_CLASS, EMPTY_ICON_CLASS } from './constants';
21
+ import { NON_DATA_CELL_CLASSES, NON_DATA_ROW_CLASSES, IGNORE_CONTAINER_CLASSES, ICON_CLASS, EMPTY_ICON_CLASS, DRAG_HANDLE_CLASS } from './constants';
22
22
  import * as i0 from "@angular/core";
23
23
  import * as i1 from "../data/change-notification.service";
24
24
  import * as i2 from "../editing/edit.service";
@@ -213,8 +213,10 @@ export class TableBodyComponent {
213
213
  clickHandler(eventArg) {
214
214
  const target = eventArg.target;
215
215
  const { cell, row } = this.targetElements(target);
216
- if (cell && !hasClasses(cell, NON_DATA_CELL_CLASSES) &&
217
- !hasClasses(row, NON_DATA_ROW_CLASSES)) {
216
+ const forbiddenCellClasses = NON_DATA_CELL_CLASSES.concat(` ${DRAG_HANDLE_CLASS}`);
217
+ const isValidCell = cell ? !hasClasses(cell, forbiddenCellClasses) : false;
218
+ const isValidRow = row ? !hasClasses(row, NON_DATA_ROW_CLASSES) : false;
219
+ if (isValidRow && isValidCell) {
218
220
  if (this.expandClick(eventArg, row) || this.checkboxClick(cell, row, eventArg)) {
219
221
  return;
220
222
  }
@@ -0,0 +1,48 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2023 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ import { Injectable } from "@angular/core";
6
+ import { RowReorderService } from './row-reorder.service';
7
+ import { isPresent } from "../utils";
8
+ import * as i0 from "@angular/core";
9
+ /**
10
+ * @hidden
11
+ */
12
+ export class FlatRowReorderService extends RowReorderService {
13
+ isOverChild(targetItem) {
14
+ const { draggedRows } = this.rowReorderArgs(this.dragTarget, this.dropTarget, this.view);
15
+ const draggedItem = draggedRows[0].dataItem;
16
+ const hasParent = isPresent(targetItem[this.parentIdField]);
17
+ const sameParents = draggedItem[this.parentIdField] === targetItem[this.parentIdField];
18
+ if (!hasParent || sameParents) {
19
+ return false;
20
+ }
21
+ if (targetItem && targetItem.hasOwnProperty(this.parentIdField)) {
22
+ if (draggedItem[this.idField] === targetItem[this.parentIdField]) {
23
+ return true;
24
+ }
25
+ const parent = this.data.find(i => i[this.idField] === targetItem[this.parentIdField]);
26
+ if (parent) {
27
+ return this.isOverChild(parent);
28
+ }
29
+ }
30
+ }
31
+ reorderRows(ev, collection) {
32
+ const { draggedRows, dropTargetRow } = ev;
33
+ const draggedDataItem = draggedRows[0].dataItem;
34
+ const dropTargetDataItem = dropTargetRow.dataItem;
35
+ let dropTargetIdx = collection.indexOf(dropTargetDataItem);
36
+ const draggedItemIdx = collection.indexOf(draggedDataItem);
37
+ collection.splice(draggedItemIdx, 1);
38
+ if (ev.dropPosition === 'after' && dropTargetIdx < draggedItemIdx) {
39
+ dropTargetIdx++;
40
+ }
41
+ collection.splice(dropTargetIdx, 0, draggedDataItem);
42
+ }
43
+ }
44
+ FlatRowReorderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: FlatRowReorderService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
45
+ FlatRowReorderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: FlatRowReorderService });
46
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: FlatRowReorderService, decorators: [{
47
+ type: Injectable
48
+ }] });
@@ -0,0 +1,55 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2023 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ import { Injectable } from "@angular/core";
6
+ import { RowReorderService } from './row-reorder.service';
7
+ import { isPresent } from "../utils";
8
+ import { dropPosition, findParent } from "./utils";
9
+ import * as i0 from "@angular/core";
10
+ /**
11
+ * @hidden
12
+ */
13
+ export class HierarchicalRowReorderService extends RowReorderService {
14
+ isOverChild(targetItem) {
15
+ const { draggedRows } = this.rowReorderArgs(this.dragTarget, this.dropTarget, this.view);
16
+ const draggedItem = draggedRows[0].dataItem;
17
+ const hasChildren = isPresent(draggedItem[this.childrenField]) && draggedItem[this.childrenField].length > 0;
18
+ if (!hasChildren) {
19
+ return false;
20
+ }
21
+ if (targetItem && draggedItem.hasOwnProperty(this.childrenField)) {
22
+ if (draggedItem[this.childrenField].includes(targetItem)) {
23
+ return true;
24
+ }
25
+ const parent = findParent(this.data, targetItem, this.childrenField);
26
+ if (parent) {
27
+ return this.isOverChild(parent);
28
+ }
29
+ }
30
+ return false;
31
+ }
32
+ reorderRows(ev, collection, field) {
33
+ const draggedItem = ev.draggedRows[0].dataItem;
34
+ const dropTargetItem = ev.dropTargetRow.dataItem;
35
+ const draggedItemParent = findParent(collection, draggedItem, field);
36
+ const dropTargetParent = findParent(collection, dropTargetItem, field);
37
+ const draggedItemIdx = draggedItemParent ? draggedItemParent[field].indexOf(draggedItem) : collection.indexOf(draggedItem);
38
+ let dropTargetItemIdx = dropTargetParent ? dropTargetParent[field].indexOf(dropTargetItem) : collection.indexOf(dropTargetItem);
39
+ if (ev.dropPosition === dropPosition.after && dropTargetItemIdx < draggedItemIdx) {
40
+ dropTargetItemIdx++;
41
+ }
42
+ draggedItemParent ? draggedItemParent[field].splice(draggedItemIdx, 1) : collection.splice(draggedItemIdx, 1);
43
+ if (ev.dropPosition !== dropPosition.over) {
44
+ dropTargetParent ? dropTargetParent[field].splice(dropTargetItemIdx, 0, draggedItem) : collection.splice(dropTargetItemIdx, 0, draggedItem);
45
+ }
46
+ else {
47
+ dropTargetItem[field].unshift(draggedItem);
48
+ }
49
+ }
50
+ }
51
+ HierarchicalRowReorderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: HierarchicalRowReorderService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
52
+ HierarchicalRowReorderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: HierarchicalRowReorderService });
53
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: HierarchicalRowReorderService, decorators: [{
54
+ type: Injectable
55
+ }] });
@@ -0,0 +1,220 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2023 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ import { EventEmitter, Injectable, Output, Renderer2 } from '@angular/core';
6
+ import { isDocumentAvailable, isPresent } from '@progress/kendo-angular-common';
7
+ import { getOffset, isNextSibling, isPreviousSibling, dropPosition, hintIcons, hintSVGIcons, hintClasses, hintStyles, dropIndicatorClasses, dropIndicatorStyles, defaultSelectors, rowIndexAttr } from './utils';
8
+ import * as i0 from "@angular/core";
9
+ /**
10
+ * @hidden
11
+ */
12
+ export class RowReorderService {
13
+ constructor(renderer) {
14
+ this.renderer = renderer;
15
+ this.defaultSelectors = defaultSelectors;
16
+ this.dragTarget = null;
17
+ this.dropTarget = null;
18
+ this.lastDropPosition = dropPosition.forbidden;
19
+ this.hintElement = null;
20
+ this.rowReorder = new EventEmitter();
21
+ }
22
+ press(ev) {
23
+ this.dragTarget = ev.dragTarget;
24
+ this.offsetY = ev.dragEvent.offsetY;
25
+ }
26
+ dragStart() {
27
+ this.createDropIndicator();
28
+ }
29
+ drag(ev) {
30
+ if (isPresent(ev.hintElement) && !isPresent(this.hintElement)) {
31
+ this.hintElement = ev.hintElement;
32
+ this.decorateHint();
33
+ }
34
+ const position = {
35
+ x: ev.dragEvent.clientX,
36
+ y: ev.dragEvent.clientY - this.offsetY
37
+ };
38
+ if (isPresent(this.hintElement)) {
39
+ this.renderer.setStyle(this.hintElement, 'left', `${position.x}px`);
40
+ this.renderer.setStyle(this.hintElement, 'top', `${position.y}px`);
41
+ }
42
+ this.positionDropIndicator(ev);
43
+ }
44
+ dragEnter(ev) {
45
+ this.dropTarget = ev.dropTarget;
46
+ this.view = ev.dragData;
47
+ }
48
+ dragLeave() {
49
+ this.dropTarget = null;
50
+ this.lastDropPosition === dropPosition.forbidden && this.hide();
51
+ }
52
+ dragEnd() {
53
+ this.destroyDropIndicator();
54
+ this.dragTarget = null;
55
+ this.dropTarget = null;
56
+ this.hintElement = null;
57
+ }
58
+ drop() {
59
+ this.destroyDropIndicator();
60
+ const rowReorderArgs = this.rowReorderArgs(this.dragTarget, this.dropTarget, this.view);
61
+ this.rowReorder.emit(rowReorderArgs);
62
+ }
63
+ get hintIcon() {
64
+ return hintIcons[this.lastDropPosition];
65
+ }
66
+ get hintSVGIcon() {
67
+ return hintSVGIcons[this.lastDropPosition];
68
+ }
69
+ getDefaultHintText(columns, data) {
70
+ let hintText = '';
71
+ const columnFieldsArray = columns
72
+ .toArray()
73
+ .filter(column => !column.hidden && isPresent(column.field))
74
+ .map(column => column.field);
75
+ const draggedDragRow = this.getDragRowPerElement(this.dragTarget, data);
76
+ const draggedDataItem = draggedDragRow?.dataItem;
77
+ isPresent(draggedDataItem) && columnFieldsArray.forEach(column => {
78
+ const columnValue = draggedDataItem[column];
79
+ isPresent(columnValue) ? hintText += `${columnValue} ` : null;
80
+ });
81
+ return hintText.trim();
82
+ }
83
+ rowReorderArgs(dragRow, dropRow, data) {
84
+ const dragRowData = this.getDragRowPerElement(dragRow, data);
85
+ const dropRowData = this.getDragRowPerElement(dropRow, data);
86
+ return {
87
+ draggedRows: [dragRowData],
88
+ dropTargetRow: dropRowData,
89
+ dropPosition: this.lastDropPosition
90
+ };
91
+ }
92
+ isOverChild(_item) { return false; }
93
+ reorderRows(_ev, _collection, _field) { }
94
+ get parentIdField() {
95
+ return this.bindingDirective.parentIdField;
96
+ }
97
+ get idField() {
98
+ return this.bindingDirective.idField;
99
+ }
100
+ get childrenField() {
101
+ return this.bindingDirective.childrenField;
102
+ }
103
+ get data() {
104
+ return this.bindingDirective.data;
105
+ }
106
+ getDragRowPerElement(row, data) {
107
+ let rowIndex = row?.getAttribute(rowIndexAttr);
108
+ rowIndex = rowIndex ? parseInt(rowIndex, 10) : -1;
109
+ const dataItem = rowIndex === -1 ? null : data?.at(rowIndex)?.data;
110
+ return {
111
+ dataItem,
112
+ rowIndex,
113
+ element: row
114
+ };
115
+ }
116
+ createDropIndicator() {
117
+ if (!isDocumentAvailable()) {
118
+ return;
119
+ }
120
+ this.dropIndicator = document.createElement('div');
121
+ this.decorateDropIndicator();
122
+ this.dropIndicator.innerHTML = `
123
+ <div class="k-drop-hint-start"></div>
124
+ <div class="k-drop-hint-line"></div>
125
+ `;
126
+ document.body.appendChild(this.dropIndicator);
127
+ this.hide();
128
+ }
129
+ destroyDropIndicator() {
130
+ if (!isDocumentAvailable()) {
131
+ return;
132
+ }
133
+ ;
134
+ if (this.dropIndicator && this.dropIndicator.parentElement) {
135
+ document.body.removeChild(this.dropIndicator);
136
+ this.dropIndicator = null;
137
+ }
138
+ }
139
+ decorateHint() {
140
+ hintClasses.forEach(className => this.renderer.addClass(this.hintElement, className));
141
+ Object.keys(hintStyles)
142
+ .forEach(style => this.renderer.setStyle(this.hintElement, style, hintStyles[style]));
143
+ }
144
+ positionDropIndicator(ev) {
145
+ this.lastDropPosition = this.getDropPosition(ev.dragEvent);
146
+ this.updateDropIndicatorPosition();
147
+ }
148
+ decorateDropIndicator() {
149
+ dropIndicatorClasses.forEach(className => this.renderer.addClass(this.dropIndicator, className));
150
+ Object.keys(dropIndicatorStyles)
151
+ .forEach(style => this.renderer.setStyle(this.dropIndicator, style, dropIndicatorStyles[style]));
152
+ }
153
+ getDropPosition(e) {
154
+ if (this.dropTarget === this.dragTarget || !isPresent(this.dropTarget)) {
155
+ return dropPosition.forbidden;
156
+ }
157
+ ;
158
+ const itemViewPortCoords = this.dropTarget.getBoundingClientRect();
159
+ const itemDivisionsCount = 3;
160
+ const itemDivisionHeight = itemViewPortCoords.height / itemDivisionsCount;
161
+ const { dropTargetRow } = this.rowReorderArgs(this.dragTarget, this.dropTarget, this.view);
162
+ const pointerPosition = e.clientY;
163
+ const itemTop = itemViewPortCoords.top;
164
+ let currentDropPosition = null;
165
+ if (pointerPosition <= itemTop + itemDivisionHeight) {
166
+ currentDropPosition = dropPosition.before;
167
+ }
168
+ else if (pointerPosition >= itemTop + itemViewPortCoords.height - itemDivisionHeight) {
169
+ currentDropPosition = dropPosition.after;
170
+ }
171
+ else {
172
+ currentDropPosition = dropPosition.over;
173
+ }
174
+ if (currentDropPosition === dropPosition.before && isNextSibling(this.dropTarget, this.dragTarget)) {
175
+ currentDropPosition = dropPosition.forbidden;
176
+ }
177
+ else if (currentDropPosition === dropPosition.after && isPreviousSibling(this.dropTarget, this.dragTarget)) {
178
+ currentDropPosition = dropPosition.forbidden;
179
+ }
180
+ if (this.isOverChild(dropTargetRow.dataItem)) {
181
+ currentDropPosition = dropPosition.forbidden;
182
+ }
183
+ return currentDropPosition;
184
+ }
185
+ updateDropIndicatorPosition() {
186
+ if (this.shouldHideDropIndicator() || !this.dropTarget) {
187
+ this.hide();
188
+ return;
189
+ }
190
+ this.show();
191
+ const destinationItemOffset = getOffset(this.dropTarget);
192
+ let indicatorOffsetTop = destinationItemOffset.top;
193
+ const indicatorOffsetLeft = destinationItemOffset.left + this.dropIndicator.offsetWidth / 2;
194
+ if (this.lastDropPosition === dropPosition.after) {
195
+ indicatorOffsetTop += this.dropTarget.offsetHeight;
196
+ }
197
+ this.renderer.setStyle(this.dropIndicator, 'left', `${indicatorOffsetLeft}px`);
198
+ this.renderer.setStyle(this.dropIndicator, 'top', `${indicatorOffsetTop}px`);
199
+ }
200
+ shouldHideDropIndicator() {
201
+ return this.lastDropPosition === dropPosition.forbidden || this.lastDropPosition === dropPosition.over;
202
+ }
203
+ hide() {
204
+ if (isPresent(this.dropIndicator)) {
205
+ this.renderer.setStyle(this.dropIndicator, 'display', 'none');
206
+ }
207
+ }
208
+ show() {
209
+ if (isPresent(this.dropIndicator)) {
210
+ this.renderer.removeStyle(this.dropIndicator, 'display');
211
+ }
212
+ }
213
+ }
214
+ RowReorderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: RowReorderService, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Injectable });
215
+ RowReorderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: RowReorderService });
216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: RowReorderService, decorators: [{
217
+ type: Injectable
218
+ }], ctorParameters: function () { return [{ type: i0.Renderer2 }]; }, propDecorators: { rowReorder: [{
219
+ type: Output
220
+ }] } });
@@ -0,0 +1,5 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2023 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ export {};
@@ -0,0 +1,129 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2023 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ import { cancelIcon, insertMiddleIcon, plusIcon } from '@progress/kendo-svg-icons';
6
+ /**
7
+ * @hidden
8
+ */
9
+ export const isNextSibling = (dropTarget, dragTarget) => dropTarget === dragTarget.nextElementSibling;
10
+ /**
11
+ * @hidden
12
+ */
13
+ export const isPreviousSibling = (dropTarget, dragTarget) => dropTarget === dragTarget.previousElementSibling;
14
+ /**
15
+ * @hidden
16
+ */
17
+ export function getOffset(element) {
18
+ const { clientTop, clientLeft } = getDocument(element);
19
+ const { pageYOffset, pageXOffset } = getWindow(element);
20
+ const { top, left } = element.getBoundingClientRect();
21
+ return {
22
+ top: top + pageYOffset - clientTop,
23
+ left: left + pageXOffset - clientLeft
24
+ };
25
+ }
26
+ ;
27
+ /**
28
+ * @hidden
29
+ */
30
+ export const hintIcons = {
31
+ forbidden: 'cancel',
32
+ before: 'insert-middle',
33
+ after: 'insert-middle',
34
+ over: 'plus'
35
+ };
36
+ /**
37
+ * @hidden
38
+ */
39
+ export const hintSVGIcons = {
40
+ forbidden: cancelIcon,
41
+ before: insertMiddleIcon,
42
+ after: insertMiddleIcon,
43
+ over: plusIcon
44
+ };
45
+ /**
46
+ * @hidden
47
+ */
48
+ export const dropPosition = {
49
+ forbidden: 'forbidden',
50
+ before: 'before',
51
+ after: 'after',
52
+ over: 'over'
53
+ };
54
+ /**
55
+ * @hidden
56
+ */
57
+ export const hintStyles = {
58
+ zIndex: '20000',
59
+ display: 'flex',
60
+ position: 'fixed'
61
+ };
62
+ /**
63
+ * @hidden
64
+ */
65
+ export const hintClasses = ['k-drag-clue', 'k-reorder-clue'];
66
+ /**
67
+ * @hidden
68
+ */
69
+ export const dropIndicatorStyles = {
70
+ zIndex: '19000',
71
+ position: 'absolute'
72
+ };
73
+ /**
74
+ * @hidden
75
+ */
76
+ export const dropIndicatorClasses = ['k-drop-hint', 'k-drop-hint-h'];
77
+ /**
78
+ * @hidden
79
+ */
80
+ export const defaultSelectors = {
81
+ handle: '.k-table-td.k-drag-cell',
82
+ dragTarget: '.k-table-row[data-treelist-view-index]',
83
+ dropTarget: '.k-table-row[data-treelist-view-index]'
84
+ };
85
+ /**
86
+ * @hidden
87
+ */
88
+ export const rowIndexAttr = 'data-treelist-view-index';
89
+ /**
90
+ * @hidden
91
+ */
92
+ export const findParent = (collection, searchItem, field) => {
93
+ let parent = null;
94
+ for (const item of collection) {
95
+ if (searchItem === item) {
96
+ return null;
97
+ }
98
+ const checked = [];
99
+ const queue = [];
100
+ queue.push(item);
101
+ while (queue.length !== 0) {
102
+ const current = queue.shift();
103
+ if (!current) {
104
+ continue;
105
+ }
106
+ checked.push(current);
107
+ if (current === searchItem) {
108
+ return item;
109
+ }
110
+ if (current.hasOwnProperty(field)) {
111
+ current[field].forEach(node => {
112
+ if (checked.indexOf(node) === -1) {
113
+ checked.push(node);
114
+ queue.push(node);
115
+ if (node === searchItem) {
116
+ parent = current;
117
+ return;
118
+ }
119
+ }
120
+ });
121
+ }
122
+ if (parent) {
123
+ return parent;
124
+ }
125
+ }
126
+ }
127
+ };
128
+ const getDocument = element => element?.ownerDocument.documentElement;
129
+ const getWindow = element => element?.ownerDocument.defaultView;