Skip to content

Commit 0caeb8d

Browse files
committed
Merge branch 'master' into fix-#5361
2 parents 9a59ffb + 76c6649 commit 0caeb8d

File tree

165 files changed

+4401
-2712
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

165 files changed

+4401
-2712
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,24 @@ All notable changes for each version of this project will be documented in this
1212
- You can use this mode to apply directives on the tab items - for example to achieve routing navigation.
1313
- You are allowed to customize tab items with labels, icons and even templates.
1414
- `IgxGrid`
15+
- **Behavioral Change** - paging now includes the group rows in the page size. You may find more information about the change in the [GroupBy Specification](https://github.com/IgniteUI/igniteui-angular/wiki/Group-By-Specification)
1516
- `IgxColumnGroup`
1617
- Re-templating the column group header is now possible using the `headerTemplate` input property or the `igxHeader` directive.
18+
- `igx-grid-footer`
19+
- You can use this to insert a custom footer in the grids.
20+
```html
21+
<igx-grid>
22+
<igx-grid-footer>
23+
Custom content
24+
</igx-grid-footer>
25+
</igx-grid>
26+
```
27+
- `igx-paginator`
28+
- Replaces the current paginator in all grids. Can be used as a standalone component.
29+
- `IgxCombo`
30+
- Input `[overlaySettings]` - allows an object of type `OverlaySettings` to be passed. These custom overlay settings control how the drop-down list displays.
31+
- `IgxForOf` now offers usage of local variables `even`, `odd`, `first` and `last` to help with the distinction of the currently iterated element.
32+
1733

1834
## 8.0.2
1935
- `igx-list-theme` now have some new parameters for styling.

projects/igniteui-angular/src/lib/combo/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ Setting `[displayDensity]` affects the control's items' and inputs' css properti
265265
| `ariaLabelledBy` | defines label ID related to combo | boolean |
266266
| `type` | Combo style. - "line", "box", "border", "search" | string |
267267
| `valid` | gets if control is valid, when used in a form | boolean |
268+
| `overlaySettings` | gets/sets the custom overlay settings that control how the drop-down list displays | OverlaySettings |
268269

269270
### Getters
270271
| Name | Description | Type |
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<ng-container *ngIf="!isHeader">
2-
<igx-checkbox [checked]="selected" disableRipple="true" [disableTransitions]="disableTransitions" disabled="true" class="igx-combo__checkbox"></igx-checkbox>
2+
<igx-checkbox [checked]="selected" disableRipple="true" [disableTransitions]="disableTransitions" [tabindex]="-1" (click)="disableCheck($event)" class="igx-combo__checkbox"></igx-checkbox>
33
</ng-container>
44
<ng-content></ng-content>

projects/igniteui-angular/src/lib/combo/combo-item.component.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ export class IgxComboItemComponent extends IgxDropDownItemComponent implements D
9999
this.comboAPI.set_selected_item(this.itemID, event);
100100
}
101101

102+
/**
103+
* @hidden
104+
* @internal
105+
* The event that is prevented is the click on the checkbox label element.
106+
* That is the only visible element that a user can interact with.
107+
* The click propagates to the host and the preventDefault is to stop it from
108+
* switching focus to the input it's base on.
109+
* The toggle happens in an internal handler in the drop-down on the next task queue cycle.
110+
*/
111+
disableCheck(event: MouseEvent) {
112+
event.preventDefault();
113+
}
114+
102115
ngDoCheck() {
103116
}
104117
}

projects/igniteui-angular/src/lib/combo/combo.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
</ng-container>
7575
</div>
7676
<igx-combo-add-item [itemHeight]='itemHeight' *ngIf="isAddButtonVisible()" [tabindex]="dropdown.collapsed ? -1 : customValueFlag ? 1 : -1"
77-
class="igx-combo__add-item" igxRipple role="button" aria-label="Add Item" [index]="virtualScrollContainer.igxForOf.length">
77+
class="igx-combo__add-item" role="button" aria-label="Add Item" [index]="virtualScrollContainer.igxForOf.length">
7878
<ng-container *ngTemplateOutlet="addItemTemplate ? addItemTemplate : addItemDefault">
7979
</ng-container>
8080
</igx-combo-add-item>

projects/igniteui-angular/src/lib/combo/combo.component.spec.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { DefaultSortingStrategy } from '../data-operations/sorting-strategy';
1616
import { configureTestSuite } from '../test-utils/configure-suite';
1717
import { IgxDropDownItemBase } from '../drop-down/drop-down-item.base';
1818
import { DisplayDensity, DisplayDensityToken } from '../core/density';
19+
import { AbsoluteScrollStrategy, ConnectedPositioningStrategy } from '../services/index';
1920

2021
const CSS_CLASS_COMBO = 'igx-combo';
2122
const CSS_CLASS_COMBO_DROPDOWN = 'igx-combo__drop-down';
@@ -28,6 +29,7 @@ const CSS_CLASS_DROPDOWNBUTTON = 'igx-combo__toggle-button';
2829
const CSS_CLASS_CLEARBUTTON = 'igx-combo__clear-button';
2930
const CSS_CLASS_CHECK_GENERAL = 'igx-combo__checkbox';
3031
const CSS_CLASS_CHECKBOX = 'igx-checkbox';
32+
const CSS_CLASS_CHECKBOX_LABEL = 'igx-checkbox__composite';
3133
const CSS_CLASS_CHECKED = 'igx-checkbox--checked';
3234
const CSS_CLASS_TOGGLE = 'igx-toggle';
3335
const CSS_CLASS_SELECTED = 'igx-drop-down__item--selected';
@@ -185,6 +187,23 @@ describe('igxCombo', () => {
185187
expect(combo.displayKey).toEqual('region');
186188
expect(combo.displayKey === combo.valueKey).toBeFalsy();
187189
});
190+
it('Should properly get/set overlaySettings', () => {
191+
const fixture = TestBed.createComponent(IgxComboTestComponent);
192+
fixture.detectChanges();
193+
const combo = fixture.componentInstance.combo;
194+
const defaultSettings = (combo as any)._overlaySettings;
195+
spyOn(combo.dropdown, 'toggle');
196+
combo.toggle();
197+
expect(combo.dropdown.toggle).toHaveBeenCalledWith(defaultSettings);
198+
const newSettings = {
199+
positionStrategy: new ConnectedPositioningStrategy({ target: fixture.elementRef.nativeElement}),
200+
scrollStrategy: new AbsoluteScrollStrategy(fixture.elementRef.nativeElement)
201+
};
202+
combo.overlaySettings = newSettings;
203+
const expectedSettings = Object.assign({}, defaultSettings, newSettings);
204+
combo.toggle();
205+
expect(combo.dropdown.toggle).toHaveBeenCalledWith(expectedSettings);
206+
});
188207

189208
describe('EditorProvider', () => {
190209
it('Should return correct edit element', () => {
@@ -932,7 +951,7 @@ describe('igxCombo', () => {
932951
}
933952
function clickItemCheckbox(dropdownElement: any, itemIndex: number) {
934953
const dropdownItems = dropdownElement.querySelectorAll('.' + CSS_CLASS_DROPDOWNLISTITEM);
935-
const checkbox = dropdownItems[itemIndex].querySelector('.' + CSS_CLASS_CHECKBOX) as HTMLElement;
954+
const checkbox = dropdownItems[itemIndex].querySelector('.' + CSS_CLASS_CHECKBOX_LABEL) as HTMLElement;
936955
checkbox.click();
937956
}
938957
function verifyItemIsSelected(

projects/igniteui-angular/src/lib/combo/combo.component.ts

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,6 @@ import { IgxComboAPIService } from './combo.api';
4242
import { EditorProvider } from '../core/edit-provider';
4343
import { take } from 'rxjs/operators';
4444

45-
/** Custom strategy to provide the combo with callback on initial positioning */
46-
class ComboConnectedPositionStrategy extends ConnectedPositioningStrategy {
47-
private _callback: () => void;
48-
constructor(callback: () => void) {
49-
super();
50-
this._callback = callback;
51-
}
52-
53-
position(contentElement, size, document?, initialCall?) {
54-
if (initialCall) {
55-
this._callback();
56-
}
57-
super.position(contentElement, size);
58-
}
59-
}
60-
6145
/**
6246
* @hidden
6347
*/
@@ -124,7 +108,7 @@ const noop = () => { };
124108
]
125109
})
126110
export class IgxComboComponent extends DisplayDensityBase implements IgxComboBase, AfterViewInit, ControlValueAccessor, OnInit,
127-
OnDestroy, EditorProvider {
111+
OnDestroy, EditorProvider {
128112
/**
129113
* @hidden @internal
130114
*/
@@ -148,10 +132,10 @@ export class IgxComboComponent extends DisplayDensityBase implements IgxComboBas
148132
private _filteredData = [];
149133
private _itemHeight = null;
150134
private _itemsMaxHeight = null;
151-
private _positionCallback: () => void;
152135
private _onChangeCallback: (_: any) => void = noop;
153-
private overlaySettings: OverlaySettings = {
136+
private _overlaySettings: OverlaySettings = {
154137
scrollStrategy: new AbsoluteScrollStrategy(),
138+
positionStrategy: new ConnectedPositioningStrategy(),
155139
modal: false,
156140
closeOnOutsideClick: true,
157141
excludePositionTarget: true
@@ -171,6 +155,26 @@ export class IgxComboComponent extends DisplayDensityBase implements IgxComboBas
171155
@ViewChild(IgxForOfDirective, { read: IgxForOfDirective, static: true })
172156
protected virtDir: IgxForOfDirective<any>;
173157

158+
/**
159+
* Set custom overlay settings that control how the combo's list of items is displayed.
160+
* Set:
161+
* ```html
162+
* <igx-combo [overlaySettings] = "customOverlaySettings"></igx-combo>
163+
* ```
164+
*
165+
* ```typescript
166+
* const customSettings = { positionStrategy: { settings: { target: myTarget } } };
167+
* combo.overlaySettings = customSettings;
168+
* ```
169+
* Get any custom overlay settings used by the combo:
170+
* ```typescript
171+
* const comboOverlaySettings: OverlaySettings = myCombo.overlaySettings;
172+
* ```
173+
*/
174+
175+
@Input()
176+
public overlaySettings: OverlaySettings = null;
177+
174178
/**
175179
* @hidden @internal
176180
*/
@@ -1249,9 +1253,7 @@ export class IgxComboComponent extends DisplayDensityBase implements IgxComboBas
12491253
*/
12501254
public ngOnInit() {
12511255
this.ngControl = this.injector.get(NgControl, null);
1252-
this._positionCallback = () => this.dropdown.updateScrollPosition();
1253-
this.overlaySettings.positionStrategy = new ComboConnectedPositionStrategy(this._positionCallback);
1254-
this.overlaySettings.positionStrategy.settings.target = this.elementRef.nativeElement;
1256+
this._overlaySettings.positionStrategy.settings.target = this.elementRef.nativeElement;
12551257
this.selection.set(this.id, new Set());
12561258
}
12571259

@@ -1263,7 +1265,7 @@ export class IgxComboComponent extends DisplayDensityBase implements IgxComboBas
12631265

12641266
if (this.ngControl) {
12651267
this.ngControl.statusChanges.pipe(takeUntil(this.destroy$)).subscribe(this.onStatusChanged);
1266-
}
1268+
}
12671269
}
12681270

12691271
/**
@@ -1358,7 +1360,8 @@ export class IgxComboComponent extends DisplayDensityBase implements IgxComboBas
13581360
*```
13591361
*/
13601362
public toggle(): void {
1361-
this.dropdown.toggle(this.overlaySettings);
1363+
const overlaySettings = Object.assign({}, this._overlaySettings, this.overlaySettings);
1364+
this.dropdown.toggle(overlaySettings);
13621365
}
13631366

13641367
/**
@@ -1370,7 +1373,8 @@ export class IgxComboComponent extends DisplayDensityBase implements IgxComboBas
13701373
*```
13711374
*/
13721375
public open(): void {
1373-
this.dropdown.open(this.overlaySettings);
1376+
const overlaySettings = Object.assign({}, this._overlaySettings, this.overlaySettings);
1377+
this.dropdown.open(overlaySettings);
13741378
}
13751379

13761380
/**

projects/igniteui-angular/src/lib/core/grid-selection.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ export class IgxGridCRUDService {
105105
return new IgxRow(cell.id.rowID, cell.rowIndex, cell.rowData);
106106
}
107107

108-
sameRow(rowID): boolean {
109-
return this.row && this.row.id === rowID;
108+
sameRow(rowIndex): boolean {
109+
return this.row && this.row.index === rowIndex;
110110
}
111111

112112
sameCell(cell: IgxCell): boolean {
@@ -175,7 +175,7 @@ export class IgxGridCRUDService {
175175
return;
176176
}
177177

178-
if (this.row && !this.sameRow(this.cell.id.rowID)) {
178+
if (this.row && !this.sameRow(this.cell.rowIndex)) {
179179
this.grid.endEdit(true);
180180
this.cell = this.createCell(cell);
181181
this.beginRowEdit();
@@ -371,11 +371,14 @@ export class IgxGridSelectionService {
371371
}
372372
}
373373

374-
keyboardStateOnFocus(node: ISelectionNode, emitter: EventEmitter<GridSelectionRange>): void {
374+
keyboardStateOnFocus(node: ISelectionNode, emitter: EventEmitter<GridSelectionRange>, dom): void {
375375
const kbState = this.keyboardState;
376376

377377
// Focus triggered by keyboard navigation
378378
if (kbState.active) {
379+
if (isChromium()) {
380+
this._moveSelectionChrome(dom);
381+
}
379382
// Start generating a range if shift is hold
380383
if (kbState.shift) {
381384
this.dragSelect(node, kbState);
@@ -525,6 +528,11 @@ export class IgxGridSelectionService {
525528
}
526529
}
527530

531+
/**
532+
* (╯°□°)╯︵ ┻━┻
533+
* Chrome and Chromium don't care about the active
534+
* range after keyboard navigation, thus this.
535+
*/
528536
_moveSelectionChrome(node: Node) {
529537
const selection = window.getSelection();
530538
selection.removeAllRanges();
@@ -534,3 +542,7 @@ export class IgxGridSelectionService {
534542
selection.addRange(range);
535543
}
536544
}
545+
546+
export function isChromium(): boolean {
547+
return (/Chrom|e?ium/g.test(navigator.userAgent) || /Google Inc/g.test(navigator.vendor)) && !/Edge/g.test(navigator.userAgent);
548+
}

projects/igniteui-angular/src/lib/core/styles/base/utilities/_functions.scss

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -220,23 +220,33 @@
220220

221221
/// Extends a Map object with the properties of another Map object.
222222
/// @access private
223-
/// @param {Map} $map1 - The source map to get extended.
224-
/// @param {Map} $map2 - The map extending the source map.
225-
/// @returns {Map} - Returns the original map extended with the properties of the second map.
226-
@function extend($map1, $map2) {
223+
/// @param {Map...} $maps - The source map to get extended.
224+
/// @returns {Map} - Returns the merged maps.
225+
@function extend($maps...) {
227226
$result: ();
228-
@each $key, $value in $map2 {
229-
@if not($value) {
230-
$result: map-merge($result, (
231-
#{$key}: map-get($map1, $key)
232-
));
233-
} @else {
227+
228+
@each $map in $maps {
229+
$result: map-merge($result, map-clean($map));
230+
}
231+
232+
@return $result;
233+
}
234+
235+
/// Removes all null key-value pairs from the map
236+
/// @access private
237+
/// @param {Map} $map - The target map to be cleaned.
238+
/// @returns {Map} - Returns a clean map.
239+
@function map-clean($map) {
240+
$result: ();
241+
242+
@each $key, $value in $map {
243+
@if($value) != null {
234244
$result: map-merge($result, (
235245
#{$key}: $value
236246
));
237247
}
238248
}
239-
$result: map-merge($map1, $result);
249+
240250
@return $result;
241251
}
242252

@@ -245,7 +255,6 @@
245255
/// @group Palettes
246256
/// @requires {function} gen-color
247257
/// @requires {function} text-contrast
248-
/// @requires {function} extend
249258
/// @param {Color} $color - The base color used to generate the palette.
250259
/// @param {List} $saturations - The saturation list of color variants.
251260
//// Based on the Material color system.
@@ -264,7 +273,6 @@
264273
/// @access private
265274
/// @group Palettes
266275
/// @requires {function} text-contrast
267-
/// @requires {function} extend
268276
/// @param {Color} $color - The base color used to generate the palette.
269277
/// @param {Map} $shades - A map of variations as keys and opacities as values.
270278
/// Based on the Material color system.
@@ -416,6 +424,7 @@
416424
/// @access private
417425
/// @param {Map} $schema - A theme schema.
418426
/// @param {Map} $palette - An igx-palette map.
427+
/// @requires {function} extend
419428
/// @requires {function} resolve-value
420429
/// @example scss Apply an `igx-palette` to theme schema
421430
/// $custom-palette: igx-palette($primary: red, $secondary: blue);
@@ -434,7 +443,7 @@
434443
@if type-of($value) == 'map' {
435444
$result: extend($result, (#{$key}: resolve-value($value, $palette)));
436445
} @else {
437-
$result: extend($result, (#{$key}: $value));
446+
$result: extend($result, (#{$key}: #{$value}));
438447
}
439448
}
440449
@return $result;

projects/igniteui-angular/src/lib/core/styles/components/grid-paginator/_grid-paginator-theme.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@
7373
z-index: 1;
7474
padding: map-get($paginator-padding, 'comfortable');
7575
height: map-get($paginator-height, 'comfortable');
76-
76+
width: 100%;
77+
7778
&:empty {
7879
padding: 0;
7980
}

0 commit comments

Comments
 (0)