Skip to content

Commit 3fb0f11

Browse files
ivanvpetrovgeorgianastasovkdinevteodosiahgedinakova
authored
[Query Builder] drag and drop refactor without DOM manipulations - master (#15536)
* fix(column): Update row island summaries when disabledSummaries changes * test(grid): fix failing test * Update codeql-analysis.yml * refactor(query-builder): drag and drop without DOM manipulations * fix(query-builder): test commit upon Enter --------- Co-authored-by: Georgi Anastasov <[email protected]> Co-authored-by: Konstantin Dinev <[email protected]> Co-authored-by: Georgi Anastasov <[email protected]> Co-authored-by: Teodosia Hristodorova <[email protected]> Co-authored-by: Galina Edinakova <[email protected]> Co-authored-by: Hristo Hristov <[email protected]> Co-authored-by: RivaIvanova <[email protected]> Co-authored-by: Marin Popov <[email protected]> Co-authored-by: Damyan Petev <[email protected]> Co-authored-by: Riva Ivanova <[email protected]> Co-authored-by: desig9stein <[email protected]> Co-authored-by: teodosiah <[email protected]> Co-authored-by: Vasya Kacheshmarova <[email protected]> Co-authored-by: Mariela Tihova <[email protected]>
1 parent bb82051 commit 3fb0f11

8 files changed

+528
-414
lines changed

Diff for: projects/igniteui-angular/src/lib/core/styles/components/query-builder/_query-builder-component.scss

+3-3
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@
107107
@extend %filter-tree__expression-item !optional;
108108
}
109109

110-
@include e(expression-item-ghost) {
110+
@include e(expression-item-drop-ghost) {
111111
@extend %filter-tree__expression-item-ghost !optional;
112112
}
113113

114-
@include e(expression-item-drop-ghost) {
115-
@extend %filter-tree__expression-drop-item-ghost !optional;
114+
@include e(expression-item-keyboard-ghost) {
115+
@extend %filter-tree__expression-item-keyboard-ghost !optional;
116116
}
117117

118118
@include e(expression-column) {

Diff for: projects/igniteui-angular/src/lib/core/styles/components/query-builder/_query-builder-theme.scss

+12-5
Original file line numberDiff line numberDiff line change
@@ -480,18 +480,25 @@
480480

481481

482482
%filter-tree__expression-item-ghost {
483-
&.igx-chip__item {
483+
.igx-chip__item {
484484
@include type-style('body-2');
485485

486486
--ig-body-2-text-transform: unset;
487487

488488
padding-inline: rem(32px);
489+
490+
color: color($color: 'gray', $variant: if($theme-variant == 'light', 600, 900));
491+
border: rem(1px) dashed color($color: 'gray', $variant: if($theme-variant == 'light', 600, 300));
492+
background: transparent;
489493
}
490-
491-
color: color($color: 'gray', $variant: if($theme-variant == 'light', 600, 900));
492-
border: rem(1px) dashed color($color: 'gray', $variant: if($theme-variant == 'light', 600, 300));
493-
background: transparent;
494494
}
495+
496+
%filter-tree__expression-item-keyboard-ghost {
497+
.igx-chip__item {
498+
box-shadow: var(--ghost-shadow);
499+
background: var(--ghost-background);
500+
}
501+
}
495502

496503
%filter-tree__expression-column {
497504
padding: 0 rem(8px);

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

+267-327
Large diffs are not rendered by default.

Diff for: projects/igniteui-angular/src/lib/query-builder/query-builder-functions.spec.ts

+26-2
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ export class QueryBuilderFunctions {
865865
}
866866

867867
public static getChipContent(chip: Element): string {
868-
if (chip.checkVisibility()) {
868+
if (chip && chip.checkVisibility()) {
869869
let text: string = '';
870870

871871
Array.from(chip.querySelectorAll('span')).forEach(element => {
@@ -883,7 +883,8 @@ export class QueryBuilderFunctions {
883883

884884
public static getDropGhost(fixture: ComponentFixture<any>): Element {
885885
var expressionsContainer = QueryBuilderFunctions.getQueryBuilderExpressionsContainer(fixture);
886-
return expressionsContainer.querySelector(`div.${QueryBuilderSelectors.FILTER_TREE_EXPRESSION_ITEM_DROP_GHOST}`);
886+
return expressionsContainer.querySelector(`div.${QueryBuilderSelectors.FILTER_TREE_EXPRESSION_ITEM_DROP_GHOST}`) ??
887+
expressionsContainer.querySelector(`div.${QueryBuilderSelectors.FILTER_TREE_EXPRESSION_ITEM_KEYBOARD_GHOST}`);
887888
}
888889

889890
public static getDropGhostBounds(fixture: ComponentFixture<any>): DOMRect {
@@ -910,4 +911,27 @@ export class QueryBuilderFunctions {
910911
dragDirective.onPointerUp({ pointerId: 1, pageX: X, pageY: Y });
911912
}
912913
}
914+
915+
public static getDropGhostAndItsSiblings(fixture: ComponentFixture<any>): [Element, string, string, string[]] {
916+
const dropGhost = this.getDropGhost(fixture);
917+
const newChipContents = QueryBuilderFunctions.GetChipsContentAsArray(fixture);
918+
let prevElement: string, nextElement: string;
919+
920+
if (dropGhost) {
921+
if (dropGhost.previousElementSibling?.className &&
922+
dropGhost.previousElementSibling?.className?.indexOf(QueryBuilderSelectors.FILTER_TREE_SUBQUERY) !== -1) {
923+
prevElement = QueryBuilderFunctions.getChipContent(dropGhost.previousElementSibling.previousElementSibling);
924+
} else if (dropGhost.previousElementSibling?.previousElementSibling) {
925+
prevElement = QueryBuilderFunctions.getChipContent(dropGhost.previousElementSibling);
926+
}
927+
928+
nextElement = QueryBuilderFunctions.getChipContent(dropGhost.nextElementSibling?.nextElementSibling);
929+
nextElement ??= QueryBuilderFunctions.getChipContent(dropGhost.nextElementSibling?.nextElementSibling?.nextElementSibling?.nextElementSibling);
930+
}
931+
932+
prevElement ??= null;
933+
nextElement ??= null;
934+
935+
return [dropGhost, prevElement, nextElement, newChipContents];
936+
}
913937
}

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

+12-1
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,24 @@
125125

126126
<ng-template #operandTemplate let-expressionItem>
127127
@if (!expressionItem.inEditMode) {
128+
@if(dragService.dropGhostExpression && expressionItem === dragService.dropGhostExpression && dragService.isKeyboardDrag === false){
129+
<div class="igx-filter-tree__expression-item igx-filter-tree__expression-item-drop-ghost">
130+
<igx-chip [data]="expressionItem">
131+
{{this.resourceStrings.igx_query_builder_drop_ghost_text}}
132+
</igx-chip>
133+
</div>
134+
} @else {
128135
<div
129136
#dragRef
130137
igxDrop
131138
(enter)="dragService.onChipEnter(dragRef, expressionItem)"
132139
(over)="dragService.onDivOver(dragRef, expressionItem)"
133140
(leave)="dragService.onChipLeave()"
134141
(dropped)="dragService.onDivDropped(expressionItem)"
135-
class="igx-filter-tree__expression-item"
142+
[ngClass]="{
143+
'igx-filter-tree__expression-item': true,
144+
'igx-filter-tree__expression-item-keyboard-ghost': expressionItem === dragService.dropGhostExpression
145+
}"
136146
(mouseenter)="expressionItem.hovered = true"
137147
(mouseleave)="expressionItem.hovered = false"
138148
(focusin)="onExpressionFocus(expressionItem)"
@@ -263,6 +273,7 @@
263273
}
264274
</div>
265275
}
276+
}
266277
<div #editingInputsContainer class="igx-filter-tree__subquery" >
267278
@if (expressionItem.inEditMode) {
268279
<div

Diff for: projects/igniteui-angular/src/lib/query-builder/query-builder-tree.component.ts

+21-10
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,19 @@ const DEFAULT_CHIP_FOCUS_DELAY = 50;
102102
],
103103
providers: [
104104
IgxQueryBuilderDragService
105-
]
105+
],
106106
})
107107
export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
108+
/**
109+
* @hidden @internal
110+
*/
111+
public _expressionTree: IExpressionTree;
112+
113+
/**
114+
* @hidden @internal
115+
*/
116+
public _expressionTreeCopy: IExpressionTree;
117+
108118
/**
109119
* @hidden @internal
110120
*/
@@ -288,8 +298,11 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
288298
@ViewChild('groupContextMenuDropDown', { read: IgxDropDownComponent })
289299
private groupContextMenuDropDown: IgxDropDownComponent;
290300

301+
/**
302+
* @hidden @internal
303+
*/
291304
@ViewChildren(IgxChipComponent, { read: IgxChipComponent })
292-
private expressionsChips: QueryList<IgxChipComponent>;
305+
public expressionsChips: QueryList<IgxChipComponent>;
293306

294307
@ViewChild('editingInputsContainer', { read: ElementRef })
295308
protected set editingInputsContainer(value: ElementRef) {
@@ -459,7 +472,6 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
459472
private _prevFocusedContainer: ElementRef;
460473
private _expandedExpressions: IFilteringExpression[] = [];
461474
private _fields: FieldType[];
462-
private _expressionTree: IExpressionTree;
463475
private _locale;
464476
private _entityNewValue: EntityType;
465477
private _resourceStrings = getCurrentResourceStrings(QueryBuilderResourceStringsEN);
@@ -475,7 +487,7 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
475487
/**
476488
* Returns if the fields combo at the root level is disabled.
477489
*/
478-
public get disableReturnFieldsChange(): boolean {
490+
public get disableReturnFieldsChange(): boolean {
479491

480492
return !this.selectedEntity || this.queryBuilder.disableReturnFieldsChange;
481493
}
@@ -1039,7 +1051,6 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
10391051
this._lastFocusedChipIndex = index;
10401052
this.focusEditedExpressionChip();
10411053
}
1042-
10431054
/**
10441055
* @hidden @internal
10451056
*/
@@ -1141,8 +1152,8 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
11411152
expressionItem.expression.condition.name :
11421153
null;
11431154
this.searchValue.value = expressionItem.expression.searchVal instanceof Set ?
1144-
Array.from(expressionItem.expression.searchVal) :
1145-
expressionItem.expression.searchVal;
1155+
Array.from(expressionItem.expression.searchVal) :
1156+
expressionItem.expression.searchVal;
11461157

11471158
expressionItem.inEditMode = true;
11481159
this._editedExpression = expressionItem;
@@ -1177,7 +1188,7 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
11771188
input?.focus();
11781189
}
11791190

1180-
(this.editingInputs?.nativeElement.parentElement as HTMLElement)?.scrollIntoView({block: "nearest", inline: "nearest"});
1191+
(this.editingInputs?.nativeElement.parentElement as HTMLElement)?.scrollIntoView({ block: "nearest", inline: "nearest" });
11811192
}
11821193

11831194
/**
@@ -1317,7 +1328,7 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
13171328
* @hidden @internal
13181329
*/
13191330
public invokeClick(eventArgs: KeyboardEvent) {
1320-
if (!this.dragService.dropGhostChipNode && this.platform.isActivationKey(eventArgs)) {
1331+
if (!this.dragService.dropGhostExpression && this.platform.isActivationKey(eventArgs)) {
13211332
eventArgs.preventDefault();
13221333
(eventArgs.currentTarget as HTMLElement).click();
13231334
}
@@ -1549,7 +1560,7 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
15491560
return groupItem;
15501561
}
15511562

1552-
for (let i = 0 ; i < expressionTree.filteringOperands.length; i++) {
1563+
for (let i = 0; i < expressionTree.filteringOperands.length; i++) {
15531564
const expr = expressionTree.filteringOperands[i];
15541565

15551566
if (isTree(expr)) {

Diff for: projects/igniteui-angular/src/lib/query-builder/query-builder.common.ts

+1-6
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export const QueryBuilderSelectors = {
6969
FILTER_TREE_EXPRESSION_CONTEXT_MENU: IGX_FILTER_TREE + '__expression-context-menu',
7070
FILTER_TREE_EXPRESSION_ITEM: IGX_FILTER_TREE + '__expression-item',
7171
FILTER_TREE_EXPRESSION_ITEM_DROP_GHOST: IGX_FILTER_TREE + '__expression-item-drop-ghost',
72+
FILTER_TREE_EXPRESSION_ITEM_KEYBOARD_GHOST: IGX_FILTER_TREE + '__expression-item-keyboard-ghost',
7273
FILTER_TREE_EXPRESSION_ITEM_GHOST: IGX_FILTER_TREE + '__expression-item-ghost',
7374
FILTER_TREE_EXPRESSION_SECTION: IGX_FILTER_TREE + '__expression-section',
7475

@@ -80,10 +81,4 @@ export const QueryBuilderSelectors = {
8081
QUERY_BUILDER_BODY: IGX_QUERY_BUILDER + '__main',
8182
QUERY_BUILDER_HEADER: IGX_QUERY_BUILDER + '__header',
8283
QUERY_BUILDER_TREE: IGX_QUERY_BUILDER + '-tree',
83-
84-
VIABLE_DROP_AREA:
85-
`.${IGX_FILTER_TREE}__expression-item[igxDrop]:not(.${IGX_FILTER_TREE + '__expression-item-drop-ghost'}),` + /*Condition chip*/
86-
`.${IGX_FILTER_TREE}__subquery:has([igxDrop]),` + /*Chip in edit*/
87-
`.${IGX_FILTER_TREE}__buttons > .igx-button[igxDrop]:first-of-type,` + /*Add Condition Button*/
88-
`.${IGX_FILTER_TREE}__expression-context-menu[igxDrop]` /*AND/OR group root*/
8984
}

0 commit comments

Comments
 (0)