Skip to content

Commit 7cedbd8

Browse files
authored
Merge branch 'master' into mdragnev/fix-5640-master
2 parents b09ec88 + 38a4fd4 commit 7cedbd8

File tree

8 files changed

+247
-37
lines changed

8 files changed

+247
-37
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ All notable changes for each version of this project will be documented in this
5050
- `IgxToast`:
5151
- Added functionality for displaying various content into the toast component. It also allows users to access toast styles through its host element.
5252

53+
- `IgxDrag`
54+
- New `igxDragIgnore` directive that allows children of the `igxDrag` element to be interactable and receive mouse events. Dragging cannot be performed from those elements that are ignored.
55+
- New `dragDirection` input that can specify only one direction of dragging or both.
56+
5357
### RTL Support
5458
- `igxSlider` have full right-to-left (RTL) support.
5559

projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,13 @@
2020
} from '@angular/core';
2121
import { animationFrameScheduler, fromEvent, interval, Subject } from 'rxjs';
2222
import { takeUntil, throttle } from 'rxjs/operators';
23-
import { IgxDragHandleDirective } from './drag-handle.directive';
2423
import { IBaseEventArgs } from '../../core/utils';
2524
import { IDropStrategy, IgxDefaultDropStrategy } from './drag-drop.strategy';
2625

27-
export enum RestrictDrag {
28-
VERTICALLY,
29-
HORIZONTALLY,
30-
NONE
26+
export enum DragDirection {
27+
VERTICAL,
28+
HORIZONTAL,
29+
BOTH
3130
}
3231

3332
export interface IgxDragCustomEventDetails {
@@ -144,6 +143,28 @@ export class IgxDragLocation {
144143
}
145144
}
146145

146+
@Directive({
147+
selector: '[igxDragHandle]'
148+
})
149+
export class IgxDragHandleDirective {
150+
151+
@HostBinding('class.igx-drag__handle')
152+
public baseClass = true;
153+
154+
constructor(public element: ElementRef<any>) {}
155+
}
156+
157+
@Directive({
158+
selector: '[igxDragIgnore]'
159+
})
160+
export class IgxDragIgnoreDirective {
161+
162+
@HostBinding('class.igx-drag__ignore')
163+
public baseClass = true;
164+
165+
constructor(public element: ElementRef<any>) {}
166+
}
167+
147168
@Directive({
148169
exportAs: 'drag',
149170
selector: '[igxDrag]'
@@ -175,6 +196,22 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
175196
@Input()
176197
public dragTolerance = 5;
177198

199+
/**
200+
* An @Input property that indicates the directions that the element can be dragged.
201+
* By default it is set to both horizontal and vertical directions.
202+
* ```html
203+
* <div igxDrag [dragDirection]="dragDir">
204+
* <span>Drag Me!</span>
205+
* </div>
206+
* ```
207+
* ```typescript
208+
* public dragDir = DragDirection.HORIZONTAL;
209+
* ```
210+
* @memberof IgxDragDirective
211+
*/
212+
@Input()
213+
public dragDirection = DragDirection.BOTH;
214+
178215
/**
179216
* An @Input property that provide a way for igxDrag and igxDrop to be linked through channels.
180217
* It accepts single value or an array of values and evaluates then using strict equality.
@@ -415,6 +452,11 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
415452
@ContentChildren(IgxDragHandleDirective)
416453
public dragHandles: QueryList<IgxDragHandleDirective>;
417454

455+
/**
456+
* @hidden
457+
*/
458+
@ContentChildren(IgxDragIgnoreDirective)
459+
public dragIgnoredElems: QueryList<IgxDragIgnoreDirective>;
418460

419461
/**
420462
* @hidden
@@ -777,6 +819,11 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
777819
* @param event PointerDown event captured
778820
*/
779821
public onPointerDown(event) {
822+
const ignoredElement = this.dragIgnoredElems.find(elem => elem.element.nativeElement === event.target);
823+
if (ignoredElement) {
824+
return;
825+
}
826+
780827
this._clicked = true;
781828
this._pointerDownId = event.pointerId;
782829

@@ -882,16 +929,15 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
882929

883930
const setPageX = moveArgs.nextPageX;
884931
const setPageY = moveArgs.nextPageY;
885-
const updatedMovedX = setPageX - this._startX;
886-
const updatedMovedY = setPageY - this._startY;
887-
888932
if (!moveArgs.cancel) {
889933
if (this.ghost) {
890-
this.ghostLeft = this._ghostStartX + updatedMovedX;
891-
this.ghostTop = this._ghostStartY + updatedMovedY;
934+
const updatedTotalMovedX = this.dragDirection === DragDirection.VERTICAL ? 0 : setPageX - this._startX;
935+
const updatedTotalMovedY = this.dragDirection === DragDirection.HORIZONTAL ? 0 : setPageY - this._startY;
936+
this.ghostLeft = this._ghostStartX + updatedTotalMovedX;
937+
this.ghostTop = this._ghostStartY + updatedTotalMovedY;
892938
} else {
893-
const lastMovedX = setPageX - this._lastX;
894-
const lastMovedY = setPageY - this._lastY;
939+
const lastMovedX = this.dragDirection === DragDirection.VERTICAL ? 0 : setPageX - this._lastX;
940+
const lastMovedY = this.dragDirection === DragDirection.HORIZONTAL ? 0 : setPageY - this._lastY;
895941
const translateX = this.getTransformX(this.element.nativeElement) + lastMovedX;
896942
const translateY = this.getTransformY(this.element.nativeElement) + lastMovedY;
897943
this.setTransformXY(translateX, translateY);
@@ -1641,7 +1687,7 @@ export class IgxDropDirective implements OnInit, OnDestroy {
16411687
* @hidden
16421688
*/
16431689
@NgModule({
1644-
declarations: [IgxDragDirective, IgxDropDirective, IgxDragHandleDirective],
1645-
exports: [IgxDragDirective, IgxDropDirective, IgxDragHandleDirective]
1690+
declarations: [IgxDragDirective, IgxDropDirective, IgxDragHandleDirective, IgxDragIgnoreDirective],
1691+
exports: [IgxDragDirective, IgxDropDirective, IgxDragHandleDirective, IgxDragIgnoreDirective]
16461692
})
16471693
export class IgxDragDropModule { }

projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.spec.ts

Lines changed: 161 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import { Component, ViewChildren, QueryList, ViewChild, ElementRef, TemplateRef, Renderer2 } from '@angular/core';
22
import { async, TestBed, ComponentFixture } from '@angular/core/testing';
3+
import { By } from '@angular/platform-browser';
34
import { FormsModule } from '@angular/forms';
4-
import { IgxDragDropModule, IgxDragDirective, IgxDropDirective, IgxDragLocation, IDropDroppedEventArgs } from './drag-drop.directive';
55
import { UIInteractions, wait} from '../../test-utils/ui-interactions.spec';
66
import { configureTestSuite } from '../../test-utils/configure-suite';
7-
import { IgxInsertDropStrategy, IgxAppendDropStrategy, IgxPrependDropStrategy } from './drag-drop.strategy';
87
import { first } from 'rxjs/operators';
8+
import { IgxInsertDropStrategy, IgxAppendDropStrategy, IgxPrependDropStrategy } from './drag-drop.strategy';
9+
import {
10+
IgxDragDropModule,
11+
IgxDragDirective,
12+
IgxDropDirective,
13+
IgxDragLocation,
14+
IDropDroppedEventArgs,
15+
DragDirection
16+
} from './drag-drop.directive';
917

1018
describe('General igxDrag/igxDrop', () => {
1119
let fix: ComponentFixture<TestDragDropComponent>;
@@ -37,10 +45,14 @@ describe('General igxDrag/igxDrop', () => {
3745
});
3846

3947
it('should correctly initialize drag and drop directives.', () => {
48+
const ignoredElem = fix.debugElement.query(By.css('.ignoredElem')).nativeElement;
49+
4050
expect(fix.componentInstance.dragElems.length).toEqual(3);
4151
expect(fix.componentInstance.dragElems.last.data).toEqual({ key: 3 });
4252
expect(fix.componentInstance.dropArea).toBeTruthy();
4353
expect(fix.componentInstance.dropArea.data).toEqual({ key: 333 });
54+
expect(fix.componentInstance.dragElems.last.dragIgnoredElems.length).toEqual(1);
55+
expect(fix.componentInstance.dragElems.last.dragIgnoredElems.first.element.nativeElement).toEqual(ignoredElem);
4456
});
4557

4658
it('should create drag ghost element and trigger ghostCreate/ghostDestroy.', (async() => {
@@ -257,6 +269,70 @@ describe('General igxDrag/igxDrop', () => {
257269
await wait();
258270
}));
259271

272+
it('should move ghost only horizontally when drag direction is set to horizontal.', (async() => {
273+
const firstDrag = fix.componentInstance.dragElems.first;
274+
const firstElement = firstDrag.element.nativeElement;
275+
const startingX = (dragDirsRects[0].left + dragDirsRects[0].right) / 2;
276+
const startingY = (dragDirsRects[0].top + dragDirsRects[0].bottom) / 2;
277+
firstDrag.dragDirection = DragDirection.HORIZONTAL;
278+
279+
// Step 1.
280+
UIInteractions.simulatePointerEvent('pointerdown', firstElement, startingX, startingY);
281+
fix.detectChanges();
282+
await wait();
283+
284+
// Step 2.
285+
UIInteractions.simulatePointerEvent('pointermove', firstElement, startingX + 10, startingY + 10);
286+
fix.detectChanges();
287+
await wait(100);
288+
289+
// Step 3.
290+
UIInteractions.simulatePointerEvent('pointermove', firstDrag.ghostElement, startingX + 20, startingY + 20);
291+
fix.detectChanges();
292+
await wait(100);
293+
294+
// We compare the base position and the new position + how much the mouse has moved.
295+
expect(firstDrag.ghostElement.getBoundingClientRect().left).toEqual(dragDirsRects[0].left + 20);
296+
expect(firstDrag.ghostElement.getBoundingClientRect().top).toEqual(dragDirsRects[0].top);
297+
298+
// Step 4.
299+
UIInteractions.simulatePointerEvent('pointerup', firstDrag.ghostElement, startingX + 20, startingY + 20);
300+
fix.detectChanges();
301+
await wait();
302+
}));
303+
304+
it('should move ghost only vertically when drag direction is set to vertical.', (async() => {
305+
const firstDrag = fix.componentInstance.dragElems.first;
306+
const firstElement = firstDrag.element.nativeElement;
307+
const startingX = (dragDirsRects[0].left + dragDirsRects[0].right) / 2;
308+
const startingY = (dragDirsRects[0].top + dragDirsRects[0].bottom) / 2;
309+
firstDrag.dragDirection = DragDirection.VERTICAL;
310+
311+
// Step 1.
312+
UIInteractions.simulatePointerEvent('pointerdown', firstElement, startingX, startingY);
313+
fix.detectChanges();
314+
await wait();
315+
316+
// Step 2.
317+
UIInteractions.simulatePointerEvent('pointermove', firstElement, startingX + 10, startingY + 10);
318+
fix.detectChanges();
319+
await wait(100);
320+
321+
// Step 3.
322+
UIInteractions.simulatePointerEvent('pointermove', firstDrag.ghostElement, startingX + 20, startingY + 20);
323+
fix.detectChanges();
324+
await wait(100);
325+
326+
// We compare the base position and the new position + how much the mouse has moved.
327+
expect(firstDrag.ghostElement.getBoundingClientRect().left).toEqual(dragDirsRects[0].left);
328+
expect(firstDrag.ghostElement.getBoundingClientRect().top).toEqual(dragDirsRects[0].top + 20);
329+
330+
// Step 4.
331+
UIInteractions.simulatePointerEvent('pointerup', firstDrag.ghostElement, startingX + 20, startingY + 20);
332+
fix.detectChanges();
333+
await wait();
334+
}));
335+
260336
it('should position ghost relative to the mouse using offsetX and offsetY correctly.', (async() => {
261337
const firstDrag = fix.componentInstance.dragElems.first;
262338
const firstElement = firstDrag.element.nativeElement;
@@ -449,6 +525,88 @@ describe('General igxDrag/igxDrop', () => {
449525
expect(firstDrag.dragEnd.emit).toHaveBeenCalled();
450526
}));
451527

528+
it('should move igxDrag element only horizontally when ghost is disabled and direction is set to horizontal.', (async() => {
529+
const firstDrag = fix.componentInstance.dragElems.first;
530+
const firstElement = firstDrag.element.nativeElement;
531+
const startingX = (dragDirsRects[0].left + dragDirsRects[0].right) / 2;
532+
const startingY = (dragDirsRects[0].top + dragDirsRects[0].bottom) / 2;
533+
firstDrag.ghost = false;
534+
firstDrag.dragDirection = DragDirection.HORIZONTAL;
535+
fix.detectChanges();
536+
537+
// Step 1.
538+
UIInteractions.simulatePointerEvent('pointerdown', firstElement, startingX, startingY);
539+
fix.detectChanges();
540+
await wait();
541+
542+
// Step 2.
543+
UIInteractions.simulatePointerEvent('pointermove', firstElement, startingX + 10, startingY + 10);
544+
fix.detectChanges();
545+
await wait(100);
546+
547+
expect(firstDrag.ghostElement).not.toBeDefined();
548+
expect(firstElement.getBoundingClientRect().left).toEqual(dragDirsRects[0].left + 10);
549+
expect(firstElement.getBoundingClientRect().top).toEqual(dragDirsRects[0].top);
550+
551+
// Step 3.
552+
UIInteractions.simulatePointerEvent('pointermove', firstElement, startingX + 20, startingY + 20);
553+
fix.detectChanges();
554+
await wait(100);
555+
556+
expect(firstDrag.ghostElement).not.toBeDefined();
557+
expect(firstElement.getBoundingClientRect().left).toEqual(dragDirsRects[0].left + 20);
558+
expect(firstElement.getBoundingClientRect().top).toEqual(dragDirsRects[0].top);
559+
560+
// Step 4.
561+
UIInteractions.simulatePointerEvent('pointerup', firstElement, startingX + 20, startingY + 20);
562+
fix.detectChanges();
563+
await wait();
564+
565+
expect(firstElement.getBoundingClientRect().left).toEqual(dragDirsRects[0].left + 20);
566+
expect(firstElement.getBoundingClientRect().top).toEqual(dragDirsRects[0].top);
567+
}));
568+
569+
it('should move igxDrag element only vertically when ghost is disabled and direction is set to vertical.', (async() => {
570+
const firstDrag = fix.componentInstance.dragElems.first;
571+
const firstElement = firstDrag.element.nativeElement;
572+
const startingX = (dragDirsRects[0].left + dragDirsRects[0].right) / 2;
573+
const startingY = (dragDirsRects[0].top + dragDirsRects[0].bottom) / 2;
574+
firstDrag.ghost = false;
575+
firstDrag.dragDirection = DragDirection.VERTICAL;
576+
fix.detectChanges();
577+
578+
// Step 1.
579+
UIInteractions.simulatePointerEvent('pointerdown', firstElement, startingX, startingY);
580+
fix.detectChanges();
581+
await wait();
582+
583+
// Step 2.
584+
UIInteractions.simulatePointerEvent('pointermove', firstElement, startingX + 10, startingY + 10);
585+
fix.detectChanges();
586+
await wait(100);
587+
588+
expect(firstDrag.ghostElement).not.toBeDefined();
589+
expect(firstElement.getBoundingClientRect().left).toEqual(dragDirsRects[0].left);
590+
expect(firstElement.getBoundingClientRect().top).toEqual(dragDirsRects[0].top + 10);
591+
592+
// Step 3.
593+
UIInteractions.simulatePointerEvent('pointermove', firstElement, startingX + 20, startingY + 20);
594+
fix.detectChanges();
595+
await wait(100);
596+
597+
expect(firstDrag.ghostElement).not.toBeDefined();
598+
expect(firstElement.getBoundingClientRect().left).toEqual(dragDirsRects[0].left);
599+
expect(firstElement.getBoundingClientRect().top).toEqual(dragDirsRects[0].top + 20);
600+
601+
// Step 4.
602+
UIInteractions.simulatePointerEvent('pointerup', firstElement, startingX + 20, startingY + 20);
603+
fix.detectChanges();
604+
await wait();
605+
606+
expect(firstElement.getBoundingClientRect().left).toEqual(dragDirsRects[0].left);
607+
expect(firstElement.getBoundingClientRect().top).toEqual(dragDirsRects[0].top + 20);
608+
}));
609+
452610
it('should prevent dragging if it does not exceed dragTolerance and ghost is disabled.', (async() => {
453611
const firstDrag = fix.componentInstance.dragElems.first;
454612
const firstElement = firstDrag.element.nativeElement;
@@ -1732,6 +1890,7 @@ const generalStyles = [`
17321890
<div id="thirdDrag" class="dragElem" [igxDrag]="{ key: 3 }">
17331891
Drag 3
17341892
<div igxDragHandle class="dragHandle"></div>
1893+
<div igxDragIgnore class="ignoredElem"></div>
17351894
</div>
17361895
<ng-template #ghostTemplate>
17371896
<div class="ghostElement">Drag Template</div>

projects/igniteui-angular/src/lib/directives/drag-drop/drag-handle.directive.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,9 +1443,9 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => {
14431443
expect(filteringRow.queryAll(By.css('igx-chip')).length).toEqual(2);
14441444
}));
14451445

1446-
it('Verify filter cell chip is scrolled into view on click.', fakeAsync(() => {
1446+
it('Verify filter cell chip is scrolled into view on click.', async () => {
14471447
grid.width = '470px';
1448-
tick(100);
1448+
await wait(DEBOUNCETIME);
14491449
fix.detectChanges();
14501450

14511451
// Verify 'ReleaseDate' filter chip is not fully visible.
@@ -1455,18 +1455,21 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => {
14551455
expect(chipRect.right > gridRect.right).toBe(true,
14561456
'chip should not be fully visible and thus not within grid');
14571457

1458-
GridFunctions.clickFilterCellChip(fix, 'ReleaseDate');
1458+
GridFunctions.clickFilterCellChipUI(fix, 'ReleaseDate');
1459+
await wait(DEBOUNCETIME);
1460+
fix.detectChanges();
14591461

1460-
GridFunctions.closeFilterRow(fix);
1461-
tick(100);
1462+
grid.filteringRow.close();
1463+
await wait();
1464+
fix.detectChanges();
14621465

14631466
// Verify 'ReleaseDate' filter chip is fully visible.
14641467
chip = GridFunctions.getFilterChipsForColumn('ReleaseDate', fix)[0].nativeElement;
14651468
chipRect = chip.getBoundingClientRect();
14661469
gridRect = grid.nativeElement.getBoundingClientRect();
14671470
expect(chipRect.left > gridRect.left && chipRect.right < gridRect.right).toBe(true,
14681471
'chip should be fully visible and within grid');
1469-
}));
1472+
});
14701473

14711474
it('Verify condition chips are scrolled into/(out of) view by using arrow buttons.', (async () => {
14721475
grid.width = '700px';

0 commit comments

Comments
 (0)