@progress/kendo-angular-dropdowns 7.1.0-dev.202208301423 → 7.2.0-dev.202209131018

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.
@@ -69,6 +69,11 @@ export declare class DataService {
69
69
  * Used to get the group at the provided index.
70
70
  */
71
71
  groupAt(index: number): any;
72
+ /**
73
+ * @hidden
74
+ * Used to get all group items indices.
75
+ */
76
+ groupItemsIndices(): number[];
72
77
  /**
73
78
  * @hidden
74
79
  * Used to get the field by which the data is grouped.
@@ -21,5 +21,10 @@ export declare enum NavigationAction {
21
21
  Left = 12,
22
22
  Right = 13,
23
23
  PageDown = 14,
24
- PageUp = 15
24
+ PageUp = 15,
25
+ SelectPrevious = 16,
26
+ SelectNext = 17,
27
+ SelectAll = 18,
28
+ SelectAllToBeginning = 19,
29
+ SelectAllToEnd = 20
25
30
  }
@@ -39,6 +39,11 @@ export declare class NavigationService {
39
39
  end: EventEmitter<NavigationEvent>;
40
40
  pagedown: EventEmitter<NavigationEvent>;
41
41
  pageup: EventEmitter<NavigationEvent>;
42
+ selectnext: EventEmitter<NavigationEvent>;
43
+ selectprevious: EventEmitter<NavigationEvent>;
44
+ selectall: EventEmitter<NavigationEvent>;
45
+ selectalltobeginning: EventEmitter<NavigationEvent>;
46
+ selectalltoend: EventEmitter<NavigationEvent>;
42
47
  constructor(disabledItemsService: DisabledItemsService, selectionService: SelectionService);
43
48
  process(args: any): NavigationAction;
44
49
  private next;
@@ -3,38 +3,52 @@
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { EventEmitter } from '@angular/core';
6
+ import { DisabledItemsService } from '../disabled-items/disabled-items.service';
6
7
  import * as i0 from "@angular/core";
7
8
  /**
8
9
  * @hidden
9
10
  */
10
11
  export interface SelectionEvent {
11
12
  indices: number[];
12
- added?: number;
13
- removed?: number;
13
+ added?: number | number[];
14
+ removed?: number | number[];
14
15
  newSelection?: boolean;
16
+ preventClosingPopup?: boolean;
17
+ isMultipleSelection?: boolean;
15
18
  }
16
19
  /**
17
20
  * @hidden
18
21
  */
19
22
  export declare class SelectionService {
23
+ private disabledItemsService;
20
24
  onSelect: EventEmitter<SelectionEvent>;
21
25
  onChange: EventEmitter<SelectionEvent>;
22
26
  onFocus: EventEmitter<number>;
23
27
  total: number;
28
+ lastClickedIndex: number;
24
29
  private selectedIndices;
25
30
  private focusedIndex;
31
+ constructor(disabledItemsService: DisabledItemsService);
26
32
  getTotal(): number;
27
33
  isSelected(index: number): boolean;
28
34
  isFocused(index: number): boolean;
29
35
  focus(index: number): void;
30
36
  select(index: number): void;
31
- add(index: number): void;
32
- unselect(index: number): void;
37
+ add(index: number, preventClosingPopup?: boolean): void;
38
+ private indicesToBeRemoved;
39
+ private indicesToBeAdded;
40
+ emitMultipleAddedRemoved(): void;
41
+ addMultiple(indices: number[]): void;
42
+ deselect(index: number, preventClosingPopup?: boolean): void;
43
+ unselectMultiple(indices: number[]): void;
33
44
  change(index: number): void;
34
45
  resetSelection(index: number | number[]): void;
35
46
  get selected(): number[];
36
47
  get focused(): number;
37
48
  set focused(index: number);
49
+ selectFromTo(from: number, to: number): void;
50
+ unselectFromTo(from: number, to: number): void;
51
+ unselectNotNeededIndices(startOfSelection: number, endOfSelection: number, totalItems: number): void;
38
52
  static ɵfac: i0.ɵɵFactoryDeclaration<SelectionService, never>;
39
53
  static ɵprov: i0.ɵɵInjectableDeclaration<SelectionService>;
40
54
  }
package/common/util.d.ts CHANGED
@@ -157,3 +157,7 @@ export declare const getRoundedClass: (rounded: DropDownRounded) => string;
157
157
  * Return the fillMode class based on the component and fillMode input.
158
158
  */
159
159
  export declare const getFillModeClass: (component: string, fillMode: DropDownFillMode) => string;
160
+ /**
161
+ * @hidden
162
+ */
163
+ export declare const filterAndMap: (arr: any[], predicate: (item: any) => boolean, mapper: (item: any) => any) => any[];
@@ -752,6 +752,7 @@ export class AutoCompleteComponent {
752
752
  this.escSubscription = this.navigationService.esc.subscribe(this.handleEscape.bind(this));
753
753
  this.scrollSubscription = merge(this.navigationService.pagedown, this.navigationService.pageup).subscribe((event) => {
754
754
  if (this.isOpen) {
755
+ event.originalEvent.preventDefault();
755
756
  this.optionsList.scrollWithOnePage(NavigationAction[event.originalEvent.code]);
756
757
  }
757
758
  });
@@ -616,6 +616,7 @@ export class ComboBoxComponent {
616
616
  this.subs.add(this.navigationService.close.subscribe(() => this.togglePopup(false)));
617
617
  this.subs.add(merge(this.navigationService.pagedown, this.navigationService.pageup).subscribe((event) => {
618
618
  if (this.isOpen) {
619
+ event.originalEvent.preventDefault();
619
620
  this.optionsList.scrollWithOnePage(NavigationAction[event.originalEvent.code]);
620
621
  }
621
622
  }));
@@ -3,7 +3,7 @@
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { Injectable } from '@angular/core';
6
- import { isPresent, hasProps, getter } from './util';
6
+ import { isPresent, hasProps, getter, filterAndMap } from './util';
7
7
  import * as i0 from "@angular/core";
8
8
  /**
9
9
  * @hidden
@@ -178,6 +178,16 @@ export class DataService {
178
178
  }
179
179
  return this._flatData.find((item) => item.header && item.index === index);
180
180
  }
181
+ /**
182
+ * @hidden
183
+ * Used to get all group items indices.
184
+ */
185
+ groupItemsIndices() {
186
+ if (this.isGrouped) {
187
+ return filterAndMap(this.data, item => item.header, mappedItem => mappedItem.index);
188
+ }
189
+ return [];
190
+ }
181
191
  /**
182
192
  * @hidden
183
193
  * Used to get the field by which the data is grouped.
@@ -142,7 +142,7 @@ export class ListComponent {
142
142
  this.selectionService.add(index);
143
143
  }
144
144
  if (!isChecked && this.selectionService.isSelected(index)) {
145
- this.selectionService.unselect(index);
145
+ this.selectionService.deselect(index);
146
146
  }
147
147
  }
148
148
  prepareClasses() {
@@ -24,4 +24,9 @@ export var NavigationAction;
24
24
  NavigationAction[NavigationAction["Right"] = 13] = "Right";
25
25
  NavigationAction[NavigationAction["PageDown"] = 14] = "PageDown";
26
26
  NavigationAction[NavigationAction["PageUp"] = 15] = "PageUp";
27
+ NavigationAction[NavigationAction["SelectPrevious"] = 16] = "SelectPrevious";
28
+ NavigationAction[NavigationAction["SelectNext"] = 17] = "SelectNext";
29
+ NavigationAction[NavigationAction["SelectAll"] = 18] = "SelectAll";
30
+ NavigationAction[NavigationAction["SelectAllToBeginning"] = 19] = "SelectAllToBeginning";
31
+ NavigationAction[NavigationAction["SelectAllToEnd"] = 20] = "SelectAllToEnd";
27
32
  })(NavigationAction || (NavigationAction = {}));
@@ -44,10 +44,17 @@ export class NavigationService {
44
44
  this.end = new EventEmitter();
45
45
  this.pagedown = new EventEmitter();
46
46
  this.pageup = new EventEmitter();
47
+ this.selectnext = new EventEmitter();
48
+ this.selectprevious = new EventEmitter();
49
+ this.selectall = new EventEmitter();
50
+ this.selectalltobeginning = new EventEmitter();
51
+ this.selectalltoend = new EventEmitter();
47
52
  }
48
53
  process(args) {
49
54
  const keyCode = args.originalEvent.keyCode;
50
55
  const altKey = args.originalEvent.altKey;
56
+ const shiftKey = args.originalEvent.shiftKey;
57
+ const ctrlKey = args.originalEvent.ctrlKey;
51
58
  let index;
52
59
  let action = NavigationAction.Undefined;
53
60
  if (altKey && keyCode === Keys.ArrowDown) {
@@ -56,6 +63,21 @@ export class NavigationService {
56
63
  else if (altKey && keyCode === Keys.ArrowUp) {
57
64
  action = NavigationAction.Close;
58
65
  }
66
+ else if (shiftKey && keyCode === Keys.ArrowUp) {
67
+ action = NavigationAction.SelectPrevious;
68
+ }
69
+ else if (shiftKey && keyCode === Keys.ArrowDown) {
70
+ action = NavigationAction.SelectNext;
71
+ }
72
+ else if (ctrlKey && keyCode === Keys.KeyA) {
73
+ action = NavigationAction.SelectAll;
74
+ }
75
+ else if (ctrlKey && shiftKey && keyCode === Keys.Home) {
76
+ action = NavigationAction.SelectAllToBeginning;
77
+ }
78
+ else if (ctrlKey && shiftKey && keyCode === Keys.End) {
79
+ action = NavigationAction.SelectAllToEnd;
80
+ }
59
81
  else if (keyCode === Keys.Enter) {
60
82
  action = NavigationAction.Enter;
61
83
  }
@@ -24,12 +24,13 @@ export class SelectableDirective {
24
24
  }
25
25
  onClick(event) {
26
26
  event.stopPropagation();
27
+ this.selectionService.lastClickedIndex = this.index;
27
28
  if (this.checkboxes.enabled && !this.checkboxes.checkOnClick) {
28
29
  return;
29
30
  }
30
31
  if (this.multipleSelection) {
31
32
  if (this.selectionService.isSelected(this.index)) {
32
- this.selectionService.unselect(this.index);
33
+ this.selectionService.deselect(this.index);
33
34
  }
34
35
  else {
35
36
  this.selectionService.add(this.index);
@@ -5,16 +5,20 @@
5
5
  import { Injectable, EventEmitter } from '@angular/core';
6
6
  import { isPresent } from '../util';
7
7
  import * as i0 from "@angular/core";
8
+ import * as i1 from "../disabled-items/disabled-items.service";
8
9
  /**
9
10
  * @hidden
10
11
  */
11
12
  export class SelectionService {
12
- constructor() {
13
+ constructor(disabledItemsService) {
14
+ this.disabledItemsService = disabledItemsService;
13
15
  this.onSelect = new EventEmitter();
14
16
  this.onChange = new EventEmitter();
15
17
  this.onFocus = new EventEmitter();
16
18
  this.total = 0;
17
19
  this.selectedIndices = [];
20
+ this.indicesToBeRemoved = [];
21
+ this.indicesToBeAdded = [];
18
22
  }
19
23
  getTotal() {
20
24
  return this.total;
@@ -43,7 +47,7 @@ export class SelectionService {
43
47
  newSelection: isPresent(index)
44
48
  });
45
49
  }
46
- add(index) {
50
+ add(index, preventClosingPopup) {
47
51
  if (this.isSelected(index)) {
48
52
  return;
49
53
  }
@@ -51,20 +55,47 @@ export class SelectionService {
51
55
  this.focused = index;
52
56
  this.onChange.emit({
53
57
  added: index,
54
- indices: this.selectedIndices.slice()
58
+ indices: this.selectedIndices.slice(),
59
+ preventClosingPopup: preventClosingPopup
60
+ });
61
+ }
62
+ emitMultipleAddedRemoved() {
63
+ this.onChange.emit({
64
+ added: this.indicesToBeAdded,
65
+ removed: this.indicesToBeRemoved,
66
+ indices: this.selectedIndices.slice(),
67
+ preventClosingPopup: true,
68
+ isMultipleSelection: true
55
69
  });
70
+ this.indicesToBeAdded = [];
71
+ this.indicesToBeRemoved = [];
72
+ }
73
+ addMultiple(indices) {
74
+ this.indicesToBeAdded = indices.slice();
75
+ this.selectedIndices.push(...indices);
56
76
  }
57
- unselect(index) {
77
+ deselect(index, preventClosingPopup) {
58
78
  if (!this.isSelected(index)) {
59
79
  return;
60
80
  }
61
81
  const position = this.selectedIndices.indexOf(index);
62
82
  this.selectedIndices.splice(position, 1);
63
83
  this.focused = index;
84
+ if (this.selected.length === 0) {
85
+ this.lastClickedIndex = null;
86
+ }
64
87
  this.onChange.emit({
65
88
  indices: this.selectedIndices.slice(),
66
- removed: index
89
+ removed: index,
90
+ preventClosingPopup: preventClosingPopup
91
+ });
92
+ }
93
+ unselectMultiple(indices) {
94
+ indices.forEach((index) => {
95
+ const position = this.selectedIndices.indexOf(index);
96
+ this.selectedIndices.splice(position, 1);
67
97
  });
98
+ this.indicesToBeRemoved = indices.slice();
68
99
  }
69
100
  change(index) {
70
101
  const newSelection = isPresent(index) && !this.isSelected(index);
@@ -91,9 +122,41 @@ export class SelectionService {
91
122
  this.onFocus.emit(index);
92
123
  }
93
124
  }
125
+ selectFromTo(from, to) {
126
+ let addedIndices = [];
127
+ for (let i = from; i <= to; i++) {
128
+ if (!this.isSelected(i) && !this.disabledItemsService.isIndexDisabled(i)) {
129
+ addedIndices.push(i);
130
+ }
131
+ }
132
+ this.addMultiple(addedIndices);
133
+ }
134
+ unselectFromTo(from, to) {
135
+ let indicesToBeUnselected = [];
136
+ for (let i = from; i >= to; i--) {
137
+ if (this.isSelected(i) && !this.disabledItemsService.isIndexDisabled(i)) {
138
+ indicesToBeUnselected.push(i);
139
+ }
140
+ }
141
+ this.unselectMultiple(indicesToBeUnselected);
142
+ }
143
+ unselectNotNeededIndices(startOfSelection, endOfSelection, totalItems) {
144
+ let indicesToBeUnselected = [];
145
+ for (let i = 0; i < startOfSelection; i++) {
146
+ if (this.isSelected(i)) {
147
+ indicesToBeUnselected.push(i);
148
+ }
149
+ }
150
+ for (let i = endOfSelection + 1; i < totalItems; i++) {
151
+ if (this.isSelected(i)) {
152
+ indicesToBeUnselected.push(i);
153
+ }
154
+ }
155
+ this.unselectMultiple(indicesToBeUnselected);
156
+ }
94
157
  }
95
- SelectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SelectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
158
+ SelectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SelectionService, deps: [{ token: i1.DisabledItemsService }], target: i0.ɵɵFactoryTarget.Injectable });
96
159
  SelectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SelectionService });
97
160
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SelectionService, decorators: [{
98
161
  type: Injectable
99
- }] });
162
+ }], ctorParameters: function () { return [{ type: i1.DisabledItemsService }]; } });
@@ -324,3 +324,7 @@ export const getFillModeClass = (component, fillMode) => {
324
324
  };
325
325
  return FILLMODE_CLASSES[fillMode];
326
326
  };
327
+ /**
328
+ * @hidden
329
+ */
330
+ export const filterAndMap = (arr, predicate, mapper) => arr.reduce((acc, curr) => predicate(curr) ? [...acc, mapper(curr)] : acc, []);
@@ -898,6 +898,7 @@ export class DropDownListComponent {
898
898
  .subscribe((event) => this.selectionService.select(event.index)));
899
899
  this.subs.add(merge(this.navigationService.pagedown, this.navigationService.pageup).subscribe((event) => {
900
900
  if (this.isOpen) {
901
+ event.originalEvent.preventDefault();
901
902
  this.optionsList.scrollWithOnePage(NavigationAction[event.originalEvent.code]);
902
903
  }
903
904
  }));
@@ -5,7 +5,7 @@
5
5
  import { guid, isPresent, isArray, isObjectArray, resolveAllValues, selectedIndices, getter, isNumber, isUntouched, inDropDown, getSizeClass, getRoundedClass, getFillModeClass } from '../common/util';
6
6
  import { SearchBarComponent } from '../common/searchbar.component';
7
7
  import { ViewChild, ViewContainerRef, Component, HostBinding, Input, Output, EventEmitter, isDevMode, forwardRef, ContentChild, Optional, Inject, HostListener } from '@angular/core';
8
- import { Subscription, Subject, of } from 'rxjs';
8
+ import { Subscription, Subject, of, merge } from 'rxjs';
9
9
  import { catchError, filter, map, tap } from 'rxjs/operators';
10
10
  import { isChanged, isDocumentAvailable, KendoInput, hasObservers, anyChanged } from '@progress/kendo-angular-common';
11
11
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
@@ -560,6 +560,16 @@ export class MultiSelectComponent {
560
560
  get isLoading() {
561
561
  return this.loading;
562
562
  }
563
+ /**
564
+ * @hidden
565
+ */
566
+ handleKeyboardEvent(event) {
567
+ if (event.ctrlKey && event.keyCode === Keys.KeyA) {
568
+ event.preventDefault();
569
+ event.stopImmediatePropagation();
570
+ this.handleSelectAll();
571
+ }
572
+ }
563
573
  /**
564
574
  * @hidden
565
575
  */
@@ -651,23 +661,45 @@ export class MultiSelectComponent {
651
661
  * @hidden
652
662
  */
653
663
  change(event) {
654
- const isCustomItem = (isPresent(event.added) || isPresent(event.removed)) && (event.added === -1 || event.removed === -1);
655
- if (isCustomItem) {
656
- this.addCustomValue(this.text);
657
- return; // The change is emited asynchronosly.
658
- }
659
- // Existing items.
660
- if (isPresent(event.added)) {
661
- const dataItem = this.dataService.itemAt(event.added);
662
- const newItem = (this.valuePrimitive && isPresent(dataItem) && isPresent(dataItem[this.valueField])) ? dataItem[this.valueField] : dataItem;
663
- this.value = [...this.value, newItem];
664
- }
665
- if (isPresent(event.removed)) {
666
- const dataItem = this.dataService.itemAt(event.removed);
667
- const filter = (item) => getter(item, this.valueField) !== getter(dataItem, this.valueField);
668
- this.value = this.value.filter(filter);
669
- this.selectionService.focused = event.removed;
670
- this.cdr.detectChanges();
664
+ if (event.isMultipleSelection) {
665
+ // Existing items.
666
+ if (isPresent(event.added) && event.added.length > 0) {
667
+ event.added.forEach((itemIndex) => {
668
+ const dataItem = this.dataService.itemAt(itemIndex);
669
+ const newItem = (this.valuePrimitive && isPresent(dataItem) && isPresent(dataItem[this.valueField])) ? dataItem[this.valueField] : dataItem;
670
+ if (newItem) {
671
+ this.value = [...this.value, newItem];
672
+ }
673
+ });
674
+ }
675
+ if (isPresent(event.removed) && event.removed.length > 0) {
676
+ event.removed.forEach((itemIndex) => {
677
+ const dataItem = this.dataService.itemAt(itemIndex);
678
+ const filter = (item) => getter(item, this.valueField) !== getter(dataItem, this.valueField);
679
+ this.value = this.value.filter(filter);
680
+ });
681
+ this.cdr.detectChanges();
682
+ }
683
+ }
684
+ else {
685
+ const isCustomItem = (isPresent(event.added) || isPresent(event.removed)) && (event.added === -1 || event.removed === -1);
686
+ if (isCustomItem) {
687
+ this.addCustomValue(this.text);
688
+ return; // The change is emited asynchronosly.
689
+ }
690
+ // Existing items.
691
+ if (isPresent(event.added)) {
692
+ const dataItem = this.dataService.itemAt(event.added);
693
+ const newItem = (this.valuePrimitive && isPresent(dataItem) && isPresent(dataItem[this.valueField])) ? dataItem[this.valueField] : dataItem;
694
+ this.value = [...this.value, newItem];
695
+ }
696
+ if (isPresent(event.removed)) {
697
+ const dataItem = this.dataService.itemAt(event.removed);
698
+ const filter = (item) => getter(item, this.valueField) !== getter(dataItem, this.valueField);
699
+ this.value = this.value.filter(filter);
700
+ this.selectionService.focused = event.removed;
701
+ this.cdr.detectChanges();
702
+ }
671
703
  }
672
704
  this.emitValueChange();
673
705
  }
@@ -800,10 +832,11 @@ export class MultiSelectComponent {
800
832
  * @hidden
801
833
  */
802
834
  clearAll(event) {
803
- event.stopImmediatePropagation();
804
- event.preventDefault();
835
+ event === null || event === void 0 ? void 0 : event.stopImmediatePropagation();
836
+ event === null || event === void 0 ? void 0 : event.preventDefault();
805
837
  this.focus();
806
838
  this.clearFilter();
839
+ this.selectionService.lastClickedIndex = null;
807
840
  const selected = this.selectionService.selected;
808
841
  this.value = this.value.filter((_item, index) => this.disabledItemsService.isIndexDisabled(selected[index]));
809
842
  this.emitValueChange();
@@ -952,7 +985,17 @@ export class MultiSelectComponent {
952
985
  this.navigationService.delete.pipe(filter(isTagFocused)).subscribe(this.handleDelete.bind(this)),
953
986
  this.navigationService.left.subscribe(this.direction === 'rtl' ? this.handleRightKey.bind(this) : this.handleLeftKey.bind(this)),
954
987
  this.navigationService.right.subscribe(this.direction === 'rtl' ? this.handleLeftKey.bind(this) : this.handleRightKey.bind(this)),
955
- this.navigationService.down.subscribe((event) => this.handleDownKey(event.index))
988
+ this.navigationService.down.subscribe((event) => this.handleDownKey(event.index)),
989
+ this.navigationService.selectprevious.pipe(filter(isOpen)).subscribe((event) => this.handleSelectUpDown(event)),
990
+ this.navigationService.selectnext.pipe(filter(isOpen)).subscribe((event) => this.handleSelectUpDown(event)),
991
+ this.navigationService.selectalltobeginning.pipe(filter(isOpen)).subscribe(() => this.handleSelectAllToBeginning()),
992
+ this.navigationService.selectalltoend.pipe(filter(isOpen)).subscribe(() => this.handleSelectAllToEnd()),
993
+ merge(this.navigationService.pagedown, this.navigationService.pageup).subscribe((event) => {
994
+ if (this.isOpen) {
995
+ event.originalEvent.preventDefault();
996
+ this.optionsList.scrollWithOnePage(NavigationAction[event.originalEvent.code]);
997
+ }
998
+ })
956
999
  ].forEach(s => this.observableSubscriptions.add(s));
957
1000
  }
958
1001
  subscribeTouchEvents() {
@@ -1011,7 +1054,7 @@ export class MultiSelectComponent {
1011
1054
  return;
1012
1055
  }
1013
1056
  if (isNumber(index)) {
1014
- this.selectionService.unselect(index);
1057
+ this.selectionService.deselect(index);
1015
1058
  this.selectionService.focused = index;
1016
1059
  this.togglePopup(false);
1017
1060
  }
@@ -1076,7 +1119,7 @@ export class MultiSelectComponent {
1076
1119
  }
1077
1120
  else {
1078
1121
  if (!customItem && this.selectionService.isSelected(itemIndex)) {
1079
- this.selectionService.unselect(itemIndex);
1122
+ this.selectionService.deselect(itemIndex);
1080
1123
  this.selectionService.focused = itemIndex;
1081
1124
  }
1082
1125
  else {
@@ -1098,7 +1141,7 @@ export class MultiSelectComponent {
1098
1141
  }
1099
1142
  handleItemChange(event) {
1100
1143
  this.change(event);
1101
- if (this.autoClose) {
1144
+ if (this.autoClose && !event.preventClosingPopup) {
1102
1145
  this.togglePopup(false);
1103
1146
  }
1104
1147
  if (this.autoClose || !this.filterable) {
@@ -1108,6 +1151,7 @@ export class MultiSelectComponent {
1108
1151
  handleEnter(event) {
1109
1152
  const service = this.selectionService;
1110
1153
  const focusedIndex = this.selectionService.focused;
1154
+ this.selectionService.lastClickedIndex = focusedIndex;
1111
1155
  if (this.isOpen) {
1112
1156
  event.originalEvent.preventDefault();
1113
1157
  }
@@ -1118,7 +1162,7 @@ export class MultiSelectComponent {
1118
1162
  return; // Clear filter & close are done at customValueSubscription due to race conditions.
1119
1163
  }
1120
1164
  if (service.isSelected(focusedIndex)) {
1121
- service.unselect(focusedIndex);
1165
+ service.deselect(focusedIndex);
1122
1166
  service.focused = focusedIndex;
1123
1167
  }
1124
1168
  else {
@@ -1141,6 +1185,85 @@ export class MultiSelectComponent {
1141
1185
  handleHome() {
1142
1186
  this.focusedTagIndex = 0;
1143
1187
  }
1188
+ sortSelectionAscending() {
1189
+ return this.selectionService.selected.sort((a, b) => a - b);
1190
+ }
1191
+ handleSelectAll() {
1192
+ const selectedItemsCount = this.selectionService.selected.length;
1193
+ const dataItemsCount = this.dataService.data.length;
1194
+ const dataItemsWithoutHeadersCount = this.dataService.data.filter(i => !i.header).length;
1195
+ if ((!this.dataService.grouped && selectedItemsCount === dataItemsCount) ||
1196
+ (this.dataService.grouped && selectedItemsCount === dataItemsWithoutHeadersCount)) {
1197
+ this.clearAll();
1198
+ }
1199
+ else {
1200
+ this.selectionService.selectFromTo(0, dataItemsCount - 1);
1201
+ this.selectionService.emitMultipleAddedRemoved();
1202
+ }
1203
+ }
1204
+ handleSelectAllToBeginning() {
1205
+ const selectedItemsCount = this.selectionService.selected.length;
1206
+ const dataItemsCount = this.dataService.data.length;
1207
+ const focusedItem = this.selectionService.focused;
1208
+ const largestIndex = this.sortSelectionAscending()[selectedItemsCount - 1];
1209
+ if (selectedItemsCount !== dataItemsCount) {
1210
+ this.selectionService.unselectFromTo(largestIndex, focusedItem + 1);
1211
+ this.selectionService.selectFromTo(0, focusedItem);
1212
+ }
1213
+ this.nextTick(() => this.selectionService.focus(0));
1214
+ this.selectionService.emitMultipleAddedRemoved();
1215
+ }
1216
+ handleSelectAllToEnd() {
1217
+ const selectedItemsCount = this.selectionService.selected.length;
1218
+ const dataItemsCount = this.dataService.data.length;
1219
+ const focusedItem = this.selectionService.focused;
1220
+ if (selectedItemsCount !== dataItemsCount) {
1221
+ this.selectionService.unselectFromTo(focusedItem - 1, 0);
1222
+ this.selectionService.selectFromTo(focusedItem, dataItemsCount - 1);
1223
+ }
1224
+ if (this.dataService.grouped) {
1225
+ const lastItemIndex = this.dataService.groupIndices[this.dataService.groupIndices.length - 1] - 1;
1226
+ this.nextTick(() => this.selectionService.focus(lastItemIndex));
1227
+ }
1228
+ else {
1229
+ this.nextTick(() => this.selectionService.focus(dataItemsCount - 1));
1230
+ }
1231
+ this.selectionService.emitMultipleAddedRemoved();
1232
+ }
1233
+ handleSelectUpDown(event) {
1234
+ const focusedIndex = this.selectionService.focused;
1235
+ if (!isPresent(focusedIndex)) {
1236
+ return;
1237
+ }
1238
+ let indexToSelect;
1239
+ if (event.originalEvent.key === 'ArrowUp') {
1240
+ indexToSelect = focusedIndex > 0 ? focusedIndex - 1 : focusedIndex;
1241
+ }
1242
+ else {
1243
+ indexToSelect = focusedIndex < this.dataService.data.length - 1 ? focusedIndex + 1 : focusedIndex;
1244
+ }
1245
+ if (!isPresent(this.selectionService.lastClickedIndex)) {
1246
+ this.selectionService.lastClickedIndex = focusedIndex;
1247
+ }
1248
+ this.selectRangeFromTo(indexToSelect);
1249
+ }
1250
+ /**
1251
+ * Selects all items between the focused item and the last clicked item (index). Also removes all other selected items.
1252
+ */
1253
+ selectRangeFromTo(indexToSelect) {
1254
+ const lastClickedIndex = this.selectionService.lastClickedIndex;
1255
+ if (lastClickedIndex > indexToSelect) {
1256
+ this.selectionService.unselectNotNeededIndices(indexToSelect, lastClickedIndex, this.dataService.data.length);
1257
+ this.selectionService.selectFromTo(indexToSelect, this.selectionService.lastClickedIndex);
1258
+ this.selectionService.emitMultipleAddedRemoved();
1259
+ }
1260
+ else {
1261
+ this.selectionService.unselectNotNeededIndices(lastClickedIndex, indexToSelect, this.dataService.data.length);
1262
+ this.selectionService.selectFromTo(lastClickedIndex, indexToSelect);
1263
+ this.selectionService.emitMultipleAddedRemoved();
1264
+ }
1265
+ this.nextTick(() => this.selectionService.focus(indexToSelect));
1266
+ }
1144
1267
  handleUp(index) {
1145
1268
  this.selectionService.focused = index;
1146
1269
  }
@@ -1339,7 +1462,7 @@ export class MultiSelectComponent {
1339
1462
  }
1340
1463
  }
1341
1464
  MultiSelectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: MultiSelectComponent, deps: [{ token: i0.ElementRef }, { token: i1.LocalizationService }, { token: i2.PopupService }, { token: i3.DataService }, { token: i4.SelectionService }, { token: i5.NavigationService }, { token: i6.DisabledItemsService }, { token: i0.ChangeDetectorRef }, { token: i0.KeyValueDiffers }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: TOUCH_ENABLED, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1342
- MultiSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: MultiSelectComponent, selector: "kendo-multiselect", inputs: { focusableId: "focusableId", autoClose: "autoClose", loading: "loading", data: "data", value: "value", valueField: "valueField", textField: "textField", tabindex: "tabindex", tabIndex: "tabIndex", size: "size", rounded: "rounded", fillMode: "fillMode", placeholder: "placeholder", disabled: "disabled", itemDisabled: "itemDisabled", checkboxes: "checkboxes", readonly: "readonly", filterable: "filterable", virtual: "virtual", popupSettings: "popupSettings", listHeight: "listHeight", valuePrimitive: "valuePrimitive", clearButton: "clearButton", tagMapper: "tagMapper", allowCustom: "allowCustom", valueNormalizer: "valueNormalizer" }, outputs: { filterChange: "filterChange", valueChange: "valueChange", open: "open", opened: "opened", close: "close", closed: "closed", onFocus: "focus", onBlur: "blur", removeTag: "removeTag" }, host: { listeners: { "mousedown": "hostMousedown($event)" }, properties: { "class.k-multiselect": "this.hostClasses", "class.k-input": "this.hostClasses", "attr.dir": "this.dir", "class.k-disabled": "this.disabledClass", "class.k-loading": "this.isLoading" } }, providers: [
1465
+ MultiSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: MultiSelectComponent, selector: "kendo-multiselect", inputs: { focusableId: "focusableId", autoClose: "autoClose", loading: "loading", data: "data", value: "value", valueField: "valueField", textField: "textField", tabindex: "tabindex", tabIndex: "tabIndex", size: "size", rounded: "rounded", fillMode: "fillMode", placeholder: "placeholder", disabled: "disabled", itemDisabled: "itemDisabled", checkboxes: "checkboxes", readonly: "readonly", filterable: "filterable", virtual: "virtual", popupSettings: "popupSettings", listHeight: "listHeight", valuePrimitive: "valuePrimitive", clearButton: "clearButton", tagMapper: "tagMapper", allowCustom: "allowCustom", valueNormalizer: "valueNormalizer" }, outputs: { filterChange: "filterChange", valueChange: "valueChange", open: "open", opened: "opened", close: "close", closed: "closed", onFocus: "focus", onBlur: "blur", removeTag: "removeTag" }, host: { listeners: { "document:keydown": "handleKeyboardEvent($event)", "mousedown": "hostMousedown($event)" }, properties: { "class.k-multiselect": "this.hostClasses", "class.k-input": "this.hostClasses", "attr.dir": "this.dir", "class.k-disabled": "this.disabledClass", "class.k-loading": "this.isLoading" } }, providers: [
1343
1466
  MULTISELECT_VALUE_ACCESSOR,
1344
1467
  DataService,
1345
1468
  SelectionService,
@@ -1778,6 +1901,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1778
1901
  }], isLoading: [{
1779
1902
  type: HostBinding,
1780
1903
  args: ['class.k-loading']
1904
+ }], handleKeyboardEvent: [{
1905
+ type: HostListener,
1906
+ args: ['document:keydown', ['$event']]
1781
1907
  }], hostMousedown: [{
1782
1908
  type: HostListener,
1783
1909
  args: ['mousedown', ['$event']]
@@ -9,7 +9,7 @@ export const packageMetadata = {
9
9
  name: '@progress/kendo-angular-dropdowns',
10
10
  productName: 'Kendo UI for Angular',
11
11
  productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
12
- publishDate: 1661869333,
12
+ publishDate: 1663064236,
13
13
  version: '',
14
14
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/?utm_medium=product&utm_source=kendoangular&utm_campaign=kendo-ui-angular-purchase-license-keys-warning'
15
15
  };