Skip to content
This repository has been archived by the owner on Dec 8, 2022. It is now read-only.

Properly disable dragging on and left of a locked column #72

Merged
merged 6 commits into from
Sep 26, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions src/app/public/modules/grid/grid-adapter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,50 @@ export class SkyGridAdapterService {

dragulaService.setOptions('sky-grid-heading', {
moves: (el: HTMLElement, container: HTMLElement, handle: HTMLElement) => {
return !el.querySelector(GRID_HEADER_LOCKED_SELECTOR) &&
handle !== undefined &&
!handle.matches(GRID_HEADER_RESIZE_HANDLE);
const columns = container.querySelectorAll('th div');
const isLeftOfLocked = this.isLeftOfLocked(handle, columns);

return !el.querySelector(GRID_HEADER_LOCKED_SELECTOR)
&& handle !== undefined
&& !handle.matches(GRID_HEADER_RESIZE_HANDLE)
&& !isLeftOfLocked;
},
accepts: (
el: HTMLElement,
target: HTMLElement,
source: HTMLElement,
sibling: HTMLElement) => {
return sibling === undefined
|| !sibling
|| (!sibling.matches(GRID_HEADER_LOCKED_SELECTOR) && !sibling.matches(GRID_HEADER_RESIZE_HANDLE));

if (sibling === undefined || !sibling) {
return true;
}

const columns = source.querySelectorAll('th div');
const siblingDiv = sibling.querySelector('div');
const isLeftOfLocked = this.isLeftOfLocked(siblingDiv, columns);

return ((!sibling.matches(GRID_HEADER_LOCKED_SELECTOR)
&& !sibling.matches(GRID_HEADER_RESIZE_HANDLE)))
&& !isLeftOfLocked;
}
});
}

public setStyle(el: ElementRef, style: string, value: string): void {
this.renderer.setStyle(el.nativeElement, style, value);
}

private isLeftOfLocked(sourceColumn: HTMLElement, columns: NodeListOf<Element>) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs return type :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (let i = (columns.length - 1); i >= 0; i--) {
if (columns[i].classList.contains('sky-grid-header-locked')) {
return true;
}

if (columns[i] === sourceColumn) {
break;
}
}

return false;
}
}
191 changes: 147 additions & 44 deletions src/app/public/modules/grid/grid.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1613,79 +1613,182 @@ describe('Grid Component', () => {
);

it('should set dragula options for locked and resizable columns', () => {
const setOptionsSpy = spyOn(mockDragulaService, 'setOptions').and
.callFake((bagId: any, options: any) => {
const moveOptionValid = options.moves(
{
querySelector(selector: string): Node {
return undefined;
}
},
undefined,
const standardHandleElement: any = {
classList: {
contains(classSelector: string) {
return false;
}
},
matches(selector: string) {
return (selector === '.sky-grid-header');
},
querySelector(selector: string): any {
return undefined;
}
};

const lockedHandleElement: any = {
classList: {
contains(classSelector: string) {
return false;
}
},
matches(selector: string) {
return (selector === '.sky-grid-header-locked');
},
querySelector(selector: string): any {
return undefined;
}
};

const resizeHandleElement: any = {
classList: {
contains(classSelector: string) {
return false;
}
},
matches(selector: string) {
return (selector === '.sky-grid-resize-handle');
},
querySelector(selector: string): any {
return undefined;
}
};

const standardMockElement: any = {
querySelector(selector: string): any {
return undefined;
},
querySelectorAll(selector: string) {
return [
standardHandleElement
];
}
};

const lockedColumnMockElement: any = {
querySelector(selector: string): any {
// NOTE: We need an element to return here but the fixture isn't yet rendered due
// to the timing we need so the doucment element is enough to suffice what we are
// testing here.
return document;
},
querySelectorAll(selector: string) {
return [
standardHandleElement
];
}
};

const lockedSiblingMockElement: any = {
querySelector(selector: string): any {
return undefined;
},
querySelectorAll(selector: string) {
return [
{
matches(selector: string) {
return (selector === '.sky-grid-header');
classList: {
contains(classSelector: string) {
return true;
}
}
}
];
}
};

const setOptionsSpy = spyOn(mockDragulaService, 'setOptions').and
.callFake((bagId: any, options: any) => {
const moveOptionValid = options.moves(
standardMockElement,
standardMockElement,
standardHandleElement
);

const moveOptionLeftOfLocked = options.moves(
standardMockElement,
lockedSiblingMockElement,
standardHandleElement
);

const moveOptionLockedHeader = options.moves(
{
querySelector(selector: string): Node {
// NOTE: We need an element to return here but the fixture isn't yet rendered due
// to the timing we need so the doucment element is enough to suffice what we are
// testing here.
return document;
}
},
undefined,
{
matches(selector: string) {
return (selector === '.sky-grid-header');
}
}
lockedColumnMockElement,
standardMockElement,
standardHandleElement
);

const moveOptionFromResize = options.moves(
{
querySelector(selector: string): Node {
return undefined;
}
},
undefined,
{
matches(selector: string) {
return (selector === '.sky-grid-resize-handle');
}
}
standardMockElement,
standardMockElement,
resizeHandleElement
);

const moveOptionUndefinedHandle = options.moves(
{
querySelector(selector: string): Node {
return undefined;
}
},
undefined,
standardMockElement,
standardMockElement,
undefined
);

const acceptsOption = options.accepts(
undefined,
undefined,
standardMockElement,
standardHandleElement
);

const acceptsOptionLoopBreak = options.accepts(
undefined,
undefined,
standardMockElement,
{
querySelector(selector: string) {
return standardHandleElement;
},
matches(selector: string) {
return (selector === '.sky-grid-header-locked');
return false;
}
}
);

const acceptsOptionUndefinedSibiling = options.accepts(
undefined,
undefined,
standardMockElement,
undefined
);

const acceptsOptionLockedHandle = options.accepts(
undefined,
undefined,
standardMockElement,
lockedHandleElement
);

const acceptsOptionResizeHandle = options.accepts(
undefined,
undefined,
standardMockElement,
resizeHandleElement
);

const acceptsOptionLeftOfLocked = options.accepts(
undefined,
undefined,
lockedSiblingMockElement,
standardHandleElement
);

expect(moveOptionValid).toBeTruthy();
expect(moveOptionLockedHeader).toBeFalsy();
expect(moveOptionLeftOfLocked).toBeFalsy();
expect(moveOptionFromResize).toBeFalsy();
expect(moveOptionUndefinedHandle).toBeFalsy();
expect(acceptsOption).toBeFalsy();
expect(acceptsOption).toBeTruthy();
expect(acceptsOptionLoopBreak).toBeTruthy();
expect(acceptsOptionUndefinedSibiling).toBeTruthy();
expect(acceptsOptionLockedHandle).toBeFalsy();
expect(acceptsOptionResizeHandle).toBeFalsy();
expect(acceptsOptionLeftOfLocked).toBeFalsy();
});

fixture.detectChanges();
Expand Down