@progress/kendo-angular-grid 16.10.1-develop.3 → 16.11.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.
@@ -6,7 +6,7 @@ import * as i0 from '@angular/core';
6
6
  import { EventEmitter, Injectable, SecurityContext, InjectionToken, Optional, Inject, Directive, SkipSelf, Input, Host, Output, HostBinding, QueryList, isDevMode, Component, ContentChildren, ContentChild, forwardRef, Pipe, TemplateRef, ChangeDetectionStrategy, ViewChildren, ViewChild, Self, NgZone, HostListener, ElementRef, ViewEncapsulation, NgModule } from '@angular/core';
7
7
  import { merge, of, Subject, from, Subscription, interval, fromEvent, Observable, zip as zip$1, BehaviorSubject } from 'rxjs';
8
8
  import * as i9 from '@progress/kendo-angular-common';
9
- import { isDocumentAvailable, Keys, anyChanged, TemplateContextDirective, DraggableDirective, EventsOutsideAngularDirective, isChanged as isChanged$1, KendoInput, guid, hasObservers, ResizeSensorComponent, isPresent as isPresent$1, closest as closest$1, isFocusable as isFocusable$1, shouldShowValidationUI, WatermarkOverlayComponent, ResizeBatchService, DraggableModule } from '@progress/kendo-angular-common';
9
+ import { isDocumentAvailable, Keys, isPresent as isPresent$1, anyChanged, TemplateContextDirective, DraggableDirective, EventsOutsideAngularDirective, isChanged as isChanged$1, KendoInput, guid, hasObservers, ResizeSensorComponent, closest as closest$1, isFocusable as isFocusable$1, shouldShowValidationUI, WatermarkOverlayComponent, ResizeBatchService, DraggableModule } from '@progress/kendo-angular-common';
10
10
  import * as i1 from '@angular/platform-browser';
11
11
  import * as i1$1 from '@progress/kendo-angular-icons';
12
12
  import { IconWrapperComponent, IconsService, KENDO_ICONS } from '@progress/kendo-angular-icons';
@@ -1067,6 +1067,10 @@ class NavigationCursor {
1067
1067
  if (cell.colSpan > 1 && cell.colIndex <= virtualCol && virtualCol < cell.colIndex + cell.colSpan) {
1068
1068
  nextColIndex = offset > 0 ? Math.min(cell.colIndex + cell.colSpan, lastIndex) : Math.max(0, cell.colIndex + offset);
1069
1069
  const nextCell = this.model.findCell(nextColIndex, prevRow);
1070
+ if (!nextCell) {
1071
+ this.virtualCol = nextColIndex;
1072
+ return this.activate(cell.rowIndex, nextColIndex);
1073
+ }
1070
1074
  if (cell !== nextCell) {
1071
1075
  cell = nextCell;
1072
1076
  this.virtualCol = cell.colIndex;
@@ -1074,7 +1078,9 @@ class NavigationCursor {
1074
1078
  else {
1075
1079
  this.virtualCol = virtualCol;
1076
1080
  }
1081
+ return this.activate(cell.rowIndex, this.virtualCol);
1077
1082
  }
1083
+ this.virtualCol = cell.colIndex;
1078
1084
  return this.activate(cell.rowIndex, cell.colIndex);
1079
1085
  }
1080
1086
  offsetRow(offset) {
@@ -1101,6 +1107,9 @@ class NavigationCursor {
1101
1107
  }
1102
1108
  if (cell.rowIndex <= this.virtualRow && offset > 0 && cell.rowSpan > 1) {
1103
1109
  cell = this.model.findCell(this.virtualCol, this.model.findRow(cell.rowIndex + cell.rowSpan - 1 + offset));
1110
+ if (!cell) {
1111
+ return;
1112
+ }
1104
1113
  }
1105
1114
  nextIndex = cell.rowIndex;
1106
1115
  nextColIndex = cell.colIndex;
@@ -1856,7 +1865,7 @@ class NavigationService {
1856
1865
  get activeRow() {
1857
1866
  if (this.mode !== 0 /* NavigationMode.Standby */) {
1858
1867
  return Object.assign({}, this.cursor.row, {
1859
- cells: this.cursor.row.cells.toArray()
1868
+ cells: this.cursor.row?.cells.toArray()
1860
1869
  });
1861
1870
  }
1862
1871
  }
@@ -2128,16 +2137,56 @@ class NavigationService {
2128
2137
  const row = this.cursor.row;
2129
2138
  switch (args.keyCode) {
2130
2139
  case Keys.ArrowDown:
2131
- preventDefault = this.cursor.moveDown(step);
2140
+ if (args.shiftKey) {
2141
+ if (this.ctx.grid.blockArrowSelection) {
2142
+ return;
2143
+ }
2144
+ preventDefault = this.cursor.moveDown(step);
2145
+ if (this.activeRow?.dataItem) {
2146
+ this.handleVerticalArrowSelection(step);
2147
+ }
2148
+ }
2149
+ else {
2150
+ preventDefault = this.cursor.moveDown(step);
2151
+ }
2132
2152
  break;
2133
2153
  case Keys.ArrowUp:
2134
- preventDefault = this.cursor.moveUp(step);
2154
+ if (args.shiftKey) {
2155
+ if (this.ctx.grid.blockArrowSelection) {
2156
+ return;
2157
+ }
2158
+ preventDefault = this.cursor.moveUp(step);
2159
+ if (this.activeRow?.dataItem) {
2160
+ this.handleVerticalArrowSelection(-step);
2161
+ }
2162
+ }
2163
+ else {
2164
+ preventDefault = this.cursor.moveUp(step);
2165
+ }
2135
2166
  break;
2136
2167
  case Keys.ArrowRight:
2137
- preventDefault = this.moveCursorFwd();
2168
+ if (args.shiftKey) {
2169
+ if (this.ctx.grid.blockArrowSelection) {
2170
+ return;
2171
+ }
2172
+ preventDefault = this.moveCursorFwd();
2173
+ this.handleHorizontalArrowSelection(args);
2174
+ }
2175
+ else {
2176
+ preventDefault = this.moveCursorFwd();
2177
+ }
2138
2178
  break;
2139
2179
  case Keys.ArrowLeft:
2140
- preventDefault = this.moveCursorBwd();
2180
+ if (args.shiftKey) {
2181
+ if (this.ctx.grid.blockArrowSelection) {
2182
+ return;
2183
+ }
2184
+ preventDefault = this.moveCursorBwd();
2185
+ this.handleHorizontalArrowSelection(args);
2186
+ }
2187
+ else {
2188
+ preventDefault = this.moveCursorBwd();
2189
+ }
2141
2190
  break;
2142
2191
  case Keys.PageDown:
2143
2192
  if (this.metadata.isVirtual && this.viewport) {
@@ -2328,6 +2377,58 @@ class NavigationService {
2328
2377
  this.leaveCell();
2329
2378
  this.cursor.reset();
2330
2379
  }
2380
+ handleVerticalArrowSelection(args) {
2381
+ const cellSelectionEnabled = this.ctx.grid.cellSelectionService.active;
2382
+ const rowSelectionEnabled = this.ctx.grid.selectionService.active && !this.ctx.grid.selectableSettings.checkboxOnly;
2383
+ if (cellSelectionEnabled || rowSelectionEnabled) {
2384
+ const selectionService = this.ctx.grid[cellSelectionEnabled ? 'cellSelectionService' : 'selectionService'];
2385
+ const colIdx = this.cursor.cell ? this.cursor.cell.colIndex : 0;
2386
+ const rowIdx = this.activeRow.dataRowIndex - this.ctx.grid.skip;
2387
+ const dataItem = selectionService.settings.view.at(rowIdx);
2388
+ const item = { index: this.activeRow.dataRowIndex, data: dataItem, column: this.ctx.grid.columnsContainer.leafColumnsToRender[colIdx] };
2389
+ if (selectionService.options.mode === 'multiple') {
2390
+ cellSelectionEnabled ? this.handleMultipleArrowCellSelection(item) : this.handleMultipleArrowRowSelection(item);
2391
+ }
2392
+ else {
2393
+ selectionService.handleClick(item, args);
2394
+ }
2395
+ }
2396
+ }
2397
+ handleHorizontalArrowSelection(args) {
2398
+ const cellSelectionEnabled = this.ctx.grid.cellSelectionService.active;
2399
+ if (cellSelectionEnabled) {
2400
+ const selectionService = this.ctx.grid[cellSelectionEnabled ? 'cellSelectionService' : 'selectionService'];
2401
+ const row = this.activeRow;
2402
+ const colIdx = this.cursor.cell ? this.cursor.cell.colIndex : 0;
2403
+ const dataItem = selectionService.settings.view.at(row.dataRowIndex - this.ctx.grid.skip);
2404
+ const item = { index: row.dataRowIndex, data: dataItem, column: this.ctx.grid.columnsContainer.leafColumnsToRender[colIdx] };
2405
+ if (!isPresent$1(dataItem) || !isPresent$1(item.column)) {
2406
+ return;
2407
+ }
2408
+ if (selectionService.options.mode === 'multiple') {
2409
+ this.handleMultipleArrowCellSelection(item);
2410
+ }
2411
+ else {
2412
+ selectionService.handleClick(item, args);
2413
+ }
2414
+ }
2415
+ }
2416
+ handleMultipleArrowCellSelection(item) {
2417
+ const cellSelectionService = this.ctx.grid.cellSelectionService;
2418
+ const startRowIndex = Math.min(cellSelectionService.lastSelectionItemRowIndex, item.index);
2419
+ const startColIndex = Math.min(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
2420
+ const endRowIndex = Math.max(cellSelectionService.lastSelectionItemRowIndex, item.index);
2421
+ const endColIndex = Math.max(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
2422
+ const ev = cellSelectionService.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex);
2423
+ cellSelectionService.changes.emit(ev);
2424
+ }
2425
+ handleMultipleArrowRowSelection(item) {
2426
+ const rowSelectionService = this.ctx.grid.selectionService;
2427
+ const startRowIndex = Math.min(rowSelectionService.lastSelectionStartIndex, item.index);
2428
+ const endRowIndex = Math.max(rowSelectionService.lastSelectionStartIndex, item.index);
2429
+ const ev = rowSelectionService.selectRange(startRowIndex, endRowIndex);
2430
+ rowSelectionService.changes.emit(ev);
2431
+ }
2331
2432
  }
2332
2433
  NavigationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NavigationService, deps: [{ token: i0.NgZone }, { token: DomEventsService }, { token: PagerContextService }, { token: ScrollRequestService }, { token: GroupsService }, { token: DetailsService }, { token: FocusRoot }, { token: EditService }, { token: i0.ChangeDetectorRef }, { token: ContextService }, { token: FocusableDirective, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
2333
2434
  NavigationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NavigationService });
@@ -14073,6 +14174,7 @@ class SelectionService {
14073
14174
  this.ctxService = ctxService;
14074
14175
  this.changes = new EventEmitter();
14075
14176
  this.currentSelection = [];
14177
+ this.nonSelectableRows = new Map();
14076
14178
  this.selectAllChecked = false;
14077
14179
  this.active = false;
14078
14180
  this.dragging = false;
@@ -14093,6 +14195,9 @@ class SelectionService {
14093
14195
  selectableSettings.drag;
14094
14196
  return this.active && dragAndMultiple;
14095
14197
  }
14198
+ get hasNonSelectable() {
14199
+ return this.nonSelectableRows.size > 0;
14200
+ }
14096
14201
  init(settings) {
14097
14202
  this.settings = settings;
14098
14203
  if (!isPresent(this.lastSelectionStartIndex)) {
@@ -14100,6 +14205,7 @@ class SelectionService {
14100
14205
  this.lastSelectionData = this.ctxService?.grid.selectionDirective?.rangeSelectionStartRow?.dataItem || {};
14101
14206
  }
14102
14207
  this.currentSelection = [];
14208
+ this.nonSelectableRows = new Map();
14103
14209
  if (settings.selectable && settings.selectable.enabled !== false) {
14104
14210
  const iterator = this.getIterator();
14105
14211
  this._selectAllState = true;
@@ -14116,6 +14222,10 @@ class SelectionService {
14116
14222
  else {
14117
14223
  this._selectAllState = undefined;
14118
14224
  }
14225
+ if (!settings.isRowSelectable(rowArgs)) {
14226
+ this.nonSelectableRows.set(rowArgs.index, rowArgs.dataItem);
14227
+ this._selectAllState = undefined;
14228
+ }
14119
14229
  }
14120
14230
  item = iterator.next();
14121
14231
  }
@@ -14126,7 +14236,7 @@ class SelectionService {
14126
14236
  }
14127
14237
  isSelected(index) {
14128
14238
  if (this.settings && this.active) {
14129
- return this.options.enabled && isPresent(this.currentSelection[index]);
14239
+ return this.options.enabled && isPresent(this.currentSelection[index]) && !this.nonSelectableRows.has(index);
14130
14240
  }
14131
14241
  }
14132
14242
  handleClick(item, event) {
@@ -14140,7 +14250,7 @@ class SelectionService {
14140
14250
  ev = this.toggle(item);
14141
14251
  }
14142
14252
  else if (this.options.mode === "multiple") {
14143
- if (ctrlKey && !event.shiftKey) {
14253
+ if ((ctrlKey || !this.options.metaKeyMultiSelect) && !event.shiftKey) {
14144
14254
  ev = this.toggle(item);
14145
14255
  }
14146
14256
  else if (event.shiftKey) {
@@ -14177,9 +14287,13 @@ class SelectionService {
14177
14287
  if (this.isSelected(item.index)) {
14178
14288
  deselectedRows.push(rowArgs);
14179
14289
  }
14180
- else {
14290
+ else if (!this.nonSelectableRows.has(item.index)) {
14181
14291
  selectedRows.push(rowArgs);
14182
14292
  }
14293
+ if (this.hasNonSelectable) {
14294
+ const nonSelectableRows = this.currentSelection.filter(i => this.nonSelectableRows.has(i.index));
14295
+ deselectedRows.push(...nonSelectableRows);
14296
+ }
14183
14297
  return {
14184
14298
  deselectedRows: deselectedRows,
14185
14299
  selectedRows: selectedRows
@@ -14212,7 +14326,7 @@ class SelectionService {
14212
14326
  const selectedRows = [];
14213
14327
  this.lastSelectionStartIndex = item.index;
14214
14328
  this.lastSelectionData = item.data;
14215
- if (!this.isSelected(item.index)) {
14329
+ if (!this.isSelected(item.index) && !this.nonSelectableRows.has(item.index)) {
14216
14330
  selectedRows.push({ dataItem: item.data, index: item.index });
14217
14331
  }
14218
14332
  this.currentSelection.forEach((row) => {
@@ -14235,7 +14349,7 @@ class SelectionService {
14235
14349
  dataItem: item.value.data,
14236
14350
  index: item.value.index
14237
14351
  };
14238
- if (this.isSelected(rowArgs.index)) {
14352
+ if (this.isSelected(rowArgs.index) || this.nonSelectableRows.has(rowArgs.index)) {
14239
14353
  const ev = {
14240
14354
  ctrlKey: false,
14241
14355
  deselectedRows: [rowArgs],
@@ -14261,12 +14375,16 @@ class SelectionService {
14261
14375
  if ((idx < start || idx > end) && this.isSelected(idx) && !ctrlKey) {
14262
14376
  deselectedRows.push(rowArgs);
14263
14377
  }
14264
- if ((idx >= start && idx <= end) && !this.isSelected(idx)) {
14378
+ if ((idx >= start && idx <= end) && !this.isSelected(idx) && !this.nonSelectableRows.has(idx)) {
14265
14379
  selectedRows.push(rowArgs);
14266
14380
  }
14267
14381
  }
14268
14382
  next = iterator.next();
14269
14383
  }
14384
+ if (this.hasNonSelectable) {
14385
+ const nonSelectableRows = this.currentSelection.filter(i => this.nonSelectableRows.has(i.index));
14386
+ deselectedRows.push(...nonSelectableRows);
14387
+ }
14270
14388
  return {
14271
14389
  deselectedRows: deselectedRows,
14272
14390
  selectedRows: selectedRows
@@ -14282,11 +14400,13 @@ class SelectionService {
14282
14400
  if (next.value && next.value.type === "data") {
14283
14401
  const idx = next.value.index;
14284
14402
  const rowArgs = { dataItem: next.value.data, index: idx };
14285
- if (this.isSelected(idx) && !selectAllChecked) {
14286
- deselectedRows.push(rowArgs);
14287
- }
14288
- if (!this.isSelected(idx) && selectAllChecked) {
14289
- selectedRows.push(rowArgs);
14403
+ if (!this.nonSelectableRows.has(idx)) {
14404
+ if (this.isSelected(idx) && !selectAllChecked) {
14405
+ deselectedRows.push(rowArgs);
14406
+ }
14407
+ if (!this.isSelected(idx) && selectAllChecked) {
14408
+ selectedRows.push(rowArgs);
14409
+ }
14290
14410
  }
14291
14411
  }
14292
14412
  next = iterator.next();
@@ -14294,6 +14414,10 @@ class SelectionService {
14294
14414
  if (!selectedRows.length && !deselectedRows.length) {
14295
14415
  return;
14296
14416
  }
14417
+ if (this.hasNonSelectable) {
14418
+ const nonSelectableRows = this.currentSelection.filter(i => this.nonSelectableRows.has(i.index));
14419
+ deselectedRows.push(...nonSelectableRows);
14420
+ }
14297
14421
  const ev = {
14298
14422
  ctrlKey: true,
14299
14423
  deselectedRows: deselectedRows,
@@ -14319,7 +14443,7 @@ class SelectionService {
14319
14443
  if ((idx < start || idx > end) && this.isSelected(idx)) {
14320
14444
  deselectedRows.push(rowArgs);
14321
14445
  }
14322
- if ((idx >= start && idx <= end) && !this.isSelected(idx)) {
14446
+ if ((idx >= start && idx <= end) && !this.isSelected(idx) && !this.nonSelectableRows.has(idx)) {
14323
14447
  selectedRows.push(rowArgs);
14324
14448
  }
14325
14449
  }
@@ -14329,6 +14453,10 @@ class SelectionService {
14329
14453
  if (this.options.cellAggregates) {
14330
14454
  cellAggregates = this.aggregateService.onSelectionChange({ selectedRows, deselectedRows });
14331
14455
  }
14456
+ if (this.hasNonSelectable) {
14457
+ const nonSelectableRows = this.currentSelection.filter(i => this.nonSelectableRows.has(i.index));
14458
+ deselectedRows.push(...nonSelectableRows);
14459
+ }
14332
14460
  return {
14333
14461
  deselectedRows: deselectedRows,
14334
14462
  selectedRows: selectedRows,
@@ -14348,7 +14476,8 @@ class SelectionService {
14348
14476
  cellAggregates: false,
14349
14477
  checkboxOnly: false,
14350
14478
  enabled: true,
14351
- mode: "multiple"
14479
+ mode: "multiple",
14480
+ metaKeyMultiSelect: true
14352
14481
  };
14353
14482
  if (!isPresent(this.settings)) {
14354
14483
  return defaultOptions;
@@ -14358,7 +14487,8 @@ class SelectionService {
14358
14487
  cellAggregates: false,
14359
14488
  checkboxOnly: false,
14360
14489
  enabled: this.settings.selectable,
14361
- mode: "multiple"
14490
+ mode: "multiple",
14491
+ metaKeyMultiSelect: true
14362
14492
  };
14363
14493
  }
14364
14494
  else {
@@ -14435,523 +14565,836 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
14435
14565
  }], ctorParameters: function () { return [{ type: DomEventsService }, { type: CellSelectionAggregateService }, { type: LocalDataChangesService }, { type: NavigationService }, { type: ContextService }]; } });
14436
14566
 
14437
14567
  /**
14438
- * Represents the select-all checkbox feature of the Grid ([see example](slug:grid_selection_persistence#toc-selecting-all-items)).
14439
- *
14440
- * @example
14441
- * ```html
14442
- * <input
14443
- * type="checkbox"
14444
- * kendoCheckBox
14445
- * kendoGridSelectAllCheckbox
14446
- * [state]="selectAllState"
14447
- * (selectAllChange)="onSelectAllChange($event)"
14448
- * />
14449
- * ```
14568
+ * @hidden
14450
14569
  */
14451
- class SelectAllCheckboxDirective {
14452
- constructor(selectionService, el, renderer, ngZone) {
14453
- this.selectionService = selectionService;
14454
- this.el = el;
14455
- this.renderer = renderer;
14456
- this.ngZone = ngZone;
14457
- /**
14458
- * Fires when the user clicks the `kendoGridSelectAllCheckbox` select-all checkbox
14459
- * ([see example](slug:grid_row_selection#toc-select-all-checkbox)).
14460
- */
14461
- this.selectAllChange = new EventEmitter();
14462
- this.type = 'checkbox';
14463
- this.stateSet = false;
14464
- this.ngZone.runOutsideAngular(() => {
14465
- this.destroyClick = this.renderer.listen(this.el.nativeElement, 'click', this.onClick.bind(this));
14466
- });
14570
+ class CellSelectionService {
14571
+ constructor(domEvents, aggregateService, localDataChangesService, navigationService) {
14572
+ this.domEvents = domEvents;
14573
+ this.aggregateService = aggregateService;
14574
+ this.localDataChangesService = localDataChangesService;
14575
+ this.navigationService = navigationService;
14576
+ this.changes = new EventEmitter();
14577
+ this.mouseUpEvent = new EventEmitter();
14578
+ this.currentSelection = [];
14579
+ this.active = false;
14580
+ this.nonSelectableRows = new Map();
14581
+ this.dragging = false;
14582
+ this.dragSelectDeselect = false;
14583
+ this.lastSelectionItem = { itemKey: 0, columnKey: 0 };
14584
+ this.lastSelectionItemRowIndex = 0;
14585
+ this.lastSelectionItemColIndex = 0;
14586
+ this.addSubscriptions();
14467
14587
  }
14468
- ngAfterContentChecked() {
14469
- this.setState();
14588
+ get enableMarquee() {
14589
+ const checkboxOnly = this.settings && typeof this.settings === 'object' && this.settings.checkboxOnly;
14590
+ if (!this.settings || checkboxOnly) {
14591
+ return false;
14592
+ }
14593
+ const selectableSettings = this.settings.selectable;
14594
+ const dragAndMultiple = typeof (selectableSettings) === 'object' &&
14595
+ isPresent(selectableSettings) &&
14596
+ selectableSettings.mode === 'multiple' &&
14597
+ selectableSettings.cell &&
14598
+ selectableSettings.enabled !== false &&
14599
+ selectableSettings.drag;
14600
+ return this.active && dragAndMultiple;
14470
14601
  }
14471
- ngOnChanges() {
14472
- this.stateSet = true;
14602
+ get hasNonSelectable() {
14603
+ return this.nonSelectableRows.size > 0;
14473
14604
  }
14474
- ngOnDestroy() {
14475
- if (this.destroyClick) {
14476
- this.destroyClick();
14605
+ init(settings) {
14606
+ this.settings = settings;
14607
+ this.currentSelection = [];
14608
+ this.nonSelectableRows = new Map();
14609
+ if (settings.selectable && settings.selectable.enabled !== false) {
14610
+ const iterator = this.getIterator();
14611
+ let item = iterator.next();
14612
+ while (!item.done) {
14613
+ if (item.value && item.value.type === "data") {
14614
+ const rowArgs = {
14615
+ dataItem: item.value.data,
14616
+ index: item.value.index
14617
+ };
14618
+ settings.columns.forEach(col => {
14619
+ const selectedCellArgs = settings.cellSelected(rowArgs, col, col.leafIndex);
14620
+ if (selectedCellArgs.selected) {
14621
+ this.currentSelection.push(selectedCellArgs.item);
14622
+ }
14623
+ if (!settings.isRowSelectable(rowArgs)) {
14624
+ this.nonSelectableRows.set(rowArgs.index, rowArgs.dataItem);
14625
+ }
14626
+ });
14627
+ }
14628
+ item = iterator.next();
14629
+ }
14477
14630
  }
14478
14631
  }
14479
- /**
14480
- * @hidden
14481
- */
14482
- onClick() {
14483
- // yields consistent cross-browser behavior when clicking an indeterminate checkbox
14484
- const undefinedCheckedStateInIE = detectIE() && this.selectionService.selectAllState === undefined;
14485
- const isChecked = undefinedCheckedStateInIE ? true : this.el.nativeElement.checked;
14486
- const options = this.selectionService.options;
14487
- const enabledAndMultiple = options.enabled && options.mode === 'multiple';
14488
- const shouldEmitSelectAll = hasObservers(this.selectAllChange);
14489
- if (enabledAndMultiple || shouldEmitSelectAll) {
14490
- this.ngZone.run(() => {
14491
- if (enabledAndMultiple) {
14492
- this.selectionService.updateAll(isChecked);
14493
- }
14494
- if (shouldEmitSelectAll) {
14495
- this.selectAllChange.emit(isChecked ? 'checked' : 'unchecked');
14496
- }
14497
- });
14632
+ isCellSelected(item, col) {
14633
+ if (this.settings && this.active) {
14634
+ const selectedCellArgs = this.settings.cellSelected({ dataItem: item.data, index: item.index }, col, col.leafIndex);
14635
+ return this.options.enabled && selectedCellArgs.selected && !this.nonSelectableRows.has(item.index);
14498
14636
  }
14637
+ return false;
14499
14638
  }
14500
- /**
14501
- * @hidden
14502
- */
14503
- setState() {
14504
- const state = this.stateSet ? this.stateToBool() : this.selectionService.selectAllState;
14505
- const elem = this.el.nativeElement;
14506
- this.renderer.setProperty(elem, 'indeterminate', !isPresent(state));
14507
- this.renderer.setProperty(elem, 'checked', isPresent(state) ? state : false);
14639
+ handleClick(item, event) {
14640
+ if (this.dragging) {
14641
+ this.dragging = false;
14642
+ return;
14643
+ }
14644
+ let ev;
14645
+ const ctrlKey = event.ctrlKey || event.metaKey;
14646
+ if (this.options.mode === "single" && ctrlKey && this.isCellSelected(item, item.column)) {
14647
+ ev = this.toggle(item);
14648
+ }
14649
+ else if (this.options.mode === "multiple") {
14650
+ if ((ctrlKey || !this.options.metaKeyMultiSelect) && !event.shiftKey) {
14651
+ ev = this.toggle(item);
14652
+ }
14653
+ else if (event.shiftKey) {
14654
+ const startRowIndex = Math.min(this.lastSelectionItemRowIndex, item.index);
14655
+ const startColIndex = Math.min(this.lastSelectionItemColIndex, item.column.leafIndex);
14656
+ const endRowIndex = Math.max(this.lastSelectionItemRowIndex, item.index);
14657
+ const endColIndex = Math.max(this.lastSelectionItemColIndex, item.column.leafIndex);
14658
+ ev = this.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex);
14659
+ }
14660
+ }
14661
+ if (!isPresent(ev)) {
14662
+ ev = this.select(item);
14663
+ this.currentSelection = [this.lastSelectionItem];
14664
+ }
14665
+ if (!ev.selectedCells.length && !ev.deselectedCells.length) {
14666
+ return;
14667
+ }
14668
+ ev.ctrlKey = ctrlKey;
14669
+ ev.shiftKey = event.shiftKey;
14670
+ if (this.options.cellAggregates && !event.shiftKey) {
14671
+ ev.cellAggregates = this.aggregateService.onSelectionChange(ev);
14672
+ }
14673
+ if (ev.shiftKey) {
14674
+ ev.rangeStartCell = this.lastSelectionItem;
14675
+ ev.rangeEndCell = {
14676
+ ...this.settings.cellSelected({ dataItem: item.data, index: item.index }, item.column, item.column.leafIndex).item
14677
+ };
14678
+ }
14679
+ this.changes.emit(ev);
14508
14680
  }
14509
- /**
14510
- * @hidden
14511
- */
14512
- stateToBool() {
14513
- switch (this.state) {
14514
- case 'checked':
14515
- return true;
14516
- case 'unchecked':
14517
- return false;
14518
- default:
14519
- return undefined;
14681
+ toggle(item) {
14682
+ const selectedCells = [];
14683
+ const deselectedCells = [];
14684
+ this.lastSelectionItem =
14685
+ this.settings.cellSelected({ dataItem: item.data, index: item.index }, item.column, item.column.leafIndex).item;
14686
+ this.lastSelectionItemRowIndex = item.index;
14687
+ this.lastSelectionItemColIndex = item.column.leafIndex;
14688
+ if (this.isCellSelected(item, item.column)) {
14689
+ deselectedCells.push(this.lastSelectionItem);
14690
+ }
14691
+ else if (!this.nonSelectableRows.has(item.index)) {
14692
+ selectedCells.push(this.lastSelectionItem);
14520
14693
  }
14694
+ return {
14695
+ deselectedCells,
14696
+ selectedCells
14697
+ };
14521
14698
  }
14522
- }
14523
- SelectAllCheckboxDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SelectAllCheckboxDirective, deps: [{ token: SelectionService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
14524
- SelectAllCheckboxDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: SelectAllCheckboxDirective, isStandalone: true, selector: "[kendoGridSelectAllCheckbox]", inputs: { state: "state" }, outputs: { selectAllChange: "selectAllChange" }, host: { properties: { "attr.type": "this.type" } }, usesOnChanges: true, ngImport: i0 });
14525
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SelectAllCheckboxDirective, decorators: [{
14526
- type: Directive,
14527
- args: [{
14528
- selector: '[kendoGridSelectAllCheckbox]',
14529
- standalone: true
14530
- }]
14531
- }], ctorParameters: function () { return [{ type: SelectionService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, propDecorators: { state: [{
14532
- type: Input
14533
- }], selectAllChange: [{
14534
- type: Output
14535
- }], type: [{
14536
- type: HostBinding,
14537
- args: ['attr.type']
14538
- }] } });
14539
-
14540
- const mergeObjects = (...args) => Object.assign.apply(null, [{}].concat(args));
14541
- const directions = initialDirection => initialDirection === "asc" ? ["asc", "desc"] : ["desc", "asc"];
14542
- /**
14543
- * @hidden
14544
- */
14545
- const isRootLevel = ({ parent }) => !isTruthy(parent);
14546
- const ofColumnType = ({ draggable }) => ['column', 'columnGroup']
14547
- .indexOf(draggable.context.type) >= 0;
14548
- const notSameElement = ({ draggable, target }) => draggable.element.nativeElement !== target.element.nativeElement;
14549
- const inSameParent = (x, y) => x.parent === y.parent ||
14550
- (isInSpanColumn$1(y) && inSameParent(x, y.parent));
14551
- const sameParent = ({ draggable, target }) => inSameParent(draggable.context.column, target.context.column);
14552
- const lastNonLocked = ({ draggable }) => !isTruthy(draggable.context.column.locked) &&
14553
- isRootLevel(draggable.context.column) &&
14554
- draggable.context.lastColumn;
14555
- const notInSpanColumn = ({ draggable }) => !isInSpanColumn$1(draggable.context.column);
14556
- const reorderable = ({ draggable }) => draggable.context.column.reorderable;
14557
- const lockable = ({ draggable, target }) => draggable.context.column.lockable !== false ||
14558
- draggable.context.column.isLocked === target.context.column.isLocked;
14559
- const rules = and(ofColumnType, reorderable, notInSpanColumn, notSameElement, sameParent, not(lastNonLocked), lockable);
14560
- const modifierKeys = ['alt', 'ctrl', 'shift', 'meta'];
14561
- /**
14562
- * @hidden
14563
- */
14564
- class HeaderComponent {
14565
- constructor(popupService, hint, cue, reorderService, idService, sortService, columnInfoService, cd, contextService, navigationService) {
14566
- this.popupService = popupService;
14567
- this.hint = hint;
14568
- this.cue = cue;
14569
- this.reorderService = reorderService;
14570
- this.idService = idService;
14571
- this.sortService = sortService;
14572
- this.columnInfoService = columnInfoService;
14573
- this.cd = cd;
14574
- this.contextService = contextService;
14575
- this.navigationService = navigationService;
14576
- this.columns = [];
14577
- this.groups = [];
14578
- this.sort = new Array();
14579
- this.sortable = false;
14580
- this.groupable = false;
14581
- this.lockedColumnsCount = 0;
14582
- this.resizable = false;
14583
- this.reorderable = false;
14584
- this.columnMenu = false;
14585
- this.totalColumnsCount = 0;
14586
- this.size = 'medium';
14587
- this.sortedFields = {};
14588
- this.hostClass = true;
14589
- this.dropTargets = new QueryList();
14590
- this.sortAscSmallIcon = sortAscSmallIcon;
14591
- this.sortDescSmallIcon = sortDescSmallIcon;
14592
- this.subscription = new Subscription();
14593
- }
14594
- get headerClass() {
14595
- return !this.scrollable;
14596
- }
14597
- get sortableLabel() {
14598
- return this.contextService.localization.get('sortable');
14599
- }
14600
- get columnMenuSettings() {
14601
- return this.columnMenu;
14602
- }
14603
- // Number of unlocked columns in the next table, if any
14604
- get unlockedColumnsCount() {
14605
- return this.totalColumnsCount - this.lockedColumnsCount - this.columns.length;
14606
- }
14607
- sortColumn(descriptor) {
14608
- this.sortService.sort(descriptor);
14609
- }
14610
- getColumnComponent(column) {
14611
- return column;
14612
- }
14613
- onSortClick(column, event, link) {
14614
- const target = event.target;
14615
- if (column.headerTemplateRef && target !== link) {
14616
- const hasFocusableParent = Boolean(closestInScope(target, isFocusable, link));
14617
- if (hasFocusableParent) {
14618
- // Do not sort when clicking focusable template elements.
14619
- return;
14620
- }
14699
+ select(item) {
14700
+ const selectedCells = [];
14701
+ const deselectedCells = [];
14702
+ this.lastSelectionItem =
14703
+ this.settings.cellSelected({ dataItem: item.data, index: item.index }, item.column, item.column.leafIndex).item;
14704
+ this.lastSelectionItemRowIndex = item.index;
14705
+ this.lastSelectionItemColIndex = item.column.leafIndex;
14706
+ if (!this.isCellSelected(item, item.column) && !this.nonSelectableRows.has(item.index)) {
14707
+ selectedCells.push(this.lastSelectionItem);
14621
14708
  }
14622
- const modifier = this.matchModifier(event);
14623
- const toggledColumn = this.toggleSort(column, modifier);
14624
- this.sortColumn(toggledColumn);
14709
+ this.currentSelection.forEach((selectedItem) => {
14710
+ if (selectedItem.itemKey !== this.lastSelectionItem.itemKey || selectedItem.columnKey !== this.lastSelectionItem.columnKey) {
14711
+ deselectedCells.push(selectedItem);
14712
+ }
14713
+ });
14714
+ return {
14715
+ deselectedCells,
14716
+ selectedCells
14717
+ };
14625
14718
  }
14626
- onHeaderKeydown(column, args) {
14627
- if (args.keyCode === Keys.ArrowDown && args.altKey && this.showFilterMenu) {
14628
- args.preventDefault();
14629
- args.stopImmediatePropagation();
14630
- const filterMenu = this.filterMenus.find(fm => fm.column === column);
14631
- filterMenu.toggle(filterMenu.anchor.nativeElement, filterMenu.template);
14632
- return;
14633
- }
14634
- if (args.keyCode === Keys.ArrowDown && args.altKey && this.showColumnMenu(column)) {
14635
- args.preventDefault();
14636
- args.stopImmediatePropagation();
14637
- const columnMenu = this.columnMenus.find(cm => cm.column === column);
14638
- columnMenu.toggle(null, columnMenu.anchor.nativeElement, columnMenu.template);
14639
- return;
14719
+ //Used to manually deselect removed items
14720
+ deselect(removedItem) {
14721
+ const iterator = this.getIterator();
14722
+ let item = iterator.next();
14723
+ let rowArgs;
14724
+ while (!item.done) {
14725
+ if (item.value && item.value.type === "data" && item.value.data === removedItem) {
14726
+ rowArgs = {
14727
+ dataItem: item.value.data,
14728
+ index: item.value.index
14729
+ };
14730
+ break;
14731
+ }
14732
+ item = iterator.next();
14640
14733
  }
14641
- const isCtrlOrMeta = args.ctrlKey || args.metaKey;
14642
- const isGroupingKeyShortcut = (args.keyCode === Keys.Enter || args.keyCode === Keys.Space) && isCtrlOrMeta;
14643
- if (isGroupingKeyShortcut && this.isGroupable(column)) {
14644
- args.preventDefault();
14645
- args.stopImmediatePropagation();
14646
- const isGroupedByField = this.groups.some(gr => gr.field === column.field);
14647
- if (isGroupedByField) {
14648
- this.groups = this.groups.filter(gr => gr.field !== column.field);
14734
+ if (rowArgs) {
14735
+ const cellsToRemove = this.currentSelection.filter(selectedItem => {
14736
+ const contender = this.settings.cellSelected(rowArgs, null, null).item;
14737
+ return selectedItem.itemKey === contender.itemKey || this.nonSelectableRows.has(rowArgs.index);
14738
+ });
14739
+ if (cellsToRemove.length) {
14740
+ const ev = {
14741
+ ctrlKey: false,
14742
+ deselectedCells: cellsToRemove,
14743
+ selectedCells: []
14744
+ };
14745
+ this.changes.emit(ev);
14649
14746
  }
14650
- else {
14651
- this.groups.push({
14652
- field: column.field
14747
+ }
14748
+ }
14749
+ selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex) {
14750
+ const selectedCells = [];
14751
+ const deselectedCells = [];
14752
+ const selectionStartRow = Math.min(startRowIndex, endRowIndex);
14753
+ const selectionStartCol = Math.min(startColIndex, endColIndex);
14754
+ const selectionEndRow = Math.max(startRowIndex, endRowIndex);
14755
+ const selectionEndCol = Math.max(startColIndex, endColIndex);
14756
+ const iterator = this.getIterator();
14757
+ let next = iterator.next();
14758
+ while (!next.done) {
14759
+ if (next.value && next.value.type === "data") {
14760
+ const idx = next.value.index;
14761
+ const data = next.value.data;
14762
+ const rowArgs = {
14763
+ dataItem: data,
14764
+ index: idx
14765
+ };
14766
+ this.settings.columns.forEach(col => {
14767
+ const { item } = this.settings.cellSelected(rowArgs, col, col.leafIndex);
14768
+ const selected = this.isCellSelected(next.value, col);
14769
+ const isInRowRange = selectionStartRow <= idx && idx <= selectionEndRow;
14770
+ const isInColRange = selectionStartCol <= col.leafIndex && col.leafIndex <= selectionEndCol;
14771
+ const isInSelectionRect = isInRowRange && isInColRange;
14772
+ if (!isInSelectionRect && selected) {
14773
+ deselectedCells.push(item);
14774
+ }
14775
+ if (isInSelectionRect && !selected && !this.nonSelectableRows.has(idx)) {
14776
+ selectedCells.push(item);
14777
+ }
14653
14778
  });
14654
14779
  }
14655
- this.contextService.grid.groupChange.emit(this.groups);
14656
- return;
14657
- }
14658
- const isLeftOrRightArrow = args.keyCode === Keys.ArrowLeft || args.keyCode === Keys.ArrowRight;
14659
- const isReorderingKeyShortcut = isLeftOrRightArrow && isCtrlOrMeta;
14660
- if (isReorderingKeyShortcut && this.isReorderable(column)) {
14661
- args.preventDefault();
14662
- const columnsCount = this.columnInfoService.leafNamedColumns.length;
14663
- const reorderDirection = args.keyCode === Keys.ArrowLeft ? -1 : 1;
14664
- const rtlMultiplier = this.contextService.localization.rtl ? -1 : 1;
14665
- const reorderDirectionOffset = reorderDirection * rtlMultiplier;
14666
- const newIndex = column.leafIndex + reorderDirectionOffset;
14667
- const normalizedNewIndex = Math.min(Math.max(0, newIndex), columnsCount - 1);
14668
- const gridInstance = this.contextService.grid;
14669
- gridInstance.reorderColumn(column, normalizedNewIndex, { before: reorderDirectionOffset < 0 });
14670
- gridInstance.columnReorder.emit(new ColumnReorderEvent({
14671
- column,
14672
- newIndex: normalizedNewIndex,
14673
- oldIndex: column.leafIndex
14674
- }));
14675
- return;
14676
- }
14677
- if (!this.sortable || args.defaultPrevented || column.sortable === false) {
14678
- return;
14780
+ next = iterator.next();
14679
14781
  }
14680
- if (args.keyCode === Keys.Enter && isPresent(column.field)) {
14681
- const modifier = this.matchModifier(args);
14682
- this.sortService.sort(this.toggleSort(column, modifier));
14782
+ let cellAggregates;
14783
+ if (this.options.cellAggregates) {
14784
+ cellAggregates = this.aggregateService.onSelectionChange({ selectedCells, deselectedCells });
14683
14785
  }
14786
+ return {
14787
+ deselectedCells,
14788
+ selectedCells,
14789
+ cellAggregates
14790
+ };
14684
14791
  }
14685
- showSortNumbering(column) {
14686
- const { showIndexes } = normalize$1(this.sortable);
14687
- return showIndexes
14688
- && this.sort
14689
- && this.sort.filter(({ dir }) => isPresent(dir)).length > 1
14690
- && this.sortOrder(column.field) > 0;
14691
- }
14692
- sortOrder(field) {
14693
- return this.sort
14694
- .filter(({ dir }) => isPresent(dir))
14695
- .findIndex(x => x.field === field)
14696
- + 1;
14697
- }
14698
- sortState(column) {
14699
- if (!this.isInteractive(column, 'sortable')) {
14700
- return;
14792
+ get options() {
14793
+ const defaultOptions = {
14794
+ cellAggregates: false,
14795
+ checkboxOnly: false,
14796
+ enabled: true,
14797
+ mode: "multiple",
14798
+ metaKeyMultiSelect: true
14799
+ };
14800
+ if (!isPresent(this.settings)) {
14801
+ return defaultOptions;
14701
14802
  }
14702
- const state = this.sortDescriptor(column.field);
14703
- if (state.dir === 'asc') {
14704
- return 'ascending';
14803
+ if (typeof this.settings.selectable === 'boolean') {
14804
+ return {
14805
+ cellAggregates: false,
14806
+ checkboxOnly: false,
14807
+ enabled: this.settings.selectable,
14808
+ mode: "multiple",
14809
+ metaKeyMultiSelect: true
14810
+ };
14705
14811
  }
14706
- if (state.dir === 'desc') {
14707
- return 'descending';
14812
+ else {
14813
+ return Object.assign(defaultOptions, this.settings.selectable);
14708
14814
  }
14709
14815
  }
14710
- get isNavigable() {
14711
- return this.navigationService.tableEnabled;
14816
+ ngOnDestroy() {
14817
+ this.removeSubscriptions();
14712
14818
  }
14713
- /**
14714
- *
14715
- * @param column
14716
- * @param modifier - Indicates whether the client-defined `multiSortKey` modifier is met. Defaults to `true`.
14717
- * @returns - SortDescriptor[]
14718
- */
14719
- toggleSort(column, modifier = true) {
14720
- const { allowUnsort, mode, initialDirection } = normalize$1(this.sortable, column.sortable);
14721
- const descriptor = this.toggleDirection(column.field, allowUnsort, initialDirection);
14722
- if (mode === 'single' || !modifier) {
14723
- return [descriptor];
14724
- }
14725
- return [...this.sort.filter(desc => desc.field !== column.field), descriptor];
14726
- }
14727
- /**
14728
- *
14729
- * Determines whether the modifier key (if any) passed
14730
- * with a click/keyboard event matches the user-defined multiSortKey.
14731
- */
14732
- matchModifier(event) {
14733
- const { multiSortKey } = normalize$1(this.sortable);
14734
- if (multiSortKey === 'none') {
14735
- return modifierKeys.every(key => !event[`${key}Key`]);
14736
- }
14737
- return multiSortKey === 'ctrl'
14738
- ? event.ctrlKey || event.metaKey
14739
- : event[`${multiSortKey}Key`];
14740
- }
14741
- ngAfterViewInit() {
14742
- this.subscription.add(observe(this.dropTargets)
14743
- .subscribe(this.attachTargets.bind(this)));
14744
- }
14745
- ngDoCheck() {
14746
- this._leafColumns = columnsToRender(this.columns || []).filter(x => !isColumnGroupComponent(x));
14747
- }
14748
- ngOnChanges(changes) {
14749
- const sortChange = changes.sort;
14750
- if (sortChange && !sortChange.isFirstChange()) {
14751
- sortChange.currentValue.forEach(change => {
14752
- this.sortedFields[change.field] = true;
14819
+ addSubscriptions() {
14820
+ if (!this.cellClickSubscription) {
14821
+ this.cellClickSubscription = this.domEvents.cellClick.subscribe((args) => {
14822
+ if (this.options.enabled && !this.options.checkboxOnly && args.type !== 'contextmenu') {
14823
+ if (this.active) {
14824
+ this.handleClick({ index: args.rowIndex, data: args.dataItem, column: args.column }, args.originalEvent);
14825
+ }
14826
+ }
14753
14827
  });
14754
14828
  }
14755
- }
14756
- ngOnInit() {
14757
- this.subscription.add(this.contextService.localization.changes
14758
- .subscribe(() => this.cd.markForCheck()));
14759
- }
14760
- ngOnDestroy() {
14761
- if (this.targetSubscription) {
14762
- this.targetSubscription.unsubscribe();
14829
+ if (!this.mousedownSubscription) {
14830
+ this.mousedownSubscription = this.domEvents.cellMousedown.subscribe((args) => {
14831
+ this.mouseDownEventArgs = args;
14832
+ if (this.options.enabled && (!this.options.mode || this.options.mode === "multiple") &&
14833
+ !this.options.checkboxOnly && args.originalEvent.shiftKey) {
14834
+ if (this.active) {
14835
+ args.originalEvent.preventDefault();
14836
+ this.navigationService.focusCellByElement(args.originalEvent.target);
14837
+ }
14838
+ }
14839
+ });
14763
14840
  }
14764
- if (this.popupService) {
14765
- this.popupService.destroy();
14841
+ if (this.localDataChangesService && !this.dataChangedSubscription) {
14842
+ this.dataChangedSubscription = this.localDataChangesService.changes.subscribe((args) => {
14843
+ if (this.active) {
14844
+ if (isPresent(args.action) && args.action === 'remove') {
14845
+ this.deselect(args.item);
14846
+ }
14847
+ }
14848
+ });
14766
14849
  }
14767
- this.subscription.unsubscribe();
14768
- }
14769
- selectAllCheckboxId() {
14770
- return this.idService.selectAllCheckboxId();
14771
- }
14772
- get selectAllCheckboxLabel() {
14773
- return this.contextService.localization.get('selectAllCheckboxLabel');
14774
- }
14775
- isFirstOnRow(column, index) {
14776
- const isTailing = (c) => c &&
14777
- (this.columnsForLevel(c.level).indexOf(c) > 0 || isTailing(c.parent));
14778
- return index === 0 && !this.groups.length && !this.detailTemplate && isTailing(column.parent);
14779
14850
  }
14780
- logicalColumnIndex(column) {
14781
- const index = column.leafIndex;
14782
- if (isPresent(index)) {
14783
- return index + (isPresent(this.detailTemplate) ? 1 : 0);
14851
+ getIterator() {
14852
+ const accessor = this.settings.view.accessor();
14853
+ if (!accessor) {
14854
+ return;
14784
14855
  }
14785
- return -1;
14786
- }
14787
- get showFilterMenu() {
14788
- return !this.columnMenu && hasFilterMenu(this.filterable);
14789
- }
14790
- get showFilterRow() {
14791
- return hasFilterRow(this.filterable);
14792
- }
14793
- showColumnMenu(column) {
14794
- return this.columnMenu && column.columnMenu &&
14795
- (this.columnMenuTemplate || column.columnMenuTemplates.length || hasItems(this.columnMenu, column));
14796
- }
14797
- isFilterable(column) {
14798
- return !isNullOrEmptyString(column.field) && column.filterable === true;
14799
- }
14800
- canDrop(draggable, target) {
14801
- return this.reorderable && rules({ draggable, target });
14856
+ return accessor[iterator]();
14802
14857
  }
14803
- shouldActivate(column) {
14804
- const canReorder = this.isReorderable(column);
14805
- if (!canReorder && !isColumnComponent(column)) {
14806
- return false;
14858
+ removeSubscriptions() {
14859
+ if (this.cellClickSubscription) {
14860
+ this.cellClickSubscription.unsubscribe();
14861
+ this.cellClickSubscription = null;
14807
14862
  }
14808
- const groupable = this.isGroupable(column);
14809
- return groupable || canReorder;
14810
- }
14811
- isInteractive(column, prop) {
14812
- return !isNullOrEmptyString(column.field)
14813
- && isTruthy(this[prop]) && isTruthy(column[prop]);
14814
- }
14815
- isCheckboxColumn(column) {
14816
- return isCheckboxColumn(column) && !column.templateRef;
14817
- }
14818
- trackByIndex(index, _item) {
14819
- return index;
14820
- }
14821
- addStickyStyles(column) {
14822
- const stickyStyles = this.columnInfoService.stickyColumnsStyles(column);
14823
- return { ...column.headerStyle, ...stickyStyles };
14824
- }
14825
- toggleDirection(field, allowUnsort, initialDirection) {
14826
- const descriptor = this.sortDescriptor(field);
14827
- const [first, second] = directions(initialDirection);
14828
- let dir = first;
14829
- if (descriptor.dir === first) {
14830
- dir = second;
14863
+ if (this.mousedownSubscription) {
14864
+ this.mousedownSubscription.unsubscribe();
14865
+ this.mousedownSubscription = null;
14831
14866
  }
14832
- else if (descriptor.dir === second && allowUnsort) {
14833
- dir = undefined;
14867
+ if (this.dataChangedSubscription) {
14868
+ this.dataChangedSubscription.unsubscribe();
14869
+ this.dataChangedSubscription = null;
14834
14870
  }
14835
- return { dir, field };
14836
- }
14837
- columnsForLevel(level) {
14838
- const columns = this.columns ? this.columns.filter(column => column.level === level) : [];
14839
- return sortColumns(columnsToRender(columns));
14840
14871
  }
14841
- isColumnGroupComponent(column) {
14842
- return isColumnGroupComponent(column);
14872
+ }
14873
+ CellSelectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CellSelectionService, deps: [{ token: DomEventsService }, { token: CellSelectionAggregateService }, { token: LocalDataChangesService }, { token: NavigationService }], target: i0.ɵɵFactoryTarget.Injectable });
14874
+ CellSelectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CellSelectionService });
14875
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CellSelectionService, decorators: [{
14876
+ type: Injectable
14877
+ }], ctorParameters: function () { return [{ type: DomEventsService }, { type: CellSelectionAggregateService }, { type: LocalDataChangesService }, { type: NavigationService }]; } });
14878
+
14879
+ /**
14880
+ * Represents the select-all checkbox feature of the Grid ([see example](slug:grid_selection_persistence#toc-selecting-all-items)).
14881
+ *
14882
+ * @example
14883
+ * ```html
14884
+ * <input
14885
+ * type="checkbox"
14886
+ * kendoCheckBox
14887
+ * kendoGridSelectAllCheckbox
14888
+ * [state]="selectAllState"
14889
+ * (selectAllChange)="onSelectAllChange($event)"
14890
+ * />
14891
+ * ```
14892
+ */
14893
+ class SelectAllCheckboxDirective {
14894
+ constructor(selectionService, cellSelectionService, el, renderer, ngZone) {
14895
+ this.selectionService = selectionService;
14896
+ this.cellSelectionService = cellSelectionService;
14897
+ this.el = el;
14898
+ this.renderer = renderer;
14899
+ this.ngZone = ngZone;
14900
+ /**
14901
+ * Fires when the user clicks the `kendoGridSelectAllCheckbox` select-all checkbox
14902
+ * ([see example](slug:grid_row_selection#toc-select-all-checkbox)).
14903
+ */
14904
+ this.selectAllChange = new EventEmitter();
14905
+ this.type = 'checkbox';
14906
+ this.stateSet = false;
14907
+ this.ngZone.runOutsideAngular(() => {
14908
+ this.destroyClick = this.renderer.listen(this.el.nativeElement, 'click', this.onClick.bind(this));
14909
+ });
14843
14910
  }
14844
- sortDescriptor(field) {
14845
- return this.sort.find(item => item.field === field) || { field };
14911
+ ngAfterContentChecked() {
14912
+ this.setState();
14846
14913
  }
14847
- get columnLevels() {
14848
- return new Array((this.totalColumnLevels || 0) + 1);
14914
+ ngOnChanges() {
14915
+ this.stateSet = true;
14849
14916
  }
14850
- get leafColumns() {
14851
- return this._leafColumns;
14917
+ ngOnDestroy() {
14918
+ if (this.destroyClick) {
14919
+ this.destroyClick();
14920
+ }
14852
14921
  }
14853
- isReorderable(column) {
14854
- return this.reorderable && column.reorderable;
14922
+ /**
14923
+ * @hidden
14924
+ */
14925
+ onClick() {
14926
+ const uncheckedState = this.el.nativeElement.indeterminate ? 'indeterminate' : 'unchecked';
14927
+ const checkboxState = this.el.nativeElement.checked ? 'checked' : uncheckedState;
14928
+ const isChecked = this.selectionService.hasNonSelectable ? !this.selectionService.selectAllChecked : this.el.nativeElement.checked;
14929
+ const options = this.selectionService.options;
14930
+ const enabledAndMultiple = options.enabled && options.mode === 'multiple' && !this.cellSelectionService.active;
14931
+ const shouldEmitSelectAll = hasObservers(this.selectAllChange);
14932
+ if (enabledAndMultiple || shouldEmitSelectAll) {
14933
+ this.ngZone.run(() => {
14934
+ if (enabledAndMultiple) {
14935
+ this.selectionService.updateAll(isChecked);
14936
+ }
14937
+ if (shouldEmitSelectAll) {
14938
+ this.selectAllChange.emit(checkboxState);
14939
+ }
14940
+ });
14941
+ }
14855
14942
  }
14856
- isGroupable(column) {
14857
- return this.groupable && isColumnComponent(column) && column.groupable !== false;
14943
+ /**
14944
+ * @hidden
14945
+ */
14946
+ setState() {
14947
+ const state = this.stateSet ? this.stateToBool() : this.selectionService.selectAllState;
14948
+ const elem = this.el.nativeElement;
14949
+ this.renderer.setProperty(elem, 'indeterminate', !isPresent(state));
14950
+ this.renderer.setProperty(elem, 'checked', isPresent(state) ? state : false);
14858
14951
  }
14859
- attachTargets() {
14860
- if (this.targetSubscription) {
14861
- this.targetSubscription.unsubscribe();
14952
+ /**
14953
+ * @hidden
14954
+ */
14955
+ stateToBool() {
14956
+ switch (this.state) {
14957
+ case 'checked':
14958
+ return true;
14959
+ case 'unchecked':
14960
+ return false;
14961
+ default:
14962
+ return undefined;
14862
14963
  }
14863
- this.targetSubscription = new Subscription();
14864
- const enterStream = merge(...this.dropTargets.map(target => target.enter));
14865
- const leaveStream = merge(...this.dropTargets.map(target => target.leave));
14866
- const dropStream = merge(...this.dropTargets.map(target => target.drop));
14867
- this.targetSubscription.add(enterStream.pipe(tap(({ target, draggable }) => {
14868
- if (draggable.context.type === 'groupIndicator') {
14869
- return;
14870
- }
14871
- const targetLocked = isTruthy(target.context.column.isLocked);
14872
- const draggableLocked = isTruthy(draggable.context.column.isLocked);
14873
- if (this.lockedColumnsCount > 0 || targetLocked || draggableLocked) {
14874
- this.hint.toggleLock(targetLocked);
14875
- }
14876
- }), filter(({ draggable, target }) => this.canDrop(draggable, target)), switchMap(this.trackMove.bind(this, leaveStream, dropStream)), map((e) => mergeObjects(e, { before: this.calculateBefore(e), changeContainer: e.changeContainer })), map(this.normalizeTarget.bind(this)), tap(this.enter.bind(this)), switchMap((args) => dropStream.pipe(map(() => args), takeUntil(leaveStream.pipe(tap(this.leave.bind(this)))))))
14877
- .subscribe(this.drop.bind(this)));
14878
14964
  }
14879
- normalizeTarget(e) {
14880
- let target = e.target;
14881
- const parent = target.context.column.parent;
14882
- if (parent && parent.isSpanColumn) {
14883
- const arr = this.dropTargets.toArray();
14884
- const firstSpan = arr.find(t => t.context.column.parent === parent);
14885
- const index = arr.indexOf(firstSpan);
14886
- const adjust = e.before ? 0 : parent.childColumns.length - 1;
14887
- target = arr[index + adjust];
14888
- }
14889
- return mergeObjects(e, { target });
14965
+ }
14966
+ SelectAllCheckboxDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SelectAllCheckboxDirective, deps: [{ token: SelectionService }, { token: CellSelectionService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
14967
+ SelectAllCheckboxDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: SelectAllCheckboxDirective, isStandalone: true, selector: "[kendoGridSelectAllCheckbox]", inputs: { state: "state" }, outputs: { selectAllChange: "selectAllChange" }, host: { properties: { "attr.type": "this.type" } }, usesOnChanges: true, ngImport: i0 });
14968
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SelectAllCheckboxDirective, decorators: [{
14969
+ type: Directive,
14970
+ args: [{
14971
+ selector: '[kendoGridSelectAllCheckbox]',
14972
+ standalone: true
14973
+ }]
14974
+ }], ctorParameters: function () { return [{ type: SelectionService }, { type: CellSelectionService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, propDecorators: { state: [{
14975
+ type: Input
14976
+ }], selectAllChange: [{
14977
+ type: Output
14978
+ }], type: [{
14979
+ type: HostBinding,
14980
+ args: ['attr.type']
14981
+ }] } });
14982
+
14983
+ const mergeObjects = (...args) => Object.assign.apply(null, [{}].concat(args));
14984
+ const directions = initialDirection => initialDirection === "asc" ? ["asc", "desc"] : ["desc", "asc"];
14985
+ /**
14986
+ * @hidden
14987
+ */
14988
+ const isRootLevel = ({ parent }) => !isTruthy(parent);
14989
+ const ofColumnType = ({ draggable }) => ['column', 'columnGroup']
14990
+ .indexOf(draggable.context.type) >= 0;
14991
+ const notSameElement = ({ draggable, target }) => draggable.element.nativeElement !== target.element.nativeElement;
14992
+ const inSameParent = (x, y) => x.parent === y.parent ||
14993
+ (isInSpanColumn$1(y) && inSameParent(x, y.parent));
14994
+ const sameParent = ({ draggable, target }) => inSameParent(draggable.context.column, target.context.column);
14995
+ const lastNonLocked = ({ draggable }) => !isTruthy(draggable.context.column.locked) &&
14996
+ isRootLevel(draggable.context.column) &&
14997
+ draggable.context.lastColumn;
14998
+ const notInSpanColumn = ({ draggable }) => !isInSpanColumn$1(draggable.context.column);
14999
+ const reorderable = ({ draggable }) => draggable.context.column.reorderable;
15000
+ const lockable = ({ draggable, target }) => draggable.context.column.lockable !== false ||
15001
+ draggable.context.column.isLocked === target.context.column.isLocked;
15002
+ const rules = and(ofColumnType, reorderable, notInSpanColumn, notSameElement, sameParent, not(lastNonLocked), lockable);
15003
+ const modifierKeys = ['alt', 'ctrl', 'shift', 'meta'];
15004
+ /**
15005
+ * @hidden
15006
+ */
15007
+ class HeaderComponent {
15008
+ constructor(popupService, hint, cue, reorderService, idService, sortService, columnInfoService, cd, contextService, navigationService) {
15009
+ this.popupService = popupService;
15010
+ this.hint = hint;
15011
+ this.cue = cue;
15012
+ this.reorderService = reorderService;
15013
+ this.idService = idService;
15014
+ this.sortService = sortService;
15015
+ this.columnInfoService = columnInfoService;
15016
+ this.cd = cd;
15017
+ this.contextService = contextService;
15018
+ this.navigationService = navigationService;
15019
+ this.columns = [];
15020
+ this.groups = [];
15021
+ this.sort = new Array();
15022
+ this.sortable = false;
15023
+ this.groupable = false;
15024
+ this.lockedColumnsCount = 0;
15025
+ this.resizable = false;
15026
+ this.reorderable = false;
15027
+ this.columnMenu = false;
15028
+ this.totalColumnsCount = 0;
15029
+ this.size = 'medium';
15030
+ this.sortedFields = {};
15031
+ this.hostClass = true;
15032
+ this.dropTargets = new QueryList();
15033
+ this.sortAscSmallIcon = sortAscSmallIcon;
15034
+ this.sortDescSmallIcon = sortDescSmallIcon;
15035
+ this.subscription = new Subscription();
14890
15036
  }
14891
- trackMove(leaveStream, dropStream, e) {
14892
- const column = e.target.context.column;
14893
- const levelColumns = this.columnsForLevel(column.level);
14894
- const index = levelColumns.indexOf(column);
14895
- const isFirst = (column.locked ? index === levelColumns.length - 1 : index === 0);
14896
- const changed = e.draggable.context.column.isLocked !== column.isLocked;
14897
- if (changed && isFirst) {
14898
- return e.draggable.drag
14899
- .pipe(takeUntil(leaveStream), takeUntil(dropStream), map(({ mouseEvent }) => mergeObjects({ changeContainer: true }, e, { mouseEvent })));
15037
+ get headerClass() {
15038
+ return !this.scrollable;
15039
+ }
15040
+ get sortableLabel() {
15041
+ return this.contextService.localization.get('sortable');
15042
+ }
15043
+ get columnMenuSettings() {
15044
+ return this.columnMenu;
15045
+ }
15046
+ // Number of unlocked columns in the next table, if any
15047
+ get unlockedColumnsCount() {
15048
+ return this.totalColumnsCount - this.lockedColumnsCount - this.columns.length;
15049
+ }
15050
+ sortColumn(descriptor) {
15051
+ this.sortService.sort(descriptor);
15052
+ }
15053
+ getColumnComponent(column) {
15054
+ return column;
15055
+ }
15056
+ onSortClick(column, event, link) {
15057
+ const target = event.target;
15058
+ if (column.headerTemplateRef && target !== link) {
15059
+ const hasFocusableParent = Boolean(closestInScope(target, isFocusable, link));
15060
+ if (hasFocusableParent) {
15061
+ // Do not sort when clicking focusable template elements.
15062
+ return;
15063
+ }
14900
15064
  }
14901
- return of(mergeObjects({ changeContainer: changed }, e));
15065
+ const modifier = this.matchModifier(event);
15066
+ const toggledColumn = this.toggleSort(column, modifier);
15067
+ this.sortColumn(toggledColumn);
14902
15068
  }
14903
- calculateBefore({ draggable, target, mouseEvent, changeContainer = false }) {
14904
- const targetElement = target.element.nativeElement;
14905
- let before = false;
14906
- if (changeContainer) {
14907
- const { left } = offset(targetElement);
14908
- const halfWidth = targetElement.offsetWidth / 2;
14909
- const middle = left + halfWidth;
14910
- before = middle > mouseEvent.pageX;
14911
- if (this.contextService.localization.rtl) {
14912
- before = !before;
15069
+ onHeaderKeydown(column, args) {
15070
+ if (args.keyCode === Keys.ArrowDown && args.altKey && this.showFilterMenu) {
15071
+ args.preventDefault();
15072
+ args.stopImmediatePropagation();
15073
+ const filterMenu = this.filterMenus.find(fm => fm.column === column);
15074
+ filterMenu.toggle(filterMenu.anchor.nativeElement, filterMenu.template);
15075
+ return;
15076
+ }
15077
+ if (args.keyCode === Keys.ArrowDown && args.altKey && this.showColumnMenu(column)) {
15078
+ args.preventDefault();
15079
+ args.stopImmediatePropagation();
15080
+ const columnMenu = this.columnMenus.find(cm => cm.column === column);
15081
+ columnMenu.toggle(null, columnMenu.anchor.nativeElement, columnMenu.template);
15082
+ return;
15083
+ }
15084
+ const isCtrlOrMeta = args.ctrlKey || args.metaKey;
15085
+ const isGroupingKeyShortcut = (args.keyCode === Keys.Enter || args.keyCode === Keys.Space) && isCtrlOrMeta;
15086
+ if (isGroupingKeyShortcut && this.isGroupable(column)) {
15087
+ args.preventDefault();
15088
+ args.stopImmediatePropagation();
15089
+ const isGroupedByField = this.groups.some(gr => gr.field === column.field);
15090
+ if (isGroupedByField) {
15091
+ this.groups = this.groups.filter(gr => gr.field !== column.field);
14913
15092
  }
15093
+ else {
15094
+ this.groups.push({
15095
+ field: column.field
15096
+ });
15097
+ }
15098
+ this.contextService.grid.groupChange.emit(this.groups);
15099
+ return;
14914
15100
  }
14915
- else {
14916
- before = isTargetBefore(draggable.element.nativeElement, targetElement);
15101
+ const isLeftOrRightArrow = args.keyCode === Keys.ArrowLeft || args.keyCode === Keys.ArrowRight;
15102
+ const isReorderingKeyShortcut = isLeftOrRightArrow && isCtrlOrMeta;
15103
+ if (isReorderingKeyShortcut && this.isReorderable(column)) {
15104
+ args.preventDefault();
15105
+ const columnsCount = this.columnInfoService.leafNamedColumns.length;
15106
+ const reorderDirection = args.keyCode === Keys.ArrowLeft ? -1 : 1;
15107
+ const rtlMultiplier = this.contextService.localization.rtl ? -1 : 1;
15108
+ const reorderDirectionOffset = reorderDirection * rtlMultiplier;
15109
+ const newIndex = column.leafIndex + reorderDirectionOffset;
15110
+ const normalizedNewIndex = Math.min(Math.max(0, newIndex), columnsCount - 1);
15111
+ const gridInstance = this.contextService.grid;
15112
+ gridInstance.reorderColumn(column, normalizedNewIndex, { before: reorderDirectionOffset < 0 });
15113
+ gridInstance.columnReorder.emit(new ColumnReorderEvent({
15114
+ column,
15115
+ newIndex: normalizedNewIndex,
15116
+ oldIndex: column.leafIndex
15117
+ }));
15118
+ return;
15119
+ }
15120
+ if (!this.sortable || args.defaultPrevented || column.sortable === false) {
15121
+ return;
15122
+ }
15123
+ if (args.keyCode === Keys.Enter && isPresent(column.field)) {
15124
+ const modifier = this.matchModifier(args);
15125
+ this.sortService.sort(this.toggleSort(column, modifier));
14917
15126
  }
14918
- return before;
14919
15127
  }
14920
- enter({ target, before }) {
14921
- this.hint.enable();
14922
- if (this.contextService.localization.rtl) {
14923
- before = !before;
15128
+ showSortNumbering(column) {
15129
+ const { showIndexes } = normalize$1(this.sortable);
15130
+ return showIndexes
15131
+ && this.sort
15132
+ && this.sort.filter(({ dir }) => isPresent(dir)).length > 1
15133
+ && this.sortOrder(column.field) > 0;
15134
+ }
15135
+ sortOrder(field) {
15136
+ return this.sort
15137
+ .filter(({ dir }) => isPresent(dir))
15138
+ .findIndex(x => x.field === field)
15139
+ + 1;
15140
+ }
15141
+ sortState(column) {
15142
+ if (!this.isInteractive(column, 'sortable')) {
15143
+ return;
15144
+ }
15145
+ const state = this.sortDescriptor(column.field);
15146
+ if (state.dir === 'asc') {
15147
+ return 'ascending';
15148
+ }
15149
+ if (state.dir === 'desc') {
15150
+ return 'descending';
14924
15151
  }
14925
- this.cue.position(position(target.element.nativeElement, before));
14926
15152
  }
14927
- leave() {
14928
- this.hint.disable();
14929
- this.cue.hide();
15153
+ get isNavigable() {
15154
+ return this.navigationService.tableEnabled;
14930
15155
  }
14931
- drop({ draggable, target, before, changeContainer }) {
14932
- this.reorderService.reorder({
14933
- before,
14934
- changeContainer,
14935
- source: draggable.context.column,
14936
- target: target.context.column
14937
- });
15156
+ /**
15157
+ *
15158
+ * @param column
15159
+ * @param modifier - Indicates whether the client-defined `multiSortKey` modifier is met. Defaults to `true`.
15160
+ * @returns - SortDescriptor[]
15161
+ */
15162
+ toggleSort(column, modifier = true) {
15163
+ const { allowUnsort, mode, initialDirection } = normalize$1(this.sortable, column.sortable);
15164
+ const descriptor = this.toggleDirection(column.field, allowUnsort, initialDirection);
15165
+ if (mode === 'single' || !modifier) {
15166
+ return [descriptor];
15167
+ }
15168
+ return [...this.sort.filter(desc => desc.field !== column.field), descriptor];
14938
15169
  }
14939
- }
14940
- HeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: HeaderComponent, deps: [{ token: SinglePopupService }, { token: DragHintService }, { token: DropCueService }, { token: ColumnReorderService }, { token: IdService }, { token: SortService }, { token: ColumnInfoService }, { token: i0.ChangeDetectorRef }, { token: ContextService }, { token: NavigationService }], target: i0.ɵɵFactoryTarget.Component });
14941
- HeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: HeaderComponent, isStandalone: true, selector: "[kendoGridHeader]", inputs: { totalColumnLevels: "totalColumnLevels", columns: "columns", groups: "groups", detailTemplate: "detailTemplate", scrollable: "scrollable", filterable: "filterable", sort: "sort", filter: "filter", sortable: "sortable", groupable: "groupable", lockedColumnsCount: "lockedColumnsCount", resizable: "resizable", reorderable: "reorderable", columnMenu: "columnMenu", columnMenuTemplate: "columnMenuTemplate", totalColumnsCount: "totalColumnsCount", totalColumns: "totalColumns", tabIndex: "tabIndex", size: "size" }, host: { properties: { "class.k-grid-header": "this.headerClass", "class.k-table-thead": "this.hostClass" } }, viewQueries: [{ propertyName: "dropTargets", predicate: DropTargetDirective, descendants: true }, { propertyName: "filterMenus", predicate: FilterMenuComponent, descendants: true }, { propertyName: "columnMenus", predicate: ColumnMenuComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
14942
- <ng-container>
14943
- <tr *ngFor="let i of columnLevels; let levelIndex = index"
14944
- kendoGridLogicalRow
14945
- [logicalRowIndex]="levelIndex"
14946
- [logicalSlaveRow]="lockedColumnsCount > 0"
14947
- [logicalCellsCount]="columns.length"
14948
- [logicalSlaveCellsCount]="unlockedColumnsCount"
14949
- [totalColumns]="totalColumns">
14950
- <th
14951
- class="k-group-cell k-header k-table-th"
14952
- role="presentation"
14953
- *ngFor="let g of groups">
14954
- </th>
15170
+ /**
15171
+ *
15172
+ * Determines whether the modifier key (if any) passed
15173
+ * with a click/keyboard event matches the user-defined multiSortKey.
15174
+ */
15175
+ matchModifier(event) {
15176
+ const { multiSortKey } = normalize$1(this.sortable);
15177
+ if (multiSortKey === 'none') {
15178
+ return modifierKeys.every(key => !event[`${key}Key`]);
15179
+ }
15180
+ return multiSortKey === 'ctrl'
15181
+ ? event.ctrlKey || event.metaKey
15182
+ : event[`${multiSortKey}Key`];
15183
+ }
15184
+ ngAfterViewInit() {
15185
+ this.subscription.add(observe(this.dropTargets)
15186
+ .subscribe(this.attachTargets.bind(this)));
15187
+ }
15188
+ ngDoCheck() {
15189
+ this._leafColumns = columnsToRender(this.columns || []).filter(x => !isColumnGroupComponent(x));
15190
+ }
15191
+ ngOnChanges(changes) {
15192
+ const sortChange = changes.sort;
15193
+ if (sortChange && !sortChange.isFirstChange()) {
15194
+ sortChange.currentValue.forEach(change => {
15195
+ this.sortedFields[change.field] = true;
15196
+ });
15197
+ }
15198
+ }
15199
+ ngOnInit() {
15200
+ this.subscription.add(this.contextService.localization.changes
15201
+ .subscribe(() => this.cd.markForCheck()));
15202
+ }
15203
+ ngOnDestroy() {
15204
+ if (this.targetSubscription) {
15205
+ this.targetSubscription.unsubscribe();
15206
+ }
15207
+ if (this.popupService) {
15208
+ this.popupService.destroy();
15209
+ }
15210
+ this.subscription.unsubscribe();
15211
+ }
15212
+ selectAllCheckboxId() {
15213
+ return this.idService.selectAllCheckboxId();
15214
+ }
15215
+ get selectAllCheckboxLabel() {
15216
+ return this.contextService.localization.get('selectAllCheckboxLabel');
15217
+ }
15218
+ isFirstOnRow(column, index) {
15219
+ const isTailing = (c) => c &&
15220
+ (this.columnsForLevel(c.level).indexOf(c) > 0 || isTailing(c.parent));
15221
+ return index === 0 && !this.groups.length && !this.detailTemplate && isTailing(column.parent);
15222
+ }
15223
+ logicalColumnIndex(column) {
15224
+ const index = column.leafIndex;
15225
+ if (isPresent(index)) {
15226
+ return index + (isPresent(this.detailTemplate) ? 1 : 0);
15227
+ }
15228
+ return -1;
15229
+ }
15230
+ get showFilterMenu() {
15231
+ return !this.columnMenu && hasFilterMenu(this.filterable);
15232
+ }
15233
+ get showFilterRow() {
15234
+ return hasFilterRow(this.filterable);
15235
+ }
15236
+ showColumnMenu(column) {
15237
+ return this.columnMenu && column.columnMenu &&
15238
+ (this.columnMenuTemplate || column.columnMenuTemplates.length || hasItems(this.columnMenu, column));
15239
+ }
15240
+ isFilterable(column) {
15241
+ return !isNullOrEmptyString(column.field) && column.filterable === true;
15242
+ }
15243
+ canDrop(draggable, target) {
15244
+ return this.reorderable && rules({ draggable, target });
15245
+ }
15246
+ shouldActivate(column) {
15247
+ const canReorder = this.isReorderable(column);
15248
+ if (!canReorder && !isColumnComponent(column)) {
15249
+ return false;
15250
+ }
15251
+ const groupable = this.isGroupable(column);
15252
+ return groupable || canReorder;
15253
+ }
15254
+ isInteractive(column, prop) {
15255
+ return !isNullOrEmptyString(column.field)
15256
+ && isTruthy(this[prop]) && isTruthy(column[prop]);
15257
+ }
15258
+ isCheckboxColumn(column) {
15259
+ return isCheckboxColumn(column) && !column.templateRef;
15260
+ }
15261
+ trackByIndex(index, _item) {
15262
+ return index;
15263
+ }
15264
+ addStickyStyles(column) {
15265
+ const stickyStyles = this.columnInfoService.stickyColumnsStyles(column);
15266
+ return { ...column.headerStyle, ...stickyStyles };
15267
+ }
15268
+ toggleDirection(field, allowUnsort, initialDirection) {
15269
+ const descriptor = this.sortDescriptor(field);
15270
+ const [first, second] = directions(initialDirection);
15271
+ let dir = first;
15272
+ if (descriptor.dir === first) {
15273
+ dir = second;
15274
+ }
15275
+ else if (descriptor.dir === second && allowUnsort) {
15276
+ dir = undefined;
15277
+ }
15278
+ return { dir, field };
15279
+ }
15280
+ columnsForLevel(level) {
15281
+ const columns = this.columns ? this.columns.filter(column => column.level === level) : [];
15282
+ return sortColumns(columnsToRender(columns));
15283
+ }
15284
+ isColumnGroupComponent(column) {
15285
+ return isColumnGroupComponent(column);
15286
+ }
15287
+ sortDescriptor(field) {
15288
+ return this.sort.find(item => item.field === field) || { field };
15289
+ }
15290
+ get columnLevels() {
15291
+ return new Array((this.totalColumnLevels || 0) + 1);
15292
+ }
15293
+ get leafColumns() {
15294
+ return this._leafColumns;
15295
+ }
15296
+ isReorderable(column) {
15297
+ return this.reorderable && column.reorderable;
15298
+ }
15299
+ isGroupable(column) {
15300
+ return this.groupable && isColumnComponent(column) && column.groupable !== false;
15301
+ }
15302
+ attachTargets() {
15303
+ if (this.targetSubscription) {
15304
+ this.targetSubscription.unsubscribe();
15305
+ }
15306
+ this.targetSubscription = new Subscription();
15307
+ const enterStream = merge(...this.dropTargets.map(target => target.enter));
15308
+ const leaveStream = merge(...this.dropTargets.map(target => target.leave));
15309
+ const dropStream = merge(...this.dropTargets.map(target => target.drop));
15310
+ this.targetSubscription.add(enterStream.pipe(tap(({ target, draggable }) => {
15311
+ if (draggable.context.type === 'groupIndicator') {
15312
+ return;
15313
+ }
15314
+ const targetLocked = isTruthy(target.context.column.isLocked);
15315
+ const draggableLocked = isTruthy(draggable.context.column.isLocked);
15316
+ if (this.lockedColumnsCount > 0 || targetLocked || draggableLocked) {
15317
+ this.hint.toggleLock(targetLocked);
15318
+ }
15319
+ }), filter(({ draggable, target }) => this.canDrop(draggable, target)), switchMap(this.trackMove.bind(this, leaveStream, dropStream)), map((e) => mergeObjects(e, { before: this.calculateBefore(e), changeContainer: e.changeContainer })), map(this.normalizeTarget.bind(this)), tap(this.enter.bind(this)), switchMap((args) => dropStream.pipe(map(() => args), takeUntil(leaveStream.pipe(tap(this.leave.bind(this)))))))
15320
+ .subscribe(this.drop.bind(this)));
15321
+ }
15322
+ normalizeTarget(e) {
15323
+ let target = e.target;
15324
+ const parent = target.context.column.parent;
15325
+ if (parent && parent.isSpanColumn) {
15326
+ const arr = this.dropTargets.toArray();
15327
+ const firstSpan = arr.find(t => t.context.column.parent === parent);
15328
+ const index = arr.indexOf(firstSpan);
15329
+ const adjust = e.before ? 0 : parent.childColumns.length - 1;
15330
+ target = arr[index + adjust];
15331
+ }
15332
+ return mergeObjects(e, { target });
15333
+ }
15334
+ trackMove(leaveStream, dropStream, e) {
15335
+ const column = e.target.context.column;
15336
+ const levelColumns = this.columnsForLevel(column.level);
15337
+ const index = levelColumns.indexOf(column);
15338
+ const isFirst = (column.locked ? index === levelColumns.length - 1 : index === 0);
15339
+ const changed = e.draggable.context.column.isLocked !== column.isLocked;
15340
+ if (changed && isFirst) {
15341
+ return e.draggable.drag
15342
+ .pipe(takeUntil(leaveStream), takeUntil(dropStream), map(({ mouseEvent }) => mergeObjects({ changeContainer: true }, e, { mouseEvent })));
15343
+ }
15344
+ return of(mergeObjects({ changeContainer: changed }, e));
15345
+ }
15346
+ calculateBefore({ draggable, target, mouseEvent, changeContainer = false }) {
15347
+ const targetElement = target.element.nativeElement;
15348
+ let before = false;
15349
+ if (changeContainer) {
15350
+ const { left } = offset(targetElement);
15351
+ const halfWidth = targetElement.offsetWidth / 2;
15352
+ const middle = left + halfWidth;
15353
+ before = middle > mouseEvent.pageX;
15354
+ if (this.contextService.localization.rtl) {
15355
+ before = !before;
15356
+ }
15357
+ }
15358
+ else {
15359
+ before = isTargetBefore(draggable.element.nativeElement, targetElement);
15360
+ }
15361
+ return before;
15362
+ }
15363
+ enter({ target, before }) {
15364
+ this.hint.enable();
15365
+ if (this.contextService.localization.rtl) {
15366
+ before = !before;
15367
+ }
15368
+ this.cue.position(position(target.element.nativeElement, before));
15369
+ }
15370
+ leave() {
15371
+ this.hint.disable();
15372
+ this.cue.hide();
15373
+ }
15374
+ drop({ draggable, target, before, changeContainer }) {
15375
+ this.reorderService.reorder({
15376
+ before,
15377
+ changeContainer,
15378
+ source: draggable.context.column,
15379
+ target: target.context.column
15380
+ });
15381
+ }
15382
+ }
15383
+ HeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: HeaderComponent, deps: [{ token: SinglePopupService }, { token: DragHintService }, { token: DropCueService }, { token: ColumnReorderService }, { token: IdService }, { token: SortService }, { token: ColumnInfoService }, { token: i0.ChangeDetectorRef }, { token: ContextService }, { token: NavigationService }], target: i0.ɵɵFactoryTarget.Component });
15384
+ HeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: HeaderComponent, isStandalone: true, selector: "[kendoGridHeader]", inputs: { totalColumnLevels: "totalColumnLevels", columns: "columns", groups: "groups", detailTemplate: "detailTemplate", scrollable: "scrollable", filterable: "filterable", sort: "sort", filter: "filter", sortable: "sortable", groupable: "groupable", lockedColumnsCount: "lockedColumnsCount", resizable: "resizable", reorderable: "reorderable", columnMenu: "columnMenu", columnMenuTemplate: "columnMenuTemplate", totalColumnsCount: "totalColumnsCount", totalColumns: "totalColumns", tabIndex: "tabIndex", size: "size" }, host: { properties: { "class.k-grid-header": "this.headerClass", "class.k-table-thead": "this.hostClass" } }, viewQueries: [{ propertyName: "dropTargets", predicate: DropTargetDirective, descendants: true }, { propertyName: "filterMenus", predicate: FilterMenuComponent, descendants: true }, { propertyName: "columnMenus", predicate: ColumnMenuComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
15385
+ <ng-container>
15386
+ <tr *ngFor="let i of columnLevels; let levelIndex = index"
15387
+ kendoGridLogicalRow
15388
+ [logicalRowIndex]="levelIndex"
15389
+ [logicalSlaveRow]="lockedColumnsCount > 0"
15390
+ [logicalCellsCount]="columns.length"
15391
+ [logicalSlaveCellsCount]="unlockedColumnsCount"
15392
+ [totalColumns]="totalColumns">
15393
+ <th
15394
+ class="k-group-cell k-header k-table-th"
15395
+ role="presentation"
15396
+ *ngFor="let g of groups">
15397
+ </th>
14955
15398
  <th class="k-hierarchy-cell k-header k-table-th"
14956
15399
  role="presentation"
14957
15400
  *ngIf="detailTemplate?.templateRef"
@@ -15680,9 +16123,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
15680
16123
  * ```
15681
16124
  */
15682
16125
  class CheckboxColumnComponent extends ColumnBase {
15683
- constructor(parent, idService) {
16126
+ constructor(selectionService, cellSelectionService, parent, idService) {
15684
16127
  super(parent, idService);
16128
+ this.selectionService = selectionService;
16129
+ this.cellSelectionService = cellSelectionService;
15685
16130
  this.parent = parent;
16131
+ /**
16132
+ * Determines whether checkboxes will be rendered for rows which are marked as non-selectable. By default, such checkboxes are visible and disabled.
16133
+ */
16134
+ this.showDisabledCheckbox = true;
15686
16135
  /*
15687
16136
  * @hidden
15688
16137
  */
@@ -15691,9 +16140,15 @@ class CheckboxColumnComponent extends ColumnBase {
15691
16140
  get templateRef() {
15692
16141
  return this.template ? this.template.templateRef : undefined;
15693
16142
  }
16143
+ /**
16144
+ * @hidden
16145
+ */
16146
+ rowSelectable(rowIdx) {
16147
+ return !this.selectionService.nonSelectableRows.has(rowIdx) && !this.cellSelectionService.nonSelectableRows.has(rowIdx);
16148
+ }
15694
16149
  }
15695
- CheckboxColumnComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CheckboxColumnComponent, deps: [{ token: ColumnBase, host: true, optional: true, skipSelf: true }, { token: IdService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
15696
- CheckboxColumnComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: CheckboxColumnComponent, isStandalone: true, selector: "kendo-grid-checkbox-column", inputs: { showSelectAll: "showSelectAll" }, providers: [
16150
+ CheckboxColumnComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CheckboxColumnComponent, deps: [{ token: SelectionService }, { token: CellSelectionService }, { token: ColumnBase, host: true, optional: true, skipSelf: true }, { token: IdService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
16151
+ CheckboxColumnComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: CheckboxColumnComponent, isStandalone: true, selector: "kendo-grid-checkbox-column", inputs: { showSelectAll: "showSelectAll", showDisabledCheckbox: "showDisabledCheckbox" }, providers: [
15697
16152
  {
15698
16153
  provide: ColumnBase,
15699
16154
  useExisting: forwardRef(() => CheckboxColumnComponent)
@@ -15712,7 +16167,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
15712
16167
  template: ``,
15713
16168
  standalone: true
15714
16169
  }]
15715
- }], ctorParameters: function () { return [{ type: ColumnBase, decorators: [{
16170
+ }], ctorParameters: function () { return [{ type: SelectionService }, { type: CellSelectionService }, { type: ColumnBase, decorators: [{
15716
16171
  type: SkipSelf
15717
16172
  }, {
15718
16173
  type: Host
@@ -15722,478 +16177,193 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
15722
16177
  type: Optional
15723
16178
  }] }]; }, propDecorators: { showSelectAll: [{
15724
16179
  type: Input
16180
+ }], showDisabledCheckbox: [{
16181
+ type: Input
15725
16182
  }], template: [{
15726
16183
  type: ContentChild,
15727
16184
  args: [CellTemplateDirective, { static: false }]
15728
16185
  }] } });
15729
16186
 
15730
- /**
15731
- * Represents the row-selection checkbox of the Grid. The directive expects the
15732
- * index of the current row as an input parameter. Inside the [`CellTemplateDirective`](slug:api_grid_celltemplatedirective), apply the
15733
- * `kendoGridSelectionCheckbox` to an `<input type="checkbox"/>` element. When the user clicks the checkbox that is associated
15734
- * with the directive, a [selectionChange](slug:api_grid_gridcomponent#toc-selectionChange)
15735
- * event is triggered.
15736
- *
15737
- * @example
15738
- * ```html
15739
- * <kendo-grid ... >
15740
- * <kendo-grid-column>
15741
- * <ng-template kendoGridCellTemplate let-rowIndex="rowIndex">
15742
- * <input ... [kendoGridSelectionCheckbox]="rowIndex"/>
15743
- * </ng-template>
15744
- * </kendo-grid-column>
15745
- * </kendo-grid>
15746
- * ```
15747
- */
15748
- class SelectionCheckboxDirective {
15749
- constructor(selectionService, aggregateService, el, renderer, ngZone) {
15750
- this.selectionService = selectionService;
15751
- this.aggregateService = aggregateService;
15752
- this.el = el;
15753
- this.renderer = renderer;
15754
- this.ngZone = ngZone;
15755
- this.type = 'checkbox';
15756
- this.ngZone.runOutsideAngular(() => {
15757
- this.destroyClick = this.renderer.listen(this.el.nativeElement, 'click', this.onClick.bind(this));
15758
- this.destroyKeyDown = this.renderer.listen(this.el.nativeElement, 'keydown', this.onKeyDown.bind(this));
15759
- });
15760
- }
15761
- ngAfterContentChecked() {
15762
- this.setCheckedState();
15763
- }
15764
- ngOnDestroy() {
15765
- if (this.destroyClick) {
15766
- this.destroyClick();
15767
- }
15768
- if (this.destroyKeyDown) {
15769
- this.destroyKeyDown();
15770
- }
15771
- }
15772
- onClick() {
15773
- if (this.selectionService.options.enabled) {
15774
- this.ngZone.run(() => {
15775
- const ev = this.selectionService.toggleByIndex(this.itemIndex);
15776
- ev.ctrlKey = true;
15777
- ev.shiftKey = false;
15778
- if (this.selectionService.options.cellAggregates) {
15779
- ev.cellAggregates = this.aggregateService.onSelectionChange(ev);
15780
- }
15781
- this.selectionService.changes.emit(ev);
15782
- });
15783
- }
15784
- }
15785
- onKeyDown(e) {
15786
- if (e.keyCode === Keys.Enter) {
15787
- this.onClick();
15788
- }
15789
- }
15790
- /*
15791
- * @hidden
15792
- */
15793
- setCheckedState() {
15794
- this.renderer.setProperty(this.el.nativeElement, 'checked', this.selectionService.isSelected(this.itemIndex));
15795
- }
15796
- }
15797
- SelectionCheckboxDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SelectionCheckboxDirective, deps: [{ token: SelectionService }, { token: CellSelectionAggregateService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
15798
- SelectionCheckboxDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: SelectionCheckboxDirective, isStandalone: true, selector: "[kendoGridSelectionCheckbox]", inputs: { itemIndex: ["kendoGridSelectionCheckbox", "itemIndex"] }, host: { properties: { "attr.type": "this.type" } }, ngImport: i0 });
15799
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SelectionCheckboxDirective, decorators: [{
15800
- type: Directive,
15801
- args: [{
15802
- selector: '[kendoGridSelectionCheckbox]',
15803
- standalone: true
15804
- }]
15805
- }], ctorParameters: function () { return [{ type: SelectionService }, { type: CellSelectionAggregateService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, propDecorators: { itemIndex: [{
15806
- type: Input,
15807
- args: ['kendoGridSelectionCheckbox']
15808
- }], type: [{
15809
- type: HostBinding,
15810
- args: ['attr.type']
15811
- }] } });
15812
-
15813
- /**
15814
- * @hidden
15815
- */
15816
- class ChangeNotificationService {
15817
- constructor(ngZone) {
15818
- this.ngZone = ngZone;
15819
- this.changes = new EventEmitter();
15820
- }
15821
- notify() {
15822
- if (!this.subscription || this.subscription.closed) {
15823
- this.subscription = this.ngZone.onStable
15824
- .asObservable().pipe(take(1))
15825
- .subscribe(() => this.changes.emit());
15826
- }
15827
- }
15828
- }
15829
- ChangeNotificationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ChangeNotificationService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
15830
- ChangeNotificationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ChangeNotificationService });
15831
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ChangeNotificationService, decorators: [{
15832
- type: Injectable
15833
- }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
15834
-
15835
- /**
15836
- * Represents the no-records template of the Grid. Provides an option to customize the
15837
- * appearance of the item that is displayed when no data is present.
15838
- * To define the no-records template, nest an `<ng-template>` tag with the `kendoGridNoRecordsTemplate`
15839
- * directive inside `<kendo-grid>` [see example](slug:norecordtemplate_grid).
15840
- *
15841
- * @example
15842
- * ```html
15843
- * <kendo-grid [data]="data">
15844
- * <ng-template kendoGridNoRecordsTemplate>
15845
- * There are not products. <a href="#" (click)="refresh()">Click here to refresh</a>.
15846
- * </ng-template>
15847
- * <kendo-grid-column field="ProductID"></kendo-grid-column>
15848
- * <kendo-grid-column field="ProductName"></kendo-grid-column>
15849
- * </kendo-grid>
15850
- * ```
15851
- */
15852
- class NoRecordsTemplateDirective {
15853
- constructor(templateRef) {
15854
- this.templateRef = templateRef;
15855
- }
15856
- }
15857
- NoRecordsTemplateDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NoRecordsTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
15858
- NoRecordsTemplateDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: NoRecordsTemplateDirective, isStandalone: true, selector: "[kendoGridNoRecordsTemplate]", ngImport: i0 });
15859
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NoRecordsTemplateDirective, decorators: [{
15860
- type: Directive,
15861
- args: [{
15862
- selector: '[kendoGridNoRecordsTemplate]',
15863
- standalone: true
15864
- }]
15865
- }], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
15866
- type: Optional
15867
- }] }]; } });
15868
-
15869
- /**
15870
- * @hidden
15871
- */
15872
- function defaultTrackBy(index, item) {
15873
- if (item.type === 'data' && item.isEditing) {
15874
- return item.data;
15875
- }
15876
- return index;
15877
- }
15878
-
15879
- /**
15880
- * @hidden
15881
- */
15882
- const NON_DATA_CELL_CLASSES = 'k-hierarchy-cell k-detail-cell k-group-cell';
15883
- /**
15884
- * @hidden
15885
- */
15886
- const NON_DATA_ROW_CLASSES = 'k-grouping-row k-group-footer k-detail-row k-grid-norecords';
15887
- /**
15888
- * @hidden
15889
- */
15890
- const IGNORE_TARGET_CLASSSES = 'k-icon k-svg-icon';
15891
- /**
15892
- * @hidden
15893
- */
15894
- const IGNORE_CONTAINER_CLASSES = 'k-grid k-grid-ignore-click';
15895
-
15896
- /**
15897
- * @hidden
15898
- */
15899
- class CellSelectionService {
15900
- constructor(domEvents, aggregateService, localDataChangesService, navigationService) {
15901
- this.domEvents = domEvents;
15902
- this.aggregateService = aggregateService;
15903
- this.localDataChangesService = localDataChangesService;
15904
- this.navigationService = navigationService;
15905
- this.changes = new EventEmitter();
15906
- this.mouseUpEvent = new EventEmitter();
15907
- this.currentSelection = [];
15908
- this.active = false;
15909
- this.dragging = false;
15910
- this.dragSelectDeselect = false;
15911
- this.lastSelectionItem = { itemKey: 0, columnKey: 0 };
15912
- this.lastSelectionItemRowIndex = 0;
15913
- this.lastSelectionItemColIndex = 0;
15914
- this.addSubscriptions();
15915
- }
15916
- get enableMarquee() {
15917
- const checkboxOnly = this.settings && typeof this.settings === 'object' && this.settings.checkboxOnly;
15918
- if (!this.settings || checkboxOnly) {
15919
- return false;
15920
- }
15921
- const selectableSettings = this.settings.selectable;
15922
- const dragAndMultiple = typeof (selectableSettings) === 'object' &&
15923
- isPresent(selectableSettings) &&
15924
- selectableSettings.mode === 'multiple' &&
15925
- selectableSettings.cell &&
15926
- selectableSettings.enabled !== false &&
15927
- selectableSettings.drag;
15928
- return this.active && dragAndMultiple;
15929
- }
15930
- init(settings) {
15931
- this.settings = settings;
15932
- this.currentSelection = [];
15933
- if (settings.selectable && settings.selectable.enabled !== false) {
15934
- const iterator = this.getIterator();
15935
- let item = iterator.next();
15936
- while (!item.done) {
15937
- if (item.value && item.value.type === "data") {
15938
- const rowArgs = {
15939
- dataItem: item.value.data,
15940
- index: item.value.index
15941
- };
15942
- settings.columns.forEach(col => {
15943
- const selectedCellArgs = settings.cellSelected(rowArgs, col, col.leafIndex);
15944
- if (selectedCellArgs.selected) {
15945
- this.currentSelection.push(selectedCellArgs.item);
15946
- }
15947
- });
15948
- }
15949
- item = iterator.next();
15950
- }
15951
- }
15952
- }
15953
- isCellSelected(item, col) {
15954
- if (this.settings && this.active) {
15955
- const selectedCellArgs = this.settings.cellSelected({ dataItem: item.data, index: item.index }, col, col.leafIndex);
15956
- return this.options.enabled && selectedCellArgs.selected;
15957
- }
15958
- return false;
15959
- }
15960
- handleClick(item, event) {
15961
- if (this.dragging) {
15962
- this.dragging = false;
15963
- return;
15964
- }
15965
- let ev;
15966
- const ctrlKey = event.ctrlKey || event.metaKey;
15967
- if (this.options.mode === "single" && ctrlKey && this.isCellSelected(item, item.column)) {
15968
- ev = this.toggle(item);
15969
- }
15970
- else if (this.options.mode === "multiple") {
15971
- if (ctrlKey && !event.shiftKey) {
15972
- ev = this.toggle(item);
15973
- }
15974
- else if (event.shiftKey) {
15975
- const startRowIndex = Math.min(this.lastSelectionItemRowIndex, item.index);
15976
- const startColIndex = Math.min(this.lastSelectionItemColIndex, item.column.leafIndex);
15977
- const endRowIndex = Math.max(this.lastSelectionItemRowIndex, item.index);
15978
- const endColIndex = Math.max(this.lastSelectionItemColIndex, item.column.leafIndex);
15979
- ev = this.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex);
15980
- }
15981
- }
15982
- if (!isPresent(ev)) {
15983
- ev = this.select(item);
15984
- this.currentSelection = [this.lastSelectionItem];
15985
- }
15986
- if (!ev.selectedCells.length && !ev.deselectedCells.length) {
15987
- return;
15988
- }
15989
- ev.ctrlKey = ctrlKey;
15990
- ev.shiftKey = event.shiftKey;
15991
- if (this.options.cellAggregates && !event.shiftKey) {
15992
- ev.cellAggregates = this.aggregateService.onSelectionChange(ev);
15993
- }
15994
- if (ev.shiftKey) {
15995
- ev.rangeStartCell = this.lastSelectionItem;
15996
- ev.rangeEndCell = {
15997
- ...this.settings.cellSelected({ dataItem: item.data, index: item.index }, item.column, item.column.leafIndex).item
15998
- };
15999
- }
16000
- this.changes.emit(ev);
16001
- }
16002
- toggle(item) {
16003
- const selectedCells = [];
16004
- const deselectedCells = [];
16005
- this.lastSelectionItem =
16006
- this.settings.cellSelected({ dataItem: item.data, index: item.index }, item.column, item.column.leafIndex).item;
16007
- this.lastSelectionItemRowIndex = item.index;
16008
- this.lastSelectionItemColIndex = item.column.leafIndex;
16009
- if (this.isCellSelected(item, item.column)) {
16010
- deselectedCells.push(this.lastSelectionItem);
16011
- }
16012
- else {
16013
- selectedCells.push(this.lastSelectionItem);
16014
- }
16015
- return {
16016
- deselectedCells,
16017
- selectedCells
16018
- };
16019
- }
16020
- select(item) {
16021
- const selectedCells = [];
16022
- const deselectedCells = [];
16023
- this.lastSelectionItem =
16024
- this.settings.cellSelected({ dataItem: item.data, index: item.index }, item.column, item.column.leafIndex).item;
16025
- this.lastSelectionItemRowIndex = item.index;
16026
- this.lastSelectionItemColIndex = item.column.leafIndex;
16027
- if (!this.isCellSelected(item, item.column)) {
16028
- selectedCells.push(this.lastSelectionItem);
16029
- }
16030
- this.currentSelection.forEach((selectedItem) => {
16031
- if (selectedItem.itemKey !== this.lastSelectionItem.itemKey || selectedItem.columnKey !== this.lastSelectionItem.columnKey) {
16032
- deselectedCells.push(selectedItem);
16033
- }
16034
- });
16035
- return {
16036
- deselectedCells,
16037
- selectedCells
16038
- };
16039
- }
16040
- //Used to manually deselect removed items
16041
- deselect(removedItem) {
16042
- const iterator = this.getIterator();
16043
- let item = iterator.next();
16044
- let rowArgs;
16045
- while (!item.done) {
16046
- if (item.value && item.value.type === "data" && item.value.data === removedItem) {
16047
- rowArgs = {
16048
- dataItem: item.value.data,
16049
- index: item.value.index
16050
- };
16051
- break;
16052
- }
16053
- item = iterator.next();
16054
- }
16055
- if (rowArgs) {
16056
- const cellsToRemove = this.currentSelection.filter(selectedItem => {
16057
- const contender = this.settings.cellSelected(rowArgs, null, null).item;
16058
- return selectedItem.itemKey === contender.itemKey;
16059
- });
16060
- if (cellsToRemove.length) {
16061
- const ev = {
16062
- ctrlKey: false,
16063
- deselectedCells: cellsToRemove,
16064
- selectedCells: []
16065
- };
16066
- this.changes.emit(ev);
16067
- }
16068
- }
16069
- }
16070
- selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex) {
16071
- const selectedCells = [];
16072
- const deselectedCells = [];
16073
- const selectionStartRow = Math.min(startRowIndex, endRowIndex);
16074
- const selectionStartCol = Math.min(startColIndex, endColIndex);
16075
- const selectionEndRow = Math.max(startRowIndex, endRowIndex);
16076
- const selectionEndCol = Math.max(startColIndex, endColIndex);
16077
- const iterator = this.getIterator();
16078
- let next = iterator.next();
16079
- while (!next.done) {
16080
- if (next.value && next.value.type === "data") {
16081
- const idx = next.value.index;
16082
- const data = next.value.data;
16083
- const rowArgs = {
16084
- dataItem: data,
16085
- index: idx
16086
- };
16087
- this.settings.columns.forEach(col => {
16088
- const { item } = this.settings.cellSelected(rowArgs, col, col.leafIndex);
16089
- const selected = this.isCellSelected(next.value, col);
16090
- const isInRowRange = selectionStartRow <= idx && idx <= selectionEndRow;
16091
- const isInColRange = selectionStartCol <= col.leafIndex && col.leafIndex <= selectionEndCol;
16092
- const isInSelectionRect = isInRowRange && isInColRange;
16093
- if (!isInSelectionRect && selected) {
16094
- deselectedCells.push(item);
16095
- }
16096
- if (isInSelectionRect && !selected) {
16097
- selectedCells.push(item);
16098
- }
16099
- });
16100
- }
16101
- next = iterator.next();
16102
- }
16103
- let cellAggregates;
16104
- if (this.options.cellAggregates) {
16105
- cellAggregates = this.aggregateService.onSelectionChange({ selectedCells, deselectedCells });
16106
- }
16107
- return {
16108
- deselectedCells,
16109
- selectedCells,
16110
- cellAggregates
16111
- };
16187
+ /**
16188
+ * Represents the row-selection checkbox of the Grid. The directive expects the
16189
+ * index of the current row as an input parameter. Inside the [`CellTemplateDirective`](slug:api_grid_celltemplatedirective), apply the
16190
+ * `kendoGridSelectionCheckbox` to an `<input type="checkbox"/>` element. When the user clicks the checkbox that is associated
16191
+ * with the directive, a [selectionChange](slug:api_grid_gridcomponent#toc-selectionChange)
16192
+ * event is triggered.
16193
+ *
16194
+ * @example
16195
+ * ```html
16196
+ * <kendo-grid ... >
16197
+ * <kendo-grid-column>
16198
+ * <ng-template kendoGridCellTemplate let-rowIndex="rowIndex">
16199
+ * <input ... [kendoGridSelectionCheckbox]="rowIndex"/>
16200
+ * </ng-template>
16201
+ * </kendo-grid-column>
16202
+ * </kendo-grid>
16203
+ * ```
16204
+ */
16205
+ class SelectionCheckboxDirective {
16206
+ constructor(selectionService, cellSelectionService, aggregateService, el, renderer, ngZone) {
16207
+ this.selectionService = selectionService;
16208
+ this.cellSelectionService = cellSelectionService;
16209
+ this.aggregateService = aggregateService;
16210
+ this.el = el;
16211
+ this.renderer = renderer;
16212
+ this.ngZone = ngZone;
16213
+ this.type = 'checkbox';
16214
+ this.ngZone.runOutsideAngular(() => {
16215
+ this.destroyClick = this.renderer.listen(this.el.nativeElement, 'click', this.onClick.bind(this));
16216
+ this.destroyKeyDown = this.renderer.listen(this.el.nativeElement, 'keydown', this.onKeyDown.bind(this));
16217
+ });
16112
16218
  }
16113
- get options() {
16114
- const defaultOptions = {
16115
- cellAggregates: false,
16116
- checkboxOnly: false,
16117
- enabled: true,
16118
- mode: "multiple"
16119
- };
16120
- if (!isPresent(this.settings)) {
16121
- return defaultOptions;
16122
- }
16123
- if (typeof this.settings.selectable === 'boolean') {
16124
- return {
16125
- cellAggregates: false,
16126
- checkboxOnly: false,
16127
- enabled: this.settings.selectable,
16128
- mode: "multiple"
16129
- };
16130
- }
16131
- else {
16132
- return Object.assign(defaultOptions, this.settings.selectable);
16133
- }
16219
+ ngAfterContentChecked() {
16220
+ this.setCheckedState();
16134
16221
  }
16135
16222
  ngOnDestroy() {
16136
- this.removeSubscriptions();
16223
+ if (this.destroyClick) {
16224
+ this.destroyClick();
16225
+ }
16226
+ if (this.destroyKeyDown) {
16227
+ this.destroyKeyDown();
16228
+ }
16137
16229
  }
16138
- addSubscriptions() {
16139
- if (!this.cellClickSubscription) {
16140
- this.cellClickSubscription = this.domEvents.cellClick.subscribe((args) => {
16141
- if (this.options.enabled && !this.options.checkboxOnly && args.type !== 'contextmenu') {
16142
- if (this.active) {
16143
- this.handleClick({ index: args.rowIndex, data: args.dataItem, column: args.column }, args.originalEvent);
16144
- }
16145
- }
16146
- });
16230
+ onClick(event) {
16231
+ const nonSelectableRow = this.selectionService.nonSelectableRows.has(this.itemIndex) || this.cellSelectionService.nonSelectableRows.has(this.itemIndex);
16232
+ if (nonSelectableRow || this.cellSelectionService.options.cell) {
16233
+ event.preventDefault();
16234
+ return;
16147
16235
  }
16148
- if (!this.mousedownSubscription) {
16149
- this.mousedownSubscription = this.domEvents.cellMousedown.subscribe((args) => {
16150
- this.mouseDownEventArgs = args;
16151
- if (this.options.enabled && (!this.options.mode || this.options.mode === "multiple") &&
16152
- !this.options.checkboxOnly && args.originalEvent.shiftKey) {
16153
- if (this.active) {
16154
- args.originalEvent.preventDefault();
16155
- this.navigationService.focusCellByElement(args.originalEvent.target);
16156
- }
16236
+ if (this.selectionService.options.enabled) {
16237
+ this.ngZone.run(() => {
16238
+ let ev;
16239
+ const ctrlKey = event.ctrlKey || event.metaKey;
16240
+ if (event.shiftKey) {
16241
+ const item = { index: this.itemIndex };
16242
+ ev = this.selectionService.addAllTo(item, ctrlKey);
16157
16243
  }
16158
- });
16159
- }
16160
- if (this.localDataChangesService && !this.dataChangedSubscription) {
16161
- this.dataChangedSubscription = this.localDataChangesService.changes.subscribe((args) => {
16162
- if (this.active) {
16163
- if (isPresent(args.action) && args.action === 'remove') {
16164
- this.deselect(args.item);
16165
- }
16244
+ else {
16245
+ ev = this.selectionService.toggleByIndex(this.itemIndex);
16246
+ }
16247
+ ev.ctrlKey = event.ctrlKey;
16248
+ ev.shiftKey = event.shiftKey;
16249
+ if (this.selectionService.options.cellAggregates) {
16250
+ ev.cellAggregates = this.aggregateService.onSelectionChange(ev);
16166
16251
  }
16252
+ this.selectionService.changes.emit(ev);
16167
16253
  });
16168
16254
  }
16169
16255
  }
16170
- getIterator() {
16171
- const accessor = this.settings.view.accessor();
16172
- if (!accessor) {
16173
- return;
16256
+ onKeyDown(e) {
16257
+ if (e.keyCode === Keys.Enter) {
16258
+ this.onClick(e);
16174
16259
  }
16175
- return accessor[iterator]();
16176
16260
  }
16177
- removeSubscriptions() {
16178
- if (this.cellClickSubscription) {
16179
- this.cellClickSubscription.unsubscribe();
16180
- this.cellClickSubscription = null;
16181
- }
16182
- if (this.mousedownSubscription) {
16183
- this.mousedownSubscription.unsubscribe();
16184
- this.mousedownSubscription = null;
16185
- }
16186
- if (this.dataChangedSubscription) {
16187
- this.dataChangedSubscription.unsubscribe();
16188
- this.dataChangedSubscription = null;
16261
+ /*
16262
+ * @hidden
16263
+ */
16264
+ setCheckedState() {
16265
+ const isSelected = this.selectionService.nonSelectableRows.has(this.itemIndex) ? false : this.selectionService.isSelected(this.itemIndex);
16266
+ this.renderer.setProperty(this.el.nativeElement, 'checked', isSelected);
16267
+ }
16268
+ }
16269
+ SelectionCheckboxDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SelectionCheckboxDirective, deps: [{ token: SelectionService }, { token: CellSelectionService }, { token: CellSelectionAggregateService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
16270
+ SelectionCheckboxDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: SelectionCheckboxDirective, isStandalone: true, selector: "[kendoGridSelectionCheckbox]", inputs: { itemIndex: ["kendoGridSelectionCheckbox", "itemIndex"] }, host: { properties: { "attr.type": "this.type" } }, ngImport: i0 });
16271
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SelectionCheckboxDirective, decorators: [{
16272
+ type: Directive,
16273
+ args: [{
16274
+ selector: '[kendoGridSelectionCheckbox]',
16275
+ standalone: true
16276
+ }]
16277
+ }], ctorParameters: function () { return [{ type: SelectionService }, { type: CellSelectionService }, { type: CellSelectionAggregateService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, propDecorators: { itemIndex: [{
16278
+ type: Input,
16279
+ args: ['kendoGridSelectionCheckbox']
16280
+ }], type: [{
16281
+ type: HostBinding,
16282
+ args: ['attr.type']
16283
+ }] } });
16284
+
16285
+ /**
16286
+ * @hidden
16287
+ */
16288
+ class ChangeNotificationService {
16289
+ constructor(ngZone) {
16290
+ this.ngZone = ngZone;
16291
+ this.changes = new EventEmitter();
16292
+ }
16293
+ notify() {
16294
+ if (!this.subscription || this.subscription.closed) {
16295
+ this.subscription = this.ngZone.onStable
16296
+ .asObservable().pipe(take(1))
16297
+ .subscribe(() => this.changes.emit());
16189
16298
  }
16190
16299
  }
16191
16300
  }
16192
- CellSelectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CellSelectionService, deps: [{ token: DomEventsService }, { token: CellSelectionAggregateService }, { token: LocalDataChangesService }, { token: NavigationService }], target: i0.ɵɵFactoryTarget.Injectable });
16193
- CellSelectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CellSelectionService });
16194
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CellSelectionService, decorators: [{
16301
+ ChangeNotificationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ChangeNotificationService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
16302
+ ChangeNotificationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ChangeNotificationService });
16303
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ChangeNotificationService, decorators: [{
16195
16304
  type: Injectable
16196
- }], ctorParameters: function () { return [{ type: DomEventsService }, { type: CellSelectionAggregateService }, { type: LocalDataChangesService }, { type: NavigationService }]; } });
16305
+ }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
16306
+
16307
+ /**
16308
+ * Represents the no-records template of the Grid. Provides an option to customize the
16309
+ * appearance of the item that is displayed when no data is present.
16310
+ * To define the no-records template, nest an `<ng-template>` tag with the `kendoGridNoRecordsTemplate`
16311
+ * directive inside `<kendo-grid>` [see example](slug:norecordtemplate_grid).
16312
+ *
16313
+ * @example
16314
+ * ```html
16315
+ * <kendo-grid [data]="data">
16316
+ * <ng-template kendoGridNoRecordsTemplate>
16317
+ * There are not products. <a href="#" (click)="refresh()">Click here to refresh</a>.
16318
+ * </ng-template>
16319
+ * <kendo-grid-column field="ProductID"></kendo-grid-column>
16320
+ * <kendo-grid-column field="ProductName"></kendo-grid-column>
16321
+ * </kendo-grid>
16322
+ * ```
16323
+ */
16324
+ class NoRecordsTemplateDirective {
16325
+ constructor(templateRef) {
16326
+ this.templateRef = templateRef;
16327
+ }
16328
+ }
16329
+ NoRecordsTemplateDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NoRecordsTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
16330
+ NoRecordsTemplateDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: NoRecordsTemplateDirective, isStandalone: true, selector: "[kendoGridNoRecordsTemplate]", ngImport: i0 });
16331
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NoRecordsTemplateDirective, decorators: [{
16332
+ type: Directive,
16333
+ args: [{
16334
+ selector: '[kendoGridNoRecordsTemplate]',
16335
+ standalone: true
16336
+ }]
16337
+ }], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
16338
+ type: Optional
16339
+ }] }]; } });
16340
+
16341
+ /**
16342
+ * @hidden
16343
+ */
16344
+ function defaultTrackBy(index, item) {
16345
+ if (item.type === 'data' && item.isEditing) {
16346
+ return item.data;
16347
+ }
16348
+ return index;
16349
+ }
16350
+
16351
+ /**
16352
+ * @hidden
16353
+ */
16354
+ const NON_DATA_CELL_CLASSES = 'k-hierarchy-cell k-detail-cell k-group-cell';
16355
+ /**
16356
+ * @hidden
16357
+ */
16358
+ const NON_DATA_ROW_CLASSES = 'k-grouping-row k-group-footer k-detail-row k-grid-norecords';
16359
+ /**
16360
+ * @hidden
16361
+ */
16362
+ const IGNORE_TARGET_CLASSSES = 'k-icon k-svg-icon';
16363
+ /**
16364
+ * @hidden
16365
+ */
16366
+ const IGNORE_CONTAINER_CLASSES = 'k-grid k-grid-ignore-click';
16197
16367
 
16198
16368
  /**
16199
16369
  * @hidden
@@ -16279,6 +16449,9 @@ class CellComponent {
16279
16449
  get isRowReorderColumn() {
16280
16450
  return isRowReorderColumn(this.column) && !this.column.templateRef;
16281
16451
  }
16452
+ get isRowSelectable() {
16453
+ return this.column.rowSelectable(this._rowIndex);
16454
+ }
16282
16455
  get isColumnEditable() {
16283
16456
  if (!this.column || this.isCommand(this.column)) {
16284
16457
  return false;
@@ -16340,13 +16513,25 @@ CellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version:
16340
16513
  </ng-container>
16341
16514
  <ng-container *ngIf="isBoundColumn">{{ dataItem | valueOf: column.field: column.format}}</ng-container>
16342
16515
  <ng-container *ngIf="isCheckboxColumn && !isNew">
16343
- <span class="k-checkbox-wrap">
16344
- <input
16345
- class="k-checkbox k-checkbox-md k-rounded-md"
16346
- [kendoGridSelectionCheckbox]="rowIndex"
16347
- [attr.id]="selectionCheckboxId"
16348
- [attr.aria-label]="selectionCheckboxLabel" />
16349
- </span>
16516
+ <ng-container *ngIf="isRowSelectable; else nonSelectableRow">
16517
+ <span class="k-checkbox-wrap">
16518
+ <input
16519
+ class="k-checkbox k-checkbox-md k-rounded-md"
16520
+ [kendoGridSelectionCheckbox]="rowIndex"
16521
+ [attr.id]="selectionCheckboxId"
16522
+ [attr.aria-label]="selectionCheckboxLabel" />
16523
+ </span>
16524
+ </ng-container>
16525
+ <ng-template #nonSelectableRow>
16526
+ <span class="k-checkbox-wrap" *ngIf="column.showDisabledCheckbox">
16527
+ <input
16528
+ class="k-checkbox k-checkbox-md k-rounded-md k-disabled"
16529
+ [kendoGridSelectionCheckbox]="rowIndex"
16530
+ [attr.id]="selectionCheckboxId"
16531
+ [attr.aria-label]="selectionCheckboxLabel"
16532
+ [disabled]="true" />
16533
+ </span>
16534
+ </ng-template>
16350
16535
  </ng-container>
16351
16536
  <ng-container *ngIf="isRowReorderColumn && !isNew">
16352
16537
  <kendo-icon-wrapper
@@ -16425,13 +16610,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
16425
16610
  </ng-container>
16426
16611
  <ng-container *ngIf="isBoundColumn">{{ dataItem | valueOf: column.field: column.format}}</ng-container>
16427
16612
  <ng-container *ngIf="isCheckboxColumn && !isNew">
16428
- <span class="k-checkbox-wrap">
16429
- <input
16430
- class="k-checkbox k-checkbox-md k-rounded-md"
16431
- [kendoGridSelectionCheckbox]="rowIndex"
16432
- [attr.id]="selectionCheckboxId"
16433
- [attr.aria-label]="selectionCheckboxLabel" />
16434
- </span>
16613
+ <ng-container *ngIf="isRowSelectable; else nonSelectableRow">
16614
+ <span class="k-checkbox-wrap">
16615
+ <input
16616
+ class="k-checkbox k-checkbox-md k-rounded-md"
16617
+ [kendoGridSelectionCheckbox]="rowIndex"
16618
+ [attr.id]="selectionCheckboxId"
16619
+ [attr.aria-label]="selectionCheckboxLabel" />
16620
+ </span>
16621
+ </ng-container>
16622
+ <ng-template #nonSelectableRow>
16623
+ <span class="k-checkbox-wrap" *ngIf="column.showDisabledCheckbox">
16624
+ <input
16625
+ class="k-checkbox k-checkbox-md k-rounded-md k-disabled"
16626
+ [kendoGridSelectionCheckbox]="rowIndex"
16627
+ [attr.id]="selectionCheckboxId"
16628
+ [attr.aria-label]="selectionCheckboxLabel"
16629
+ [disabled]="true" />
16630
+ </span>
16631
+ </ng-template>
16435
16632
  </ng-container>
16436
16633
  <ng-container *ngIf="isRowReorderColumn && !isNew">
16437
16634
  <kendo-icon-wrapper
@@ -16642,12 +16839,17 @@ class TableBodyComponent {
16642
16839
  isOdd(item) {
16643
16840
  return item.index % 2 !== 0;
16644
16841
  }
16645
- isSelectable() {
16646
- return this.selectable && this.selectable.enabled !== false;
16842
+ isSelectable(args) {
16843
+ const rowSelectable = this.isRowSelectable(args);
16844
+ const selectionEnabled = this.selectable && this.selectable.enabled !== false;
16845
+ return selectionEnabled && rowSelectable;
16647
16846
  }
16648
16847
  isRowSelected(item) {
16649
16848
  return this.selectionService.isSelected(item.index);
16650
16849
  }
16850
+ isRowSelectable(args) {
16851
+ return this.selectionService.settings?.isRowSelectable(args) || this.cellSelectionService.settings?.isRowSelectable(args);
16852
+ }
16651
16853
  trackByWrapper(index, item) {
16652
16854
  if (item.type === 'data') {
16653
16855
  item.isEditing = this.editService.hasEdited(item.index);
@@ -16805,6 +17007,10 @@ class TableBodyComponent {
16805
17007
  if (!focusable && !matchesNodeName('label')(target) && !hasClasses(target, IGNORE_TARGET_CLASSSES) &&
16806
17008
  !closestInScope(target, matchesClasses(IGNORE_CONTAINER_CLASSES), cell)) {
16807
17009
  const args = this.cellClickArgs(cell, row, eventArg);
17010
+ const selectionEnabled = this.selectable && this.selectable.enabled !== false;
17011
+ if (selectionEnabled && !this.isRowSelectable({ index: args.rowIndex, dataItem: args.dataItem })) {
17012
+ return;
17013
+ }
16808
17014
  if (eventArg.type === 'mousedown' || eventArg.type === 'touchstart') {
16809
17015
  this.domEvents.cellMousedown.emit(args);
16810
17016
  }
@@ -16977,9 +17183,9 @@ TableBodyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
16977
17183
  [ngClass]="rowClass({ dataItem: item.data, index: $any(item).index })"
16978
17184
  [class.k-master-row]="true"
16979
17185
  [class.k-grid-edit-row]="isEditingRow($any(item).index)"
16980
- [attr.aria-selected]="lockedColumnsCount < 1 ? isSelectable() && isRowSelected(item) : undefined"
17186
+ [attr.aria-selected]="lockedColumnsCount < 1 ? isSelectable({ dataItem: item.data, index: $any(item).index }) && isRowSelected(item) : undefined"
16981
17187
  [attr.data-kendo-grid-item-index]="$any(item).index"
16982
- [class.k-selected]="isSelectable() && isRowSelected(item)">
17188
+ [class.k-selected]="isSelectable({ dataItem: item.data, index: $any(item).index }) && isRowSelected(item)">
16983
17189
  <ng-container *ngIf="!skipGroupDecoration">
16984
17190
  <td class="k-group-cell k-table-td" *ngFor="let g of groups" role="presentation"></td>
16985
17191
  </ng-container>
@@ -17022,10 +17228,10 @@ TableBodyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
17022
17228
  [colSpan]="column.colspan"
17023
17229
  [attr.role]="column.tableCellsRole"
17024
17230
  class="k-table-td"
17025
- [attr.aria-selected]="lockedColumnsCount < 1 && isSelectable() ? isAriaSelected(item, column) : undefined"
17231
+ [attr.aria-selected]="lockedColumnsCount < 1 && isSelectable({ dataItem: item.data, index: $any(item).index }) ? isAriaSelected(item, column) : undefined"
17026
17232
  [class.k-grid-content-sticky]="column.sticky"
17027
- [class.k-touch-action-none]="isSelectable() && $any(selectable).drag"
17028
- [class.k-touch-action-auto]="!(isSelectable() && $any(selectable).drag)"
17233
+ [class.k-touch-action-none]="isSelectable({ dataItem: item.data, index: $any(item).index }) && $any(selectable).drag"
17234
+ [class.k-touch-action-auto]="!(isSelectable({ dataItem: item.data, index: $any(item).index }) && $any(selectable).drag)"
17029
17235
  [ngClass]="column.cssClass"
17030
17236
  [class.k-grid-edit-cell]="isEditingCell($any(item).index, column)"
17031
17237
  [ngStyle]="column.sticky ? addStickyColumnStyles(column) : column.style"
@@ -17206,9 +17412,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
17206
17412
  [ngClass]="rowClass({ dataItem: item.data, index: $any(item).index })"
17207
17413
  [class.k-master-row]="true"
17208
17414
  [class.k-grid-edit-row]="isEditingRow($any(item).index)"
17209
- [attr.aria-selected]="lockedColumnsCount < 1 ? isSelectable() && isRowSelected(item) : undefined"
17415
+ [attr.aria-selected]="lockedColumnsCount < 1 ? isSelectable({ dataItem: item.data, index: $any(item).index }) && isRowSelected(item) : undefined"
17210
17416
  [attr.data-kendo-grid-item-index]="$any(item).index"
17211
- [class.k-selected]="isSelectable() && isRowSelected(item)">
17417
+ [class.k-selected]="isSelectable({ dataItem: item.data, index: $any(item).index }) && isRowSelected(item)">
17212
17418
  <ng-container *ngIf="!skipGroupDecoration">
17213
17419
  <td class="k-group-cell k-table-td" *ngFor="let g of groups" role="presentation"></td>
17214
17420
  </ng-container>
@@ -17251,10 +17457,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
17251
17457
  [colSpan]="column.colspan"
17252
17458
  [attr.role]="column.tableCellsRole"
17253
17459
  class="k-table-td"
17254
- [attr.aria-selected]="lockedColumnsCount < 1 && isSelectable() ? isAriaSelected(item, column) : undefined"
17460
+ [attr.aria-selected]="lockedColumnsCount < 1 && isSelectable({ dataItem: item.data, index: $any(item).index }) ? isAriaSelected(item, column) : undefined"
17255
17461
  [class.k-grid-content-sticky]="column.sticky"
17256
- [class.k-touch-action-none]="isSelectable() && $any(selectable).drag"
17257
- [class.k-touch-action-auto]="!(isSelectable() && $any(selectable).drag)"
17462
+ [class.k-touch-action-none]="isSelectable({ dataItem: item.data, index: $any(item).index }) && $any(selectable).drag"
17463
+ [class.k-touch-action-auto]="!(isSelectable({ dataItem: item.data, index: $any(item).index }) && $any(selectable).drag)"
17258
17464
  [ngClass]="column.cssClass"
17259
17465
  [class.k-grid-edit-cell]="isEditingCell($any(item).index, column)"
17260
17466
  [ngStyle]="column.sticky ? addStickyColumnStyles(column) : column.style"
@@ -19409,8 +19615,8 @@ const packageMetadata = {
19409
19615
  name: '@progress/kendo-angular-grid',
19410
19616
  productName: 'Kendo UI for Angular',
19411
19617
  productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
19412
- publishDate: 1727275920,
19413
- version: '16.10.1-develop.3',
19618
+ publishDate: 1727423166,
19619
+ version: '16.11.0-develop.2',
19414
19620
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
19415
19621
  };
19416
19622
 
@@ -19902,6 +20108,9 @@ class Selection {
19902
20108
  if (!isPresent(this.ctx.grid.rowSelected)) {
19903
20109
  this.ctx.grid.rowSelected = (row) => this.rowSelectionState.has(this.getItemKey(row));
19904
20110
  }
20111
+ if (!isPresent(this.ctx.grid.isRowSelectable)) {
20112
+ this.ctx.grid.isRowSelectable = (_row) => Boolean(this.ctx.grid.selectable);
20113
+ }
19905
20114
  if (!isPresent(this.ctx.grid.cellSelected)) {
19906
20115
  this.ctx.grid.cellSelected = (row, column, colIndex) => {
19907
20116
  const contender = this.getSelectionItem(row, column, colIndex);
@@ -22766,11 +22975,16 @@ class GridComponent {
22766
22975
  this._data = [];
22767
22976
  this.cachedWindowWidth = 0;
22768
22977
  this._rowSelected = null;
22978
+ this._isRowSelectable = null;
22769
22979
  this._cellSelected = null;
22770
22980
  this._rowReorderable = false;
22771
22981
  this._navigable = [];
22772
22982
  this._size = 'medium';
22773
22983
  this._loading = false;
22984
+ /**
22985
+ * @hidden
22986
+ */
22987
+ this.blockArrowSelection = false;
22774
22988
  this.rtl = false;
22775
22989
  this._rowClass = () => null;
22776
22990
  const isValid = validatePackage(packageMetadata);
@@ -22817,6 +23031,9 @@ class GridComponent {
22817
23031
  */
22818
23032
  set data(value) {
22819
23033
  this._data = value;
23034
+ if (this.selectable && this.selectableSettings?.enabled && this.isVirtual) {
23035
+ this.blockArrowSelection = false;
23036
+ }
22820
23037
  if (this.notifyTimeout) {
22821
23038
  clearTimeout(this.notifyTimeout);
22822
23039
  this.notifyTimeout = null;
@@ -23042,6 +23259,19 @@ class GridComponent {
23042
23259
  get rowSelected() {
23043
23260
  return this._rowSelected;
23044
23261
  }
23262
+ /**
23263
+ * Defines a Boolean function that is executed for each data row in the component.
23264
+ * Determines whether the row will be selectable.
23265
+ */
23266
+ set isRowSelectable(fn) {
23267
+ if (isDevMode() && typeof fn !== 'function') {
23268
+ throw new Error(GridConfigurationErrorMessages.functionType('isRowSelectable', fn));
23269
+ }
23270
+ this._isRowSelectable = fn;
23271
+ }
23272
+ get isRowSelectable() {
23273
+ return this._isRowSelectable;
23274
+ }
23045
23275
  /**
23046
23276
  * Defines a function that determines the selected state of a data cell.
23047
23277
  * Returns an object with `selected` and `item` properties.
@@ -23844,6 +24074,12 @@ class GridComponent {
23844
24074
  get flatData() {
23845
24075
  return isArray(this.data) ? this.data : this.data.data;
23846
24076
  }
24077
+ /**
24078
+ * @hidden
24079
+ */
24080
+ updateNavigationMetadata() {
24081
+ this.navigationService.metadata = this.navigationMetadata();
24082
+ }
23847
24083
  /**
23848
24084
  * @hidden
23849
24085
  */
@@ -23959,6 +24195,7 @@ class GridComponent {
23959
24195
  activeService.init({
23960
24196
  cellSelected: cellSelectionMode ? this.cellSelected : undefined,
23961
24197
  rowSelected: cellSelectionMode ? undefined : this.rowSelected,
24198
+ isRowSelectable: this.isRowSelectable,
23962
24199
  selectable: this.selectable,
23963
24200
  view: this.view,
23964
24201
  columns: cellSelectionMode ? this.columnList.toArray() : undefined
@@ -24075,6 +24312,9 @@ class GridComponent {
24075
24312
  .subscribe(x => {
24076
24313
  this.closeCell();
24077
24314
  this.cancelCell();
24315
+ if (this.selectable && this.selectableSettings?.enabled && this.isVirtual) {
24316
+ this.blockArrowSelection = true;
24317
+ }
24078
24318
  this.dataStateChange.emit(x);
24079
24319
  });
24080
24320
  }
@@ -24260,9 +24500,6 @@ class GridComponent {
24260
24500
  const headerRows = this.totalColumnLevels + 1 + filterRowOffset + addRowOffset;
24261
24501
  return new NavigationMetadata(dataRows, headerRows, isVirtual, this.hasPager, isPresent(this.detailTemplate), this.wrapper, this.virtualColumns, this.columnsContainer);
24262
24502
  }
24263
- updateNavigationMetadata() {
24264
- this.navigationService.metadata = this.navigationMetadata();
24265
- }
24266
24503
  applyAutoSize() {
24267
24504
  const cols = this.columns.filter((c) => this.autoSize ? c.autoSize !== false : c.autoSize);
24268
24505
  if (cols.length > 0) {
@@ -24366,7 +24603,7 @@ class GridComponent {
24366
24603
  }
24367
24604
  }
24368
24605
  GridComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: GridComponent, deps: [{ token: BrowserSupportService }, { token: SelectionService }, { token: CellSelectionService }, { token: i0.ElementRef }, { token: GroupInfoService }, { token: GroupsService }, { token: ChangeNotificationService }, { token: DetailsService }, { token: EditService }, { token: FilterService }, { token: PDFService }, { token: ResponsiveService }, { token: i0.Renderer2 }, { token: ExcelService }, { token: i0.NgZone }, { token: ScrollSyncService }, { token: DomEventsService }, { token: ColumnResizingService }, { token: i0.ChangeDetectorRef }, { token: ColumnReorderService }, { token: ColumnInfoService }, { token: NavigationService }, { token: SortService }, { token: ScrollRequestService }, { token: i1$2.LocalizationService }, { token: ContextService }, { token: SizingOptionsService }, { token: RowReorderService }], target: i0.ɵɵFactoryTarget.Component });
24369
- GridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: GridComponent, isStandalone: true, selector: "kendo-grid", inputs: { data: "data", pageSize: "pageSize", height: "height", rowHeight: "rowHeight", detailRowHeight: "detailRowHeight", skip: "skip", scrollable: "scrollable", selectable: "selectable", sort: "sort", size: "size", trackBy: "trackBy", filter: "filter", group: "group", virtualColumns: "virtualColumns", filterable: "filterable", sortable: "sortable", pageable: "pageable", groupable: "groupable", rowReorderable: "rowReorderable", navigable: "navigable", navigatable: "navigatable", autoSize: "autoSize", rowClass: "rowClass", rowSticky: "rowSticky", rowSelected: "rowSelected", cellSelected: "cellSelected", resizable: "resizable", reorderable: "reorderable", loading: "loading", columnMenu: "columnMenu", hideHeader: "hideHeader", isDetailExpanded: "isDetailExpanded", isGroupExpanded: "isGroupExpanded" }, outputs: { filterChange: "filterChange", pageChange: "pageChange", groupChange: "groupChange", sortChange: "sortChange", selectionChange: "selectionChange", rowReorder: "rowReorder", dataStateChange: "dataStateChange", groupExpand: "groupExpand", groupCollapse: "groupCollapse", detailExpand: "detailExpand", detailCollapse: "detailCollapse", edit: "edit", cancel: "cancel", save: "save", remove: "remove", add: "add", cellClose: "cellClose", cellClick: "cellClick", pdfExport: "pdfExport", excelExport: "excelExport", columnResize: "columnResize", columnReorder: "columnReorder", columnVisibilityChange: "columnVisibilityChange", columnLockedChange: "columnLockedChange", columnStickyChange: "columnStickyChange", scrollBottom: "scrollBottom", contentScroll: "contentScroll" }, host: { properties: { "attr.dir": "this.dir", "class.k-grid": "this.hostClass", "class.k-grid-sm": "this.sizeSmallClass", "class.k-grid-md": "this.sizeMediumClass", "class.k-grid-lockedcolumns": "this.lockedClasses", "class.k-grid-virtual": "this.virtualClasses", "class.k-grid-no-scrollbar": "this.noScrollbarClass" } }, providers: [
24606
+ GridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: GridComponent, isStandalone: true, selector: "kendo-grid", inputs: { data: "data", pageSize: "pageSize", height: "height", rowHeight: "rowHeight", detailRowHeight: "detailRowHeight", skip: "skip", scrollable: "scrollable", selectable: "selectable", sort: "sort", size: "size", trackBy: "trackBy", filter: "filter", group: "group", virtualColumns: "virtualColumns", filterable: "filterable", sortable: "sortable", pageable: "pageable", groupable: "groupable", rowReorderable: "rowReorderable", navigable: "navigable", navigatable: "navigatable", autoSize: "autoSize", rowClass: "rowClass", rowSticky: "rowSticky", rowSelected: "rowSelected", isRowSelectable: "isRowSelectable", cellSelected: "cellSelected", resizable: "resizable", reorderable: "reorderable", loading: "loading", columnMenu: "columnMenu", hideHeader: "hideHeader", isDetailExpanded: "isDetailExpanded", isGroupExpanded: "isGroupExpanded" }, outputs: { filterChange: "filterChange", pageChange: "pageChange", groupChange: "groupChange", sortChange: "sortChange", selectionChange: "selectionChange", rowReorder: "rowReorder", dataStateChange: "dataStateChange", groupExpand: "groupExpand", groupCollapse: "groupCollapse", detailExpand: "detailExpand", detailCollapse: "detailCollapse", edit: "edit", cancel: "cancel", save: "save", remove: "remove", add: "add", cellClose: "cellClose", cellClick: "cellClick", pdfExport: "pdfExport", excelExport: "excelExport", columnResize: "columnResize", columnReorder: "columnReorder", columnVisibilityChange: "columnVisibilityChange", columnLockedChange: "columnLockedChange", columnStickyChange: "columnStickyChange", scrollBottom: "scrollBottom", contentScroll: "contentScroll" }, host: { properties: { "attr.dir": "this.dir", "class.k-grid": "this.hostClass", "class.k-grid-sm": "this.sizeSmallClass", "class.k-grid-md": "this.sizeMediumClass", "class.k-grid-lockedcolumns": "this.lockedClasses", "class.k-grid-virtual": "this.virtualClasses", "class.k-grid-no-scrollbar": "this.noScrollbarClass" } }, providers: [
24370
24607
  BrowserSupportService,
24371
24608
  LocalizationService,
24372
24609
  ColumnInfoService,
@@ -25692,6 +25929,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
25692
25929
  type: Input
25693
25930
  }], rowSelected: [{
25694
25931
  type: Input
25932
+ }], isRowSelectable: [{
25933
+ type: Input
25695
25934
  }], cellSelected: [{
25696
25935
  type: Input
25697
25936
  }], resizable: [{
@@ -26020,6 +26259,7 @@ class DataBindingDirective {
26020
26259
  }
26021
26260
  updateGridData() {
26022
26261
  this.grid.data = this.process(this.state);
26262
+ this.grid.updateNavigationMetadata();
26023
26263
  this.dataChanged = false;
26024
26264
  }
26025
26265
  }