Skip to content

Commit 029aaeb

Browse files
committed
Merge branch 'dmdimitrov/query-builder-improvements' of https://github.com/IgniteUI/igniteui-angular into dmdimitrov/query-builder-improvements
2 parents 11d5d74 + 02bcf80 commit 029aaeb

File tree

3 files changed

+86
-69
lines changed

3 files changed

+86
-69
lines changed

projects/igniteui-angular/src/lib/query-builder/query-builder-drag.service.ts

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,11 @@ export class IgxQueryBuilderDragService {
7373

7474
//On entering a drop area of another chip
7575
public onDivEnter(targetDragElement: HTMLElement, targetExpressionItem: ExpressionItem) {
76-
this.onChipEnter(targetDragElement, targetExpressionItem, true)
76+
this.onChipEnter(targetDragElement, targetExpressionItem)
7777
}
7878

79-
//TODO remove fromDiv: boolean -> targetDragElement is always the div
80-
public onChipEnter(targetDragElement: HTMLElement, targetExpressionItem: ExpressionItem, fromDiv: boolean) {
81-
// console.log('Entering:', targetDragElement, targetExpressionItem, 'from div:', fromDiv);
79+
public onChipEnter(targetDragElement: HTMLElement, targetExpressionItem: ExpressionItem) {
80+
// console.log('Entering:', targetDragElement, targetExpressionItem);
8281
if (!this.sourceElement || !this.sourceExpressionItem) return;
8382

8483
//If entering the one that's been picked up
@@ -92,28 +91,27 @@ export class IgxQueryBuilderDragService {
9291
this.targetElement = targetDragElement;
9392
this.targetExpressionItem = targetExpressionItem;
9493

95-
//Determine the middle point of the chip. (fromDiv - get the div's chip)
96-
const appendUnder = fromDiv ? this.ghostInLowerPart(targetDragElement.children[0] as HTMLElement) : this.ghostInLowerPart(targetDragElement);
94+
//Determine the middle point of the chip.
95+
const appendUnder = this.ghostInLowerPart(targetDragElement);
9796

9897
this.renderDropGhostChip(targetDragElement, appendUnder);
9998
}
10099

101100
//On moving the dragged chip in a drop area
102101
public onDivOver(targetDragElement: HTMLElement, targetExpressionItem: ExpressionItem) {
103102
if (this.targetExpressionItem === targetExpressionItem) {
104-
this.onChipOver(targetDragElement, true)
103+
this.onChipOver(targetDragElement)
105104
} else {
106-
this.onChipEnter(targetDragElement, targetExpressionItem, true);
105+
this.onChipEnter(targetDragElement, targetExpressionItem);
107106
}
108107
}
109108

110-
//TODO remove fromDiv: boolean -> targetDragElement is always the div
111-
public onChipOver(targetDragElement: HTMLElement, fromDiv: boolean): void {
109+
public onChipOver(targetDragElement: HTMLElement): void {
112110
//console.log('Over:', targetDragElement, 'type: ', typeof event);
113111
if (!this.sourceElement || !this.sourceExpressionItem) return;
114112

115-
//Determine the middle point of the chip. (fromDiv - get the div's chip)
116-
const appendUnder = fromDiv ? this.ghostInLowerPart(targetDragElement.children[0] as HTMLElement) : this.ghostInLowerPart(targetDragElement);
113+
//Determine the middle point of the chip.
114+
const appendUnder = this.ghostInLowerPart(targetDragElement);
117115

118116
this.renderDropGhostChip(targetDragElement, appendUnder);
119117
}
@@ -183,13 +181,7 @@ export class IgxQueryBuilderDragService {
183181
if (lastElement == this.dropGhostChipNode) return;
184182

185183
//simulate entering in the lower part of the last chip/group
186-
this.onChipEnter(lastElement as HTMLElement,
187-
rootGroup.children[rootGroup.children.length - 1],
188-
false);
189-
}
190-
191-
public onAddConditionLeave() {
192-
this.onChipLeave();
184+
this.onChipEnter(lastElement as HTMLElement, rootGroup.children[rootGroup.children.length - 1]);
193185
}
194186

195187
public onChipDragIndicatorFocus(sourceDragElement: HTMLElement, sourceExpressionItem: ExpressionItem) {
@@ -239,7 +231,6 @@ export class IgxQueryBuilderDragService {
239231
}
240232

241233
//Create the drop ghost node based on the base chip that's been dragged
242-
//TODO refactor this using angular and css?
243234
private createDropGhost(keyboardMode?: boolean) {
244235
const dragCopy = this.sourceElement.cloneNode(true);
245236
(dragCopy as HTMLElement).classList.add(this._dropGhostClass);
@@ -306,17 +297,20 @@ export class IgxQueryBuilderDragService {
306297
}
307298

308299
//Execute the drop
309-
private moveDraggedChipToNewLocation(appendToExpressionItem: ExpressionItem, fromAddConditionBtn?: boolean) {
300+
private moveDraggedChipToNewLocation(appendToExpressionItem: ExpressionItem) {
310301
//Copy dragged chip
311302
const dragCopy = { ...this.sourceExpressionItem };
312303
dragCopy.parent = appendToExpressionItem.parent;
313304

314305
//Paste on new place
315306
const index = appendToExpressionItem.parent.children.indexOf(appendToExpressionItem);
316-
appendToExpressionItem.parent.children.splice(index + (fromAddConditionBtn || this.dropUnder ? 1 : 0), 0, dragCopy);
307+
appendToExpressionItem.parent.children.splice(index + (this.dropUnder ? 1 : 0), 0, dragCopy);
317308

318309
//Delete from old place
319310
this._queryBuilderTreeComponentDeleteItem(this.sourceExpressionItem);
311+
312+
// this._queryBuilderTreeComponent._lastFocusedChipIndex = index;
313+
// this._queryBuilderTreeComponent.focusEditedExpressionChip();
320314
}
321315

322316
//Reset Drag&Drop vars. Optionally the drag source vars too
@@ -507,7 +501,7 @@ export class IgxQueryBuilderDragService {
507501

508502
//Gets all chip elements owned by this tree (discard child trees), AND/OR group roots and '+condition' button, flatten out as a list of HTML elements
509503
private getListedDropZones(): HTMLElement[] {
510-
const viableDropAreaSelector = `.igx-filter-tree__expression-item[igxDrop]:not(.${this._dropGhostClass}),` + /*Condition chip*/ //TODO :not(.${this.dropGhostClass}) might be redundant now
504+
const viableDropAreaSelector = `.igx-filter-tree__expression-item[igxDrop]:not(.${this._dropGhostClass}),` + /*Condition chip*/
511505
`.igx-filter-tree__subquery:has([igxDrop]),` + /*Chip in edit*/
512506
`.igx-filter-tree__buttons > .igx-button[igxDrop]:first-of-type,` + /*Add Condition Button*/
513507
`.igx-filter-tree__expression-context-menu[igxDrop]`; /*AND/OR group root*/

projects/igniteui-angular/src/lib/query-builder/query-builder-tree.component.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
<div
124124
#dragRef
125125
igxDrop
126-
(enter)="dragService.onChipEnter(dragRef, expressionItem, true)"
126+
(enter)="dragService.onChipEnter(dragRef, expressionItem)"
127127
(over)="dragService.onDivOver(dragRef, expressionItem)"
128128
(leave)="dragService.onChipLeave()"
129129
(dropped)="dragService.onDivDropped(expressionItem)"
@@ -141,8 +141,8 @@
141141
[animateOnRelease] = "false"
142142
(moveStart)="canBeDragged() ? dragService.onMoveStart(dragRef, expressionItem, false): null"
143143
(moveEnd)="dragService.onMoveEnd()"
144-
(dragEnter)="dragService.onChipEnter(dragRef, expressionItem, false)"
145-
(dragOver)="dragService.onChipOver(dragRef, false)"
144+
(dragEnter)="dragService.onChipEnter(dragRef, expressionItem)"
145+
(dragOver)="dragService.onChipOver(dragRef)"
146146
(dragLeave)="dragService.onChipLeave()"
147147
(dragDrop)="dragService.onChipDropped()"
148148
#target="tooltipTarget"
@@ -257,7 +257,7 @@
257257
<div #editingInputsContainer class="igx-filter-tree__subquery" >
258258
<div
259259
igxDrop
260-
(enter)="dragService.onChipEnter(editingInputsContainer, expressionItem, true)"
260+
(enter)="dragService.onChipEnter(editingInputsContainer, expressionItem)"
261261
(over)="dragService.onDivOver(editingInputsContainer, expressionItem)"
262262
(leave)="dragService.onChipLeave()"
263263
(dropped)="dragService.onDivDropped(expressionItem)"

projects/igniteui-angular/src/lib/query-builder/query-builder.component.spec.ts

Lines changed: 65 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ describe('IgxQueryBuilder', () => {
142142
QueryBuilderFunctions.verifyQueryEditModeExpressionInputValues(fix, 'Orders', 'OrderId, OrderName, OrderDate, Delivered', '', '', '');
143143

144144
// Verify adding buttons are not displayed
145-
expect(QueryBuilderFunctions.getQueryBuilderTreeRootGroupButtonsContainer(fix, 0)).toBe(undefined);
145+
expect(QueryBuilderFunctions.getQueryBuilderTreeRootGroupButtonsContainer(fix, 0)).toBe(undefined);
146146
}));
147147

148148
it(`Should discard newly added group when clicking on the 'cancel' button of its initial condition.`, fakeAsync(() => {
@@ -231,7 +231,7 @@ describe('IgxQueryBuilder', () => {
231231
QueryBuilderFunctions.verifyEditModeExpressionInputValues(fix, '', '', '');
232232

233233
// Verify adding buttons are not displayed
234-
expect(QueryBuilderFunctions.getQueryBuilderTreeRootGroupButtonsContainer(fix, 0)).toBe(undefined);
234+
expect(QueryBuilderFunctions.getQueryBuilderTreeRootGroupButtonsContainer(fix, 0)).toBe(undefined);
235235

236236
// Populate edit inputs.
237237
QueryBuilderFunctions.selectColumnInEditModeExpression(fix, 1); // Select 'OrderName' column.
@@ -1021,7 +1021,7 @@ describe('IgxQueryBuilder', () => {
10211021
fix.detectChanges();
10221022

10231023
// Verify adding buttons are not displayed
1024-
expect(QueryBuilderFunctions.getQueryBuilderTreeRootGroupButtonsContainer(fix, 0)).toBe(undefined);
1024+
expect(QueryBuilderFunctions.getQueryBuilderTreeRootGroupButtonsContainer(fix, 0)).toBe(undefined);
10251025

10261026
// Exit edit mode
10271027
const closeButton = QueryBuilderFunctions.getQueryBuilderExpressionCloseButton(fix);
@@ -2433,7 +2433,6 @@ describe('IgxQueryBuilder', () => {
24332433
chipComponents = fix.debugElement.queryAll(By.directive(IgxChipComponent));
24342434
});
24352435

2436-
//OK
24372436
it('should render ghost when mouse drag operation starts.', () => {
24382437
const draggedChip = chipComponents[1].componentInstance;
24392438

@@ -2445,22 +2444,19 @@ describe('IgxQueryBuilder', () => {
24452444
expect(dropGhost.innerText).toBe(DROP_CONDITION_HERE);
24462445
});
24472446

2448-
//OK
24492447
it('should collapse the condition when mouse drag operation starts.', () => {
24502448
const secondChip = chipComponents[1].componentInstance;
24512449

24522450
UIInteractions.moveDragDirective(fix, secondChip.dragDirective, 100, 10, false);
24532451
expect(chipComponents[1].nativeElement.getBoundingClientRect().height).toBe(0);
24542452
});
24552453

2456-
//OK
24572454
it('should render drop ghost properly when mouse dragged.', async () => {
24582455
const draggedChip = chipComponents[1].componentInstance;
24592456
const draggedChipCenter = QueryBuilderFunctions.getElementCenter(draggedChip.chipArea.nativeElement);
24602457
const dragDir = draggedChip.dragDirective;
24612458

2462-
let X = 100, Y = 100, run = 0;
2463-
2459+
let X = 100, Y = 150;
24642460

24652461
//pickup chip
24662462
dragDir.onPointerDown({ pointerId: 1, pageX: draggedChipCenter.X, pageY: draggedChipCenter.Y });
@@ -2472,47 +2468,74 @@ describe('IgxQueryBuilder', () => {
24722468

24732469
spyOn(dragDir.ghostElement, 'dispatchEvent').and.callThrough();
24742470

2475-
for (let i = 0; i <= 30; i++) {
2476-
QueryBuilderFunctions.dragMove(dragDir, X, Y);
2471+
const ghostPositionVisits: boolean[] = [false, false, false, false, false, false, false, false]
2472+
2473+
let i = 0, pass = 1, inc = 1;
24772474

2478-
await wait(i < 24 ? 20 : 120); //wait a bit more when leaving the tree, for the RxJS listener to trigger
2475+
//Drag ghost up and down four times and check if drop ghost is rendered in the expected positions
2476+
while (pass <= 4) {
2477+
i += inc;
2478+
Y += 5 * inc;
2479+
2480+
QueryBuilderFunctions.dragMove(dragDir, X, Y);
2481+
await wait();
24792482
fix.detectChanges();
2480-
Y += 15;
2481-
const newChipContents = QueryBuilderFunctions.GetChipsContentAsArray(fix);
24822483

2483-
//When dragging over div, the mouse needs to be closer to the row, compared to when dragging over chip, that's why the '+run'
2484-
switch (true) {
2485-
case i < 5 + run:
2486-
expect(newChipContents).not.toContain(DROP_CONDITION_HERE);
2487-
break;
2488-
case i < 10 + run:
2489-
expect(newChipContents[0]).toBe(DROP_CONDITION_HERE);
2490-
break;
2491-
case i < 13 + run:
2492-
expect(newChipContents[1]).toBe(DROP_CONDITION_HERE);
2493-
break;
2494-
case i < 15 + run:
2495-
expect(newChipContents[4]).toBe(DROP_CONDITION_HERE);
2496-
break;
2497-
case i < 18 + run:
2498-
expect(newChipContents[5]).toBe(DROP_CONDITION_HERE);
2499-
break;
2500-
case i < 24 + run:
2501-
expect(newChipContents[6]).toBe(DROP_CONDITION_HERE);
2502-
break;
2503-
default:
2504-
expect(newChipContents).not.toContain(DROP_CONDITION_HERE);
2505-
break;
2484+
const dropGhost = QueryBuilderFunctions.getDropGhost(fix);
2485+
const prevElement = dropGhost && dropGhost.previousElementSibling ? QueryBuilderFunctions.getChipContent(dropGhost.previousElementSibling) : null;
2486+
const nextElement = dropGhost && dropGhost.nextElementSibling ? QueryBuilderFunctions.getChipContent(dropGhost.nextElementSibling) : null;
2487+
2488+
if (i < 8 && !ghostPositionVisits[0]) {
2489+
await wait(100);
2490+
if (!dropGhost) ghostPositionVisits[0] = true;
25062491
}
25072492

2508-
//When done moving mouse over chips, go to the left and test the chip row (blank space to the right) as well
2509-
if (i === 30 && run === 0) {
2510-
i = 0;
2511-
X += 500;
2512-
Y = 100;
2513-
run = 1;
2493+
if (i > 7 && i < 22 && !ghostPositionVisits[1]) {
2494+
if (dropGhost && !prevElement && nextElement == "OrderName Equals foo") ghostPositionVisits[1] = true;
2495+
}
2496+
2497+
if (i > 21 && i < 34 && !ghostPositionVisits[2]) {
2498+
if (dropGhost && prevElement == "OrderName Equals foo" && !nextElement) ghostPositionVisits[2] = true;
2499+
}
2500+
2501+
if (i > 33 && i < 38 && !ghostPositionVisits[3]) {
2502+
if (dropGhost && !prevElement && nextElement == "OrderName Ends With a") ghostPositionVisits[3] = true;
2503+
}
2504+
2505+
if (i > 37 && i < 46 && !ghostPositionVisits[4]) {
2506+
if (dropGhost && prevElement == "OrderName Ends With a" && !nextElement) ghostPositionVisits[4] = true;
2507+
}
2508+
2509+
if (i > 45 && i < 56 && !ghostPositionVisits[5]) {
2510+
if (dropGhost && prevElement == "OrderDate Today" && !nextElement) ghostPositionVisits[5] = true;
2511+
}
2512+
2513+
if (i > 55 && i < 63 && !ghostPositionVisits[6]) {
2514+
if (pass > 2 || (dropGhost && prevElement == "or OrderName Ends With a OrderDate Today" && !nextElement)) ghostPositionVisits[6] = true;
2515+
}
2516+
2517+
if (i > 63 && !ghostPositionVisits[7]) {
2518+
await wait(100);
2519+
if (!dropGhost) ghostPositionVisits[7] = true;
2520+
}
2521+
2522+
//When dragged to the end, check results and reverse direction for next pass
2523+
if (i === 65 || i === 0) {
2524+
expect(ghostPositionVisits).not.toContain(false,
2525+
`Ghost was not rendered on position(s) ${ghostPositionVisits.reduce((arr, e, ix) => ((e == false) && arr.push(ix), arr), []).toString()
2526+
} on pass:${pass}`);
2527+
2528+
ghostPositionVisits.fill(false);
2529+
pass++;
2530+
inc *= -1;
2531+
if (pass % 2 === 0) Y -= ROW_HEIGHT;
2532+
if (pass % 2 !== 0) Y += ROW_HEIGHT;
2533+
2534+
//go to the left and test the whole chip div as well(blank space to the right)
2535+
if (pass == 3) X += 400;
25142536
}
25152537
}
2538+
25162539
});
25172540

25182541
it('should position drop ghost below the target condition on dragging down.', () => {

0 commit comments

Comments
 (0)