@progress/kendo-angular-grid 14.4.0-develop.9 → 15.0.0-develop.2

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 (52) hide show
  1. package/NOTICE.txt +146 -593
  2. package/common/clipboard-types.d.ts +102 -0
  3. package/common/clipboard.directive.d.ts +49 -0
  4. package/common/clipboard.service.d.ts +28 -0
  5. package/common/dom-events.service.d.ts +1 -0
  6. package/common/error-messages.d.ts +12 -0
  7. package/databinding.directive.d.ts +1 -1
  8. package/esm2020/column-menu/column-menu-item-base.mjs +2 -1
  9. package/esm2020/column-menu/column-menu.component.mjs +8 -5
  10. package/esm2020/columns/column-base.mjs +3 -2
  11. package/esm2020/columns/column-group.component.mjs +2 -1
  12. package/esm2020/columns/span-column.component.mjs +2 -1
  13. package/esm2020/common/clipboard-types.mjs +5 -0
  14. package/esm2020/common/clipboard.directive.mjs +185 -0
  15. package/esm2020/common/clipboard.service.mjs +218 -0
  16. package/esm2020/common/dom-events.service.mjs +1 -0
  17. package/esm2020/common/error-messages.mjs +45 -1
  18. package/esm2020/databinding.directive.mjs +3 -2
  19. package/esm2020/editing-directives/local-edit.service.mjs +2 -2
  20. package/esm2020/excel/excel.service.mjs +2 -1
  21. package/esm2020/filtering/cell/autocomplete-filter-cell.component.mjs +1 -1
  22. package/esm2020/filtering/cell/numeric-filter-cell.component.mjs +1 -1
  23. package/esm2020/filtering/menu/filter-menu-container.component.mjs +2 -2
  24. package/esm2020/filtering/menu/numeric-filter-menu-input.component.mjs +1 -1
  25. package/esm2020/grid.component.mjs +40 -34
  26. package/esm2020/grid.module.mjs +8 -4
  27. package/esm2020/grouping/group-scroll-binding.directive.mjs +2 -3
  28. package/esm2020/index.mjs +2 -0
  29. package/esm2020/package-metadata.mjs +2 -2
  30. package/esm2020/pager/pager-input.component.mjs +1 -1
  31. package/esm2020/pager/pager.component.mjs +1 -5
  32. package/esm2020/pdf/pdf.component.mjs +3 -2
  33. package/esm2020/pdf/pdf.service.mjs +2 -1
  34. package/esm2020/rendering/cell.component.mjs +33 -25
  35. package/esm2020/rendering/details/detail-template.directive.mjs +2 -1
  36. package/esm2020/rendering/header/header.component.mjs +16 -12
  37. package/esm2020/rendering/table-body.component.mjs +4 -4
  38. package/esm2020/selection/marquee.directive.mjs +11 -17
  39. package/esm2020/selection/selection-default.mjs +11 -5
  40. package/esm2020/utils.mjs +10 -0
  41. package/fesm2015/progress-kendo-angular-grid.mjs +598 -145
  42. package/fesm2020/progress-kendo-angular-grid.mjs +594 -145
  43. package/grid.component.d.ts +7 -1
  44. package/grid.module.d.ts +99 -98
  45. package/index.d.ts +3 -1
  46. package/package.json +16 -16
  47. package/pager/pager.component.d.ts +0 -1
  48. package/schematics/ngAdd/index.js +3 -3
  49. package/selection/marquee.directive.d.ts +4 -3
  50. package/selection/selection-default.d.ts +10 -4
  51. package/selection/types.d.ts +6 -0
  52. package/utils.d.ts +8 -0
@@ -0,0 +1,218 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2024 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 { ColumnComponent } from '../columns/column.component';
7
+ import { isPresent } from '@progress/kendo-angular-common';
8
+ import { ContextService } from './provider.service';
9
+ import { groupBy } from '@progress/kendo-data-query';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "./provider.service";
12
+ /**
13
+ * @hidden
14
+ */
15
+ export class ClipboardService {
16
+ constructor(contextService) {
17
+ this.contextService = contextService;
18
+ this.itemToString = (item, cols) => {
19
+ if (!cols.length) {
20
+ return null;
21
+ }
22
+ return cols.map(col => item[col.field]).join(`\t`);
23
+ };
24
+ }
25
+ createClipboardData(data, columns, options) {
26
+ let result = {
27
+ gridItems: [],
28
+ dataString: ''
29
+ };
30
+ const fieldCols = columns.flatMap(c => c instanceof ColumnComponent && isPresent(c.field) ? [c] : []);
31
+ const clipboardData = { items: [], dataStrings: [] };
32
+ const colFields = fieldCols.map(c => c.field);
33
+ if (options.wholeRow) {
34
+ this.targetColField = fieldCols[0]?.field;
35
+ this.targetRowIndex = data[0].dataRowIndex;
36
+ data.forEach(item => {
37
+ clipboardData.items.push({ dataItem: { ...item.dataItem }, fields: colFields });
38
+ clipboardData.dataStrings.push(this.itemToString(item.dataItem, fieldCols));
39
+ });
40
+ result = {
41
+ gridItems: options.operationType === 'cut' ? clipboardData.items.map(item => {
42
+ item.fields.forEach(field => item.dataItem[field] = null);
43
+ return item;
44
+ }) : [...clipboardData.items],
45
+ dataString: options.copyHeaders ? this.addHeaders(clipboardData.dataStrings.join(`\r\n`), fieldCols) : clipboardData.dataStrings.join(`\n`)
46
+ };
47
+ }
48
+ else {
49
+ if (options.target === 'selection') {
50
+ const { tabular, groups } = this.groupSelection();
51
+ const selectionDirective = this.contextService.grid.selectionDirective;
52
+ const colIdentifier = selectionDirective.columnKey;
53
+ if (tabular) {
54
+ const selectionKeys = groups[0].items.map(item => item.columnKey);
55
+ const selectedFieldCols = columns.flatMap((c, i) => (c instanceof ColumnComponent && c.field) && selectionKeys.find(k => typeof colIdentifier === 'function' ? k === colIdentifier(c, i) : k === i) ? [c] : []);
56
+ const selectedColFields = selectedFieldCols.map(c => c.field);
57
+ this.targetColField = selectedColFields[0];
58
+ result.dataString = data.flatMap(item => {
59
+ const itemString = this.itemToString(item.dataItem, selectedFieldCols);
60
+ const existingItem = isPresent(itemString);
61
+ if (!isPresent(this.targetRowIndex) && isPresent(itemString)) {
62
+ this.targetRowIndex = item.dataRowIndex;
63
+ }
64
+ if (options.operationType === 'cut') {
65
+ selectedColFields.forEach(f => item.dataItem[f] = null);
66
+ }
67
+ result.gridItems.push({
68
+ dataItem: item.dataItem,
69
+ fields: selectedColFields
70
+ });
71
+ return existingItem ? [itemString] : [];
72
+ }).join(`\r\n`);
73
+ if (options.copyHeaders) {
74
+ result.dataString = this.addHeaders(result.dataString, selectedFieldCols);
75
+ }
76
+ }
77
+ else { // split per row (uneven rows)
78
+ const rowIdentifier = selectionDirective.selectionKey;
79
+ result.dataString = data.flatMap(item => {
80
+ // determine cols per item
81
+ const key = rowIdentifier ?
82
+ typeof rowIdentifier === 'string' ? item.dataItem[rowIdentifier] : rowIdentifier({ index: item.dataRowIndex, dataItem: item.dataItem }) :
83
+ item.dataRowIndex;
84
+ const selectionKeys = groups.find(gr => gr.value === key).items.map(item => item.columnKey);
85
+ const selectedFieldCols = columns.flatMap((c, i) => (c instanceof ColumnComponent && c.field) && selectionKeys.find(k => typeof colIdentifier === 'function' ? k === colIdentifier(c, i) : k === i) ? [c] : []);
86
+ const selectedColFields = selectedFieldCols.map(c => c.field);
87
+ if (!this.targetColField) {
88
+ this.targetColField = selectedColFields[0];
89
+ }
90
+ const itemString = this.itemToString(item.dataItem, selectedFieldCols);
91
+ const existingItem = isPresent(itemString);
92
+ if (!isPresent(this.targetRowIndex) && existingItem) {
93
+ this.targetRowIndex = item.dataRowIndex;
94
+ }
95
+ if (existingItem) {
96
+ if (options.operationType === 'cut') {
97
+ selectedColFields.forEach(f => item.dataItem[f] = null);
98
+ }
99
+ result.gridItems.push({
100
+ dataItem: item.dataItem,
101
+ fields: selectedColFields
102
+ });
103
+ }
104
+ return existingItem ? options.copyHeaders ? [this.addHeaders(itemString, selectedFieldCols)] : [itemString] : [];
105
+ }).join(`\r\n`);
106
+ }
107
+ }
108
+ else {
109
+ const item = data[0];
110
+ const col = columns[item.colIndex];
111
+ const colField = col.field;
112
+ const title = col.title;
113
+ const copiedData = item.dataItem[colField];
114
+ this.targetRowIndex = item.dataRowIndex;
115
+ this.targetColField = colField;
116
+ if (options.operationType === 'cut' && colField) {
117
+ item.dataItem[colField] = null;
118
+ }
119
+ result = {
120
+ gridItems: [{
121
+ dataItem: item.dataItem,
122
+ fields: colField ? [colField] : []
123
+ }],
124
+ dataString: options.copyHeaders ? [title || colField, copiedData].join(`\r\n`) : colField ? copiedData : ``
125
+ };
126
+ }
127
+ }
128
+ return result;
129
+ }
130
+ getGridData(data, columns, targetType, targetRowIndex, options) {
131
+ const separator = data.includes(`\r\n`) ? `\r\n` : data.includes(`\n`) ? `\n` : null;
132
+ const dataRows = separator ? data.split(separator) : [data];
133
+ this.targetRowIndex = targetRowIndex;
134
+ if (targetType === 'activeCell') {
135
+ if (options.wholeRow) {
136
+ this.targetColField = columns.find(c => c instanceof ColumnComponent && c.field)?.field;
137
+ }
138
+ else {
139
+ const activeCellIndex = this.contextService.grid.activeCell.colIndex;
140
+ for (let i = 0; i < columns.length; i++) {
141
+ const col = columns[i];
142
+ if (col instanceof ColumnComponent && col.field && i >= activeCellIndex) {
143
+ this.targetColField = col.field;
144
+ break;
145
+ }
146
+ }
147
+ }
148
+ }
149
+ else {
150
+ if (options.wholeRow || !options.isCellSelection) {
151
+ this.targetColField = (columns.filter(c => c instanceof ColumnComponent && c.field))[0]['field'];
152
+ }
153
+ else {
154
+ const { groups } = this.groupSelection();
155
+ const selectionDirective = this.contextService.grid.selectionDirective;
156
+ const colIdentifier = selectionDirective.columnKey;
157
+ const visibleCols = columns.filter(c => c.isVisible);
158
+ const selectionKeys = groups[0].items.map(item => item.columnKey);
159
+ const selectedFieldCols = visibleCols.flatMap((c, i) => (c instanceof ColumnComponent && c.field) && selectionKeys.find(k => typeof colIdentifier === 'function' ? k === colIdentifier(c, i) : k === i) ? [c] : []);
160
+ const selectedColFields = selectedFieldCols.map(c => c.field);
161
+ this.targetColField = selectedColFields[0];
162
+ }
163
+ }
164
+ const items = dataRows.map(rowString => {
165
+ const cells = rowString.includes(`\t`) ? rowString.split(`\t`) : [rowString];
166
+ const colFields = columns.flatMap(c => (c instanceof ColumnComponent) && c.field ? [c.field] : []);
167
+ const targetColFieldIndex = colFields.indexOf(this.targetColField);
168
+ const affectedFields = colFields.slice(targetColFieldIndex, targetColFieldIndex + cells.length);
169
+ const item = {};
170
+ colFields.slice(targetColFieldIndex, targetColFieldIndex + cells.length).forEach((colField, index) => item[colField] = cells[index]);
171
+ return {
172
+ dataItem: item,
173
+ fields: affectedFields
174
+ };
175
+ });
176
+ return items;
177
+ }
178
+ groupSelection() {
179
+ const selection = this.contextService.grid.selection;
180
+ const groups = groupBy(selection, [{ field: 'itemKey' }])
181
+ .map(gr => {
182
+ gr.items.sort((a, b) => a.columnKey - b.columnKey);
183
+ return gr;
184
+ });
185
+ for (let i = 1; i < groups.length; i++) {
186
+ if (!this.areEqual(groups[i].items, groups[i - 1].items)) {
187
+ return {
188
+ tabular: false,
189
+ groups
190
+ };
191
+ }
192
+ }
193
+ return {
194
+ tabular: true,
195
+ groups
196
+ };
197
+ }
198
+ areEqual(arr1, arr2) {
199
+ if (arr1.length !== arr2.length) {
200
+ return false;
201
+ }
202
+ for (let i = 0; i < arr1.length; i++) {
203
+ if (arr1[i].columnKey !== arr2[i].columnKey) {
204
+ return false;
205
+ }
206
+ }
207
+ return true;
208
+ }
209
+ addHeaders(initialData, cols) {
210
+ const headersRowData = cols.map(c => c.title || c.field).join(`\t`);
211
+ return `${headersRowData}\r\n${initialData}`;
212
+ }
213
+ }
214
+ ClipboardService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: ClipboardService, deps: [{ token: i1.ContextService }], target: i0.ɵɵFactoryTarget.Injectable });
215
+ ClipboardService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: ClipboardService });
216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: ClipboardService, decorators: [{
217
+ type: Injectable
218
+ }], ctorParameters: function () { return [{ type: i1.ContextService }]; } });
@@ -18,6 +18,7 @@ export class DomEventsService {
18
18
  this.focusIn = new EventEmitter();
19
19
  this.focusOut = new EventEmitter();
20
20
  this.windowBlur = new EventEmitter();
21
+ this.paste = new EventEmitter();
21
22
  }
22
23
  }
23
24
  DomEventsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: DomEventsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -7,5 +7,49 @@
7
7
  */
8
8
  export const ColumnMenuErrorMessages = {
9
9
  autoSizeColumn: 'The auto size column does not work with enabled virtual columns',
10
- autoSizeAllColumns: 'The auto size all columns does not work with enabled virtual columns'
10
+ autoSizeAllColumns: 'The auto size all columns does not work with enabled virtual columns',
11
+ serviceInput: 'The service input of the predefined column menu components is mandatory.'
12
+ };
13
+ /**
14
+ * @hidden
15
+ */
16
+ export const ClipboardErrorMessages = {
17
+ activeCellNavigable: 'Grid must be navigable to use "activeCell" as clipboard target type.',
18
+ selectionSelectable: 'Grid must be selectable to use "selection" as clipboard target type.'
19
+ };
20
+ /**
21
+ * @hidden
22
+ */
23
+ export const ColumnConfigurationErrorMessages = {
24
+ fieldName: (field) => `Grid column field name '${field}' does not look like a valid JavaScript identifier.
25
+ Identifiers can contain only alphanumeric characters (including "$" or "_"), and may not start with a digit.
26
+ Please use only valid identifier names to ensure error-free operation.`,
27
+ width: (value, parsedValue) => `Expected numeric value for column width, but got a string "${value}". Treating as ${parsedValue}px.`,
28
+ invalidColumn: (column) => `Invalid column ${column}.`,
29
+ requiredWidth: (columnType) => `${columnType} columns feature requires all columns to have set width.`,
30
+ requiredScroll: (columnType) => `${columnType} columns are only supported when scrolling is enabled.`,
31
+ groupColumnContent: 'ColumnGroupComponent should contain ColumnComponent or CommandColumnComponent.',
32
+ lockedParent: 'Locked child columns require their parent columns to be locked.',
33
+ columnNested: 'Columns can be nested only inside ColumnGroupComponent',
34
+ nestedInside: (nestedColumnNameType, parentColumnType) => `${nestedColumnNameType} cannot be nested inside ${parentColumnType}.`
35
+ };
36
+ /**
37
+ * @hidden
38
+ */
39
+ export const GridConfigurationErrorMessages = {
40
+ functionType: (propName, fn) => `${propName} must be a function, but received ${JSON.stringify(fn)}.`,
41
+ incompatibleFeatures: (feat1Name, feat2Name) => `'Having both ${feat1Name} and ${feat2Name} is not supported.'`,
42
+ nonLockedColumnPresent: 'There should be at least one non-locked column',
43
+ rowHeightVirtual: 'Row height and detail row height settings require virtual scrolling mode to be enabled.',
44
+ focusNavigable: 'The Grid should be configured as navigable to control focus',
45
+ expandCollapseMethods: (expandMethodName, collapseMethodName, directiveName, callbackName) => `The ${expandMethodName} and ${collapseMethodName} methods should not be called
46
+ when using the ${directiveName} directive or the ${callbackName} callback.
47
+ These methods are provided only for backwards compatibility with legacy versions.`,
48
+ requiredEditService: `The default edit service of the editing directives works only when binding to plain array.
49
+ Please provide an editService.`,
50
+ requiredModule: (exportedType, moduleName, componentSelector) => `Creating ${exportedType} requires including the ${moduleName} and adding the ${componentSelector} component.`,
51
+ groupBindingDirectives: `Using the "kendoGridGroupBinding" directive in combination with the "kendoGridExpandGroupBy" directive
52
+ or the "isGroupExpanded" callback is not supported. To use grouping with the "kendoGridGroupBinding" directive,
53
+ set the Grid "groupable" property to "true".`,
54
+ unsupportedMethod: (methodName, suggestedMethodName) => `Using ${methodName} in this context is not supported. Use ${suggestedMethodName} instead.`
11
55
  };
@@ -171,11 +171,12 @@ export class DataBindingDirective {
171
171
  }
172
172
  }
173
173
  DataBindingDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: DataBindingDirective, deps: [{ token: i1.GridComponent }, { token: i0.ChangeDetectorRef }, { token: i2.LocalDataChangesService }, { token: i3.RowReorderService }], target: i0.ɵɵFactoryTarget.Directive });
174
- DataBindingDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.12", type: DataBindingDirective, selector: "[kendoGridBinding]", inputs: { skip: "skip", sort: "sort", filter: "filter", pageSize: "pageSize", group: "group", data: ["kendoGridBinding", "data"] }, usesOnChanges: true, ngImport: i0 });
174
+ DataBindingDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.12", type: DataBindingDirective, selector: "[kendoGridBinding]", inputs: { skip: "skip", sort: "sort", filter: "filter", pageSize: "pageSize", group: "group", data: ["kendoGridBinding", "data"] }, exportAs: ["kendoGridBinding"], usesOnChanges: true, ngImport: i0 });
175
175
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: DataBindingDirective, decorators: [{
176
176
  type: Directive,
177
177
  args: [{
178
- selector: '[kendoGridBinding]'
178
+ selector: '[kendoGridBinding]',
179
+ exportAs: 'kendoGridBinding'
179
180
  }]
180
181
  }], ctorParameters: function () { return [{ type: i1.GridComponent }, { type: i0.ChangeDetectorRef }, { type: i2.LocalDataChangesService }, { type: i3.RowReorderService }]; }, propDecorators: { skip: [{
181
182
  type: Input
@@ -3,6 +3,7 @@
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { isDevMode } from '@angular/core';
6
+ import { GridConfigurationErrorMessages } from '../common/error-messages';
6
7
  /**
7
8
  * @hidden
8
9
  */
@@ -52,8 +53,7 @@ export class LocalEditService {
52
53
  return data;
53
54
  }
54
55
  if (isDevMode()) {
55
- throw new Error('The default edit service of the editing directives works only when binding to plain array.' +
56
- 'Please provide an editService.');
56
+ throw new Error(GridConfigurationErrorMessages.requiredEditService);
57
57
  }
58
58
  return [];
59
59
  }
@@ -3,6 +3,7 @@
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { EventEmitter, Injectable, isDevMode } from '@angular/core';
6
+ import { GridConfigurationErrorMessages } from '../common/error-messages';
6
7
  import * as i0 from "@angular/core";
7
8
  /**
8
9
  * @hidden
@@ -15,7 +16,7 @@ export class ExcelService {
15
16
  save(component) {
16
17
  if (this.saveToExcel.observers.length === 0) {
17
18
  if (isDevMode()) {
18
- throw new Error('Saving excel requires including the ExcelModule and adding the <kendo-grid-excel> component.');
19
+ throw new Error(GridConfigurationErrorMessages.requiredModule('excel', 'ExcelModule', '<kendo-grid-excel>'));
19
20
  }
20
21
  }
21
22
  else {
@@ -75,7 +75,7 @@ AutoCompleteFilterCellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion:
75
75
  [value]="currentFilter?.value">
76
76
  </kendo-autocomplete>
77
77
  </kendo-grid-filter-wrapper-cell>
78
- `, isInline: true, components: [{ type: i5.FilterCellWrapperComponent, selector: "kendo-grid-filter-wrapper-cell", inputs: ["showOperators"] }, { type: i6.AutoCompleteComponent, selector: "kendo-autocomplete", inputs: ["highlightFirst", "showStickyHeader", "focusableId", "data", "value", "valueField", "placeholder", "adaptiveMode", "title", "subtitle", "popupSettings", "listHeight", "loading", "clearButton", "suggest", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoAutoComplete"] }], directives: [{ type: i7.FilterInputDirective, selector: "[kendoFilterInput]", inputs: ["filterDelay", "columnLabel", "value"] }] });
78
+ `, isInline: true, components: [{ type: i5.FilterCellWrapperComponent, selector: "kendo-grid-filter-wrapper-cell", inputs: ["showOperators"] }, { type: i6.AutoCompleteComponent, selector: "kendo-autocomplete", inputs: ["highlightFirst", "showStickyHeader", "focusableId", "data", "value", "valueField", "placeholder", "adaptiveMode", "title", "subtitle", "popupSettings", "listHeight", "loading", "clearButton", "suggest", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoAutoComplete"] }], directives: [{ type: i7.FilterInputDirective, selector: "[kendoFilterInput]", inputs: ["filterDelay", "columnLabel", "value"] }] });
79
79
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: AutoCompleteFilterCellComponent, decorators: [{
80
80
  type: Component,
81
81
  args: [{
@@ -101,7 +101,7 @@ NumericFilterCellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0
101
101
  </kendo-numerictextbox-messages>
102
102
  </kendo-numerictextbox>
103
103
  </kendo-grid-filter-wrapper-cell>
104
- `, isInline: true, components: [{ type: i4.FilterCellWrapperComponent, selector: "kendo-grid-filter-wrapper-cell", inputs: ["showOperators"] }, { 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: i5.NumericTextBoxCustomMessagesComponent, selector: "kendo-numerictextbox-messages" }], directives: [{ type: i6.FocusableDirective, selector: "[kendoGridFocusable],\n [kendoGridEditCommand],\n [kendoGridRemoveCommand],\n [kendoGridSaveCommand],\n [kendoGridCancelCommand],\n [kendoGridSelectionCheckbox]\n ", inputs: ["kendoGridFocusable"] }, { type: i7.FilterInputDirective, selector: "[kendoFilterInput]", inputs: ["filterDelay", "columnLabel", "value"] }] });
104
+ `, isInline: true, components: [{ type: i4.FilterCellWrapperComponent, selector: "kendo-grid-filter-wrapper-cell", inputs: ["showOperators"] }, { 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", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { type: i5.NumericTextBoxCustomMessagesComponent, selector: "kendo-numerictextbox-messages" }], directives: [{ type: i6.FocusableDirective, selector: "[kendoGridFocusable],\n [kendoGridEditCommand],\n [kendoGridRemoveCommand],\n [kendoGridSaveCommand],\n [kendoGridCancelCommand],\n [kendoGridSelectionCheckbox]\n ", inputs: ["kendoGridFocusable"] }, { type: i7.FilterInputDirective, selector: "[kendoFilterInput]", inputs: ["filterDelay", "columnLabel", "value"] }] });
105
105
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: NumericFilterCellComponent, decorators: [{
106
106
  type: Component,
107
107
  args: [{
@@ -157,7 +157,7 @@ FilterMenuContainerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12
157
157
  MenuTabbingService
158
158
  ], viewQueries: [{ propertyName: "resetButton", first: true, predicate: ["resetButton"], descendants: true }, { propertyName: "filterButton", first: true, predicate: ["filterButton"], descendants: true }], ngImport: i0, template: `
159
159
  <form (submit)="submit()" (reset)="reset()"
160
- class="k-filter-menu k-group k-reset k-state-border-up">
160
+ class="k-filter-menu">
161
161
  <div class="k-filter-menu-container">
162
162
  <ng-container [ngSwitch]="hasTemplate">
163
163
  <ng-container *ngSwitchCase="false">
@@ -203,7 +203,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
203
203
  selector: 'kendo-grid-filter-menu-container',
204
204
  template: `
205
205
  <form (submit)="submit()" (reset)="reset()"
206
- class="k-filter-menu k-group k-reset k-state-border-up">
206
+ class="k-filter-menu">
207
207
  <div class="k-filter-menu-container">
208
208
  <ng-container [ngSwitch]="hasTemplate">
209
209
  <ng-container *ngSwitchCase="false">
@@ -75,7 +75,7 @@ NumericFilterMenuInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion:
75
75
  </kendo-numerictextbox-messages>
76
76
  </kendo-numerictextbox>
77
77
  </kendo-grid-filter-menu-input-wrapper>
78
- `, isInline: true, components: [{ type: i2.FilterMenuInputWrapperComponent, selector: "kendo-grid-filter-menu-input-wrapper", inputs: ["filterService", "isFirstDropDown", "menuTabbingService", "currentFilter"] }, { type: i3.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: i3.NumericTextBoxCustomMessagesComponent, selector: "kendo-numerictextbox-messages" }], directives: [{ type: i4.FilterInputDirective, selector: "[kendoFilterInput]", inputs: ["filterDelay", "columnLabel", "value"] }] });
78
+ `, isInline: true, components: [{ type: i2.FilterMenuInputWrapperComponent, selector: "kendo-grid-filter-menu-input-wrapper", inputs: ["filterService", "isFirstDropDown", "menuTabbingService", "currentFilter"] }, { type: i3.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", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { type: i3.NumericTextBoxCustomMessagesComponent, selector: "kendo-numerictextbox-messages" }], directives: [{ type: i4.FilterInputDirective, selector: "[kendoFilterInput]", inputs: ["filterDelay", "columnLabel", "value"] }] });
79
79
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: NumericFilterMenuInputComponent, decorators: [{
80
80
  type: Component,
81
81
  args: [{
@@ -77,6 +77,8 @@ import { DragTargetContainerDirective, DropTargetContainerDirective } from '@pro
77
77
  import { RowReorderService } from './row-reordering/row-reorder.service';
78
78
  import { StatusBarTemplateDirective } from './aggregates/status-bar-template.directive';
79
79
  import { CellSelectionAggregateService } from './aggregates/selection-aggregate.service';
80
+ import { ClipboardService } from './common/clipboard.service';
81
+ import { ColumnConfigurationErrorMessages, GridConfigurationErrorMessages } from './common/error-messages';
80
82
  import * as i0 from "@angular/core";
81
83
  import * as i1 from "./layout/browser-support.service";
82
84
  import * as i2 from "./selection/selection.service";
@@ -128,11 +130,7 @@ const createControl = (source) => (acc, key) => {
128
130
  const validateColumnsField = (columns) => expandColumns(columns.toArray())
129
131
  .filter(isColumnComponent)
130
132
  .filter(({ field }) => !isValidFieldName(field))
131
- .forEach(({ field }) => console.warn(`
132
- Grid column field name '${field}' does not look like a valid JavaScript identifier.
133
- Identifiers can contain only alphanumeric characters (including "$" or "_"), and may not start with a digit.
134
- Please use only valid identifier names to ensure error-free operation.
135
- `));
133
+ .forEach(({ field }) => console.warn(ColumnConfigurationErrorMessages.fieldName(field)));
136
134
  const handleExpandCollapseGroupsService = (service, expandEmitter, collapseEmitter, map) => (service.changes.pipe(filter(({ group }) => isPresent(group)))
137
135
  .subscribe((x) => x.expand ? expandEmitter.emit(map(x)) : collapseEmitter.emit(map(x))));
138
136
  const handleExpandCollapseDetailsService = (service, expandEmitter, collapseEmitter, map) => (service.changes.pipe(filter(({ dataItem }) => isPresent(dataItem)))
@@ -647,7 +645,7 @@ export class GridComponent {
647
645
  */
648
646
  set rowClass(fn) {
649
647
  if (isDevMode() && typeof fn !== 'function') {
650
- throw new Error(`rowClass must be a function, but received ${JSON.stringify(fn)}.`);
648
+ throw new Error(GridConfigurationErrorMessages.functionType('rowClass', fn));
651
649
  }
652
650
  this._rowClass = fn;
653
651
  }
@@ -660,7 +658,7 @@ export class GridComponent {
660
658
  */
661
659
  set rowSticky(fn) {
662
660
  if (isDevMode() && isPresent(fn) && typeof fn !== 'function') {
663
- throw new Error(`rowSticky must be a function, but received ${JSON.stringify(fn)}.`);
661
+ throw new Error(GridConfigurationErrorMessages.functionType('rowSticky', fn));
664
662
  }
665
663
  if (isPresent(fn)) {
666
664
  this._rowSticky = fn;
@@ -676,7 +674,7 @@ export class GridComponent {
676
674
  */
677
675
  set rowSelected(fn) {
678
676
  if (isDevMode() && typeof fn !== 'function') {
679
- throw new Error(`rowSelected must be a function, but received ${JSON.stringify(fn)}.`);
677
+ throw new Error(GridConfigurationErrorMessages.functionType('rowSelected', fn));
680
678
  }
681
679
  this._rowSelected = fn;
682
680
  }
@@ -693,7 +691,7 @@ export class GridComponent {
693
691
  */
694
692
  set cellSelected(fn) {
695
693
  if (isDevMode() && typeof fn !== 'function') {
696
- throw new Error(`cellSelected must be a function, but received ${JSON.stringify(fn)}.`);
694
+ throw new Error(GridConfigurationErrorMessages.functionType('cellSelected', fn));
697
695
  }
698
696
  this._cellSelected = fn;
699
697
  }
@@ -712,6 +710,16 @@ export class GridComponent {
712
710
  get activeRow() {
713
711
  return this.navigationService.activeRow;
714
712
  }
713
+ /**
714
+ * Returns the current Grid selection.
715
+ *
716
+ * @hidden
717
+ */
718
+ get selection() {
719
+ return (this.selectable || this.selectionDirective) ?
720
+ this.defaultSelection ? this.defaultSelection.stateToArray() : this.selectionDirective.stateToArray() :
721
+ [];
722
+ }
715
723
  /**
716
724
  * Specifies if the loading indicator of the Grid will be displayed ([see example]({% slug binding_grid %})).
717
725
  *
@@ -1628,7 +1636,7 @@ export class GridComponent {
1628
1636
  instance = column;
1629
1637
  }
1630
1638
  if (!instance && isDevMode()) {
1631
- throw new Error(`Invalid column ${column}`);
1639
+ throw new Error(ColumnConfigurationErrorMessages.invalidColumn(column));
1632
1640
  }
1633
1641
  return instance;
1634
1642
  }
@@ -1637,43 +1645,43 @@ export class GridComponent {
1637
1645
  const locked = this.lockedLeafColumns.length || (this.columnMenu && this.columnMenu.lock);
1638
1646
  const stickyColumns = this.stickyColumns.length || (this.columnMenu && this.columnMenu.stick);
1639
1647
  if (locked && this.detailTemplate) {
1640
- throw new Error('Having both detail template and locked columns is not supported.');
1648
+ throw new Error(GridConfigurationErrorMessages.incompatibleFeatures('detail template', 'locked columns'));
1641
1649
  }
1642
1650
  if (stickyColumns && this.detailTemplate) {
1643
- throw new Error('Having both detail template and sticky columns is not supported.');
1651
+ throw new Error(GridConfigurationErrorMessages.incompatibleFeatures('detail template', 'sticky columns'));
1644
1652
  }
1645
1653
  if (this.lockedLeafColumns.length && !this.nonLockedLeafColumns.length) {
1646
- throw new Error('There should be at least one non-locked column');
1654
+ throw new Error(GridConfigurationErrorMessages.nonLockedColumnPresent);
1647
1655
  }
1648
1656
  if ((locked || this.virtualColumns) && expandColumns(this.columnList.toArray()).filter(column => !column.width && !isColumnGroupComponent(column)).length) {
1649
- throw new Error((locked ? 'Locked' : 'Virtual') + ' columns feature requires all columns to have set width.');
1657
+ throw new Error(ColumnConfigurationErrorMessages.requiredWidth(locked ? 'Locked' : 'Virtual'));
1650
1658
  }
1651
1659
  if (locked && !this.isScrollable) {
1652
- throw new Error('Locked columns are only supported when scrolling is enabled.');
1660
+ throw new Error(ColumnConfigurationErrorMessages.requiredScroll('Locked'));
1661
+ }
1662
+ if (stickyColumns && !this.isScrollable) {
1663
+ throw new Error(ColumnConfigurationErrorMessages.requiredScroll('Sticky'));
1653
1664
  }
1654
1665
  if (this.columnList.filter(isColumnGroupComponent).filter((x) => !x.hasChildren).length) {
1655
- throw new Error('ColumnGroupComponent should contain ColumnComponent or CommandColumnComponent.');
1666
+ throw new Error(ColumnConfigurationErrorMessages.groupColumnContent);
1656
1667
  }
1657
1668
  if (this.columnList.filter(x => x.locked && x.parent && !x.parent.isLocked).length) {
1658
- throw new Error('Locked child columns require their parent columns to be locked.');
1669
+ throw new Error(ColumnConfigurationErrorMessages.lockedParent);
1659
1670
  }
1660
1671
  if ((this.rowHeight || this.detailRowHeight) && !this.isVirtual) {
1661
- throw new Error('Row height and detail row height settings require virtual scrolling mode to be enabled.');
1672
+ throw new Error(GridConfigurationErrorMessages.rowHeightVirtual);
1662
1673
  }
1663
1674
  if (stickyColumns && expandColumns(this.columnList.toArray()).filter(column => !column.width && !isColumnGroupComponent(column)).length) {
1664
- throw new Error('Sticky columns feature requires all columns to have set width.');
1665
- }
1666
- if (stickyColumns && !this.isScrollable) {
1667
- throw new Error('Sticky columns are only supported when scrolling is enabled.');
1675
+ throw new Error(ColumnConfigurationErrorMessages.requiredWidth('Sticky'));
1668
1676
  }
1669
1677
  if (stickyColumns && this.virtualColumns) {
1670
- throw new Error('Having both sticky columns and column virtualization is not supported.');
1678
+ throw new Error(GridConfigurationErrorMessages.incompatibleFeatures('sticky columns', 'column virtualization'));
1671
1679
  }
1672
1680
  if (this.rowSticky && this.scrollable === 'virtual') {
1673
- throw new Error('Having both sticky rows and row virtualization (scrollable="virtual") is not supported.');
1681
+ throw new Error(GridConfigurationErrorMessages.incompatibleFeatures('sticky rows', 'row virtualization (scrollable="virtual")'));
1674
1682
  }
1675
1683
  if (this.rowSticky && this.groupable) {
1676
- throw new Error('Having both sticky rows and grouping is not supported.');
1684
+ throw new Error(GridConfigurationErrorMessages.incompatibleFeatures('sticky rows', 'grouping'));
1677
1685
  }
1678
1686
  validateColumnsField(this.columnList);
1679
1687
  }
@@ -1872,7 +1880,7 @@ export class GridComponent {
1872
1880
  }
1873
1881
  assertNavigable() {
1874
1882
  if (isDevMode() && !this.navigationService.enabled) {
1875
- throw new Error('The Grid should be configured as navigable to control focus');
1883
+ throw new Error(GridConfigurationErrorMessages.focusNavigable);
1876
1884
  }
1877
1885
  }
1878
1886
  navigationMetadata() {
@@ -1944,9 +1952,7 @@ export class GridComponent {
1944
1952
  toggleDetailRowLegacy(index, expand) {
1945
1953
  const hasCallback = typeof this.isDetailExpanded === 'function';
1946
1954
  if (isDevMode() && hasCallback) {
1947
- throw new Error('The expandRow and collapseRow methods should not be called when using the ' +
1948
- 'kendoGridDetailsExpandBy directive or the isDetailExpanded callback. ' +
1949
- 'These methods are provided only for backwards compatibility with legacy versions.');
1955
+ throw new Error(GridConfigurationErrorMessages.expandCollapseMethods('expandRow', 'collapseRow', 'kendoGridDetailsExpandBy', 'isDetailExpanded'));
1950
1956
  }
1951
1957
  if (!isDevMode() && hasCallback) {
1952
1958
  return;
@@ -1958,9 +1964,7 @@ export class GridComponent {
1958
1964
  toggleGroupRowLegacy(index, expand) {
1959
1965
  const hasCallback = typeof this.isGroupExpanded === 'function';
1960
1966
  if (isDevMode() && hasCallback) {
1961
- throw new Error('The expandGroup and collapseGroup methods should not be called when using the ' +
1962
- 'kendoGridExpandGroupBy directive or the isGroupExpanded callback. ' +
1963
- 'These methods are provided only for backwards compatibility with legacy versions.');
1967
+ throw new Error(GridConfigurationErrorMessages.expandCollapseMethods('expandGroup', 'collapseGroup', 'kendoGridExpandGroupBy', 'isGroupExpanded'));
1964
1968
  }
1965
1969
  if (!isDevMode() && hasCallback) {
1966
1970
  return;
@@ -2034,7 +2038,8 @@ GridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version:
2034
2038
  SortService,
2035
2039
  ContextService,
2036
2040
  SizingOptionsService,
2037
- RowReorderService
2041
+ RowReorderService,
2042
+ ClipboardService
2038
2043
  ], queries: [{ propertyName: "columns", predicate: ColumnBase }, { propertyName: "detailTemplateChildren", predicate: DetailTemplateDirective }, { propertyName: "cellLoadingTemplateChildren", predicate: CellLoadingTemplateDirective }, { propertyName: "loadingTemplateChildren", predicate: LoadingTemplateDirective }, { propertyName: "statusBarTemplateChildren", predicate: StatusBarTemplateDirective }, { propertyName: "noRecordsTemplateChildren", predicate: NoRecordsTemplateDirective }, { propertyName: "pagerTemplateChildren", predicate: PagerTemplateDirective }, { propertyName: "toolbarTemplateChildren", predicate: ToolbarTemplateDirective }, { propertyName: "columnMenuTemplates", predicate: ColumnMenuTemplateDirective }], viewQueries: [{ propertyName: "lockedHeader", first: true, predicate: ["lockedHeader"], descendants: true }, { propertyName: "header", first: true, predicate: ["header"], descendants: true }, { propertyName: "ariaRoot", first: true, predicate: ["ariaRoot"], descendants: true, static: true }, { propertyName: "dragTargetContainer", first: true, predicate: DragTargetContainerDirective, descendants: true }, { propertyName: "dropTargetContainer", first: true, predicate: DropTargetContainerDirective, descendants: true }, { propertyName: "footer", predicate: ["footer"], descendants: true }], exportAs: ["kendoGrid"], usesOnChanges: true, ngImport: i0, template: `
2039
2044
  <ng-container kendoGridLocalizedMessages
2040
2045
  i18n-groupPanelEmpty="kendo.grid.groupPanelEmpty|The label visible in the Grid group panel when it is empty"
@@ -2662,7 +2667,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
2662
2667
  SortService,
2663
2668
  ContextService,
2664
2669
  SizingOptionsService,
2665
- RowReorderService
2670
+ RowReorderService,
2671
+ ClipboardService
2666
2672
  ],
2667
2673
  selector: 'kendo-grid',
2668
2674
  template: `