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

Changes related to iteration support #8

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
22 changes: 21 additions & 1 deletion src/app/public/modules/flyout/flyout.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
(mousedown)="onMouseDown($event)" />

<div class="sky-flyout-header sky-padding-squish-large" #flyoutHeader>
<div class="sky-flyout-header-content"></div>
<div class="sky-flyout-header-content">
<ng-container *ngTemplateOutlet="iteratorTemplate">
</ng-container>
</div>
<div class="sky-flyout-header-buttons">
<ng-container *ngTemplateOutlet="permalinkTemplate">
</ng-container>
Expand Down Expand Up @@ -83,3 +86,20 @@
</button>
</ng-template>
</ng-template>

<ng-template class="" #iteratorTemplate>
<ng-template [ngIf]="iteratorDetail">
<button
(click)="invokeIterator(true)"
class="sky-btn sky-btn-default sky-flyout-btn-iterator"
[disabled]="iteratorDetail.previousIteratorIsDisabled">
<span class="ng-scope fa fa-chevron-up"></span>
</button>
<button
(click)="invokeIterator(false)"
class="sky-btn sky-btn-default sky-flyout-btn-iterator"
[disabled]="iteratorDetail.nextIteratorIsDisabled">
<span class="ng-scope fa fa-chevron-down"></span>
</button>
</ng-template>
</ng-template>
216 changes: 145 additions & 71 deletions src/app/public/modules/flyout/flyout.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
} from '@skyux-sdk/testing';

import {
SkyFlyoutConfig
SkyFlyoutConfig,
SkyFlyoutIterator
} from './types';

import {
Expand Down Expand Up @@ -81,13 +82,13 @@ describe('Flyout component', () => {

function makeEvent(eventType: string, evtObj: any) {
let evt = document.createEvent('MouseEvents');
evt.initMouseEvent(eventType, false, false, window, 0, 0, 0, evtObj.clientX,
0, false, false, false, false, 0, undefined);
evt.initMouseEvent(eventType, false, false, window, 0, 0, 0, evtObj.clientX,
0, false, false, false, false, 0, undefined);
document.dispatchEvent(evt);
}

function getFlyoutElement(): HTMLElement {
return document.querySelector('.sky-flyout') as HTMLElement;
return document.querySelector('.sky-flyout') as HTMLElement;
}

function getFlyoutHandleElement(): HTMLElement {
Expand All @@ -106,6 +107,10 @@ describe('Flyout component', () => {
return document.querySelector('.sky-flyout-btn-permalink') as HTMLElement;
}

function getIteratorButtonElement(): NodeListOf<HTMLButtonElement> {
return document.querySelectorAll('.sky-flyout-btn-iterator') as NodeListOf<HTMLButtonElement>;
}

function getPrimaryActionButtonElement(): HTMLElement {
return document.querySelector('.sky-flyout-btn-primary-action') as HTMLElement;
}
Expand Down Expand Up @@ -314,61 +319,61 @@ describe('Flyout component', () => {
);

it('should resize when handle is dragged', fakeAsync(() => {
openFlyout({});
const flyoutElement = getFlyoutElement();
const handleElement = getFlyoutHandleElement();
openFlyout({});
const flyoutElement = getFlyoutElement();
const handleElement = getFlyoutHandleElement();

expect(flyoutElement.style.width).toBe('500px');
expect(flyoutElement.style.width).toBe('500px');

let evt = document.createEvent('MouseEvents');
evt.initMouseEvent('mousedown', false, false, window, 0, 0, 0, 1000,
0, false, false, false, false, 0, undefined);
let evt = document.createEvent('MouseEvents');
evt.initMouseEvent('mousedown', false, false, window, 0, 0, 0, 1000,
0, false, false, false, false, 0, undefined);

handleElement.dispatchEvent(evt);
makeEvent('mousemove', { clientX: 1100 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('400px');
makeEvent('mousemove', { clientX: 1000 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('500px');
makeEvent('mouseup', {});
handleElement.dispatchEvent(evt);
makeEvent('mousemove', { clientX: 1100 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('400px');
makeEvent('mousemove', { clientX: 1000 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('500px');
makeEvent('mouseup', {});
}));

it('should resize flyout when range input is changed', fakeAsync(() => {
openFlyout({});
const flyoutElement = getFlyoutElement();
expect(flyoutElement.style.width).toBe('500px');
let resizeInput: any = flyoutElement.querySelector('.sky-flyout-resize-handle');
openFlyout({});
const flyoutElement = getFlyoutElement();
expect(flyoutElement.style.width).toBe('500px');
let resizeInput: any = flyoutElement.querySelector('.sky-flyout-resize-handle');

resizeInput.value = '400';
SkyAppTestUtility.fireDomEvent(resizeInput, 'input');
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('400px');
resizeInput.value = '400';
SkyAppTestUtility.fireDomEvent(resizeInput, 'input');
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('400px');

resizeInput.value = '500';
SkyAppTestUtility.fireDomEvent(resizeInput, 'input');
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('500px');
resizeInput.value = '500';
SkyAppTestUtility.fireDomEvent(resizeInput, 'input');
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('500px');
}));

it('should have correct aria-labels on resizing range input', fakeAsync(() => {
openFlyout({maxWidth: 1000, minWidth: 200});
const flyoutElement = getFlyoutElement();
let resizeInput: any = flyoutElement.querySelector('.sky-flyout-resize-handle');
openFlyout({ maxWidth: 1000, minWidth: 200 });
const flyoutElement = getFlyoutElement();
let resizeInput: any = flyoutElement.querySelector('.sky-flyout-resize-handle');

expect(flyoutElement.style.width).toBe('500px');
expect(resizeInput.getAttribute('aria-controls')).toBe(flyoutElement.id);
expect(flyoutElement.style.width).toBe('500px');
expect(resizeInput.getAttribute('aria-controls')).toBe(flyoutElement.id);

expect(resizeInput.getAttribute('aria-valuenow')).toBe('500');
expect(resizeInput.getAttribute('aria-valuemax')).toBe('1000');
expect(resizeInput.getAttribute('aria-valuemin')).toBe('200');
expect(resizeInput.getAttribute('aria-valuenow')).toBe('500');
expect(resizeInput.getAttribute('aria-valuemax')).toBe('1000');
expect(resizeInput.getAttribute('aria-valuemin')).toBe('200');

expect(resizeInput.getAttribute('max')).toBe('1000');
expect(resizeInput.getAttribute('min')).toBe('200');
expect(resizeInput.getAttribute('max')).toBe('1000');
expect(resizeInput.getAttribute('min')).toBe('200');
}));

it('should set iframe styles correctly during dragging', fakeAsync(() => {
Expand All @@ -392,33 +397,33 @@ describe('Flyout component', () => {
}));

it('should respect minimum and maximum when resizing', fakeAsync(() => {
openFlyout({ maxWidth: 1000, minWidth: 200});
const flyoutElement = getFlyoutElement();
const handleElement = getFlyoutHandleElement();
openFlyout({ maxWidth: 1000, minWidth: 200 });
const flyoutElement = getFlyoutElement();
const handleElement = getFlyoutHandleElement();

expect(flyoutElement.style.width).toBe('500px');
let evt = document.createEvent('MouseEvents');
evt.initMouseEvent('mousedown', false, false, window, 0, 0, 0, 1000,
0, false, false, false, false, 0, undefined);
handleElement.dispatchEvent(evt);
makeEvent('mousemove', { clientX: 500 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('1000px');
makeEvent('mousemove', { clientX: 200 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('1000px');
makeEvent('mousemove', { clientX: 1300 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('200px');
makeEvent('mousemove', { clientX: 1400 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('200px');
makeEvent('mouseup', {});
})
expect(flyoutElement.style.width).toBe('500px');
let evt = document.createEvent('MouseEvents');
evt.initMouseEvent('mousedown', false, false, window, 0, 0, 0, 1000,
0, false, false, false, false, 0, undefined);
handleElement.dispatchEvent(evt);
makeEvent('mousemove', { clientX: 500 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('1000px');
makeEvent('mousemove', { clientX: 200 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('1000px');
makeEvent('mousemove', { clientX: 1300 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('200px');
makeEvent('mousemove', { clientX: 1400 });
fixture.detectChanges();
tick();
expect(flyoutElement.style.width).toBe('200px');
makeEvent('mouseup', {});
})
);

it('should not resize when handle is not clicked',
Expand Down Expand Up @@ -652,4 +657,73 @@ describe('Flyout component', () => {
})
);
});

describe('iterator', () => {
it('should not show the iterator button if no iterator config properties are defined',
fakeAsync(() => {
openFlyout();
const iteratorButtons = getIteratorButtonElement();
expect(iteratorButtons.length).toEqual(0);
})
);

it('should show disabled iterator buttons if iterator config properties are set to disabled',
fakeAsync(() => {
openFlyout({
iterator: <SkyFlyoutIterator>{
previousIteratorIsDisabled: true,
nextIteratorIsDisabled: true,
previousIteratorButtonClick: () => undefined,
nextIteratorButtonClick: () => undefined
}
});
const iteratorButtons = getIteratorButtonElement();
expect(iteratorButtons.length).toEqual(2);
expect(iteratorButtons[0].disabled).toBeTruthy();
expect(iteratorButtons[1].disabled).toBeTruthy();
})
);

it('should call previousIteratorButtonClick callback if previous button is clicked',
fakeAsync(() => {
let callbackClicked: boolean = false;
openFlyout({
iterator: <SkyFlyoutIterator>{
previousIteratorIsDisabled: false,
nextIteratorIsDisabled: false,
previousIteratorButtonClick: () => {
callbackClicked = true;
},
nextIteratorButtonClick: () => undefined
}
});
const iteratorButtons = getIteratorButtonElement();
iteratorButtons[0].click();
fixture.detectChanges();
tick();
expect(callbackClicked).toBeTruthy();
})
);

it('should call nextIteratorButtonClick callback if next button is clicked',
fakeAsync(() => {
let callbackClicked: boolean = false;
openFlyout({
iterator: <SkyFlyoutIterator>{
previousIteratorIsDisabled: false,
nextIteratorIsDisabled: false,
previousIteratorButtonClick: () => undefined,
nextIteratorButtonClick: () => {
callbackClicked = true;
}
}
});
const iteratorButtons = getIteratorButtonElement();
iteratorButtons[1].click();
fixture.detectChanges();
tick();
expect(callbackClicked).toBeTruthy();
})
);
});
});
37 changes: 28 additions & 9 deletions src/app/public/modules/flyout/flyout.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import {
SkyFlyoutConfig,
SkyFlyoutMessage,
SkyFlyoutMessageType,
SkyFlyoutPermalink
SkyFlyoutPermalink,
SkyFlyoutIterator
} from './types';

const FLYOUT_OPEN_STATE = 'flyoutOpen';
Expand Down Expand Up @@ -111,6 +112,10 @@ export class SkyFlyoutComponent implements OnDestroy, OnInit {
return {};
}

public get iteratorDetail(): SkyFlyoutIterator {
return this.config.iterator;
}

public get primaryActionLabel(): string {
if (this.config.primaryAction && this.config.primaryAction.label) {
return this.config.primaryAction.label;
Expand Down Expand Up @@ -200,6 +205,20 @@ export class SkyFlyoutComponent implements OnDestroy, OnInit {
return false;
}

public invokeIterator(showPrevious: boolean) {
let iteratorDetail = this.iteratorDetail;

if (iteratorDetail) {
if (showPrevious && iteratorDetail.previousIteratorButtonClick) {
iteratorDetail.previousIteratorButtonClick();
} else if (!showPrevious && iteratorDetail.nextIteratorButtonClick) {
iteratorDetail.nextIteratorButtonClick();
}
}

return false;
}

public getAnimationState(): string {
return (this.isOpening) ? FLYOUT_OPEN_STATE : FLYOUT_CLOSED_STATE;
}
Expand Down Expand Up @@ -268,16 +287,16 @@ export class SkyFlyoutComponent implements OnDestroy, OnInit {
/* tslint:disable-next-line:switch-default */
switch (message.type) {
case SkyFlyoutMessageType.Open:
if (!this.isOpen) {
this.isOpen = false;
this.isOpening = true;
}
break;
if (!this.isOpen) {
this.isOpen = false;
this.isOpening = true;
}
break;

case SkyFlyoutMessageType.Close:
this.isOpen = true;
this.isOpening = false;
break;
this.isOpen = true;
this.isOpening = false;
break;
}

this.changeDetector.markForCheck();
Expand Down
5 changes: 5 additions & 0 deletions src/app/public/modules/flyout/types/flyout-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import {
SkyFlyoutPermalink
} from './flyout-permalink';

import {
SkyFlyoutIterator
} from './flyout-iterator';

export interface SkyFlyoutConfig {
ariaDescribedBy?: string;
ariaLabelledBy?: string;
Expand All @@ -16,4 +20,5 @@ export interface SkyFlyoutConfig {
permalink?: SkyFlyoutPermalink;
primaryAction?: SkyFlyoutAction;
providers?: any[];
iterator?: SkyFlyoutIterator;
}
6 changes: 6 additions & 0 deletions src/app/public/modules/flyout/types/flyout-iterator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface SkyFlyoutIterator {
previousIteratorIsDisabled: boolean;
nextIteratorIsDisabled: boolean;
previousIteratorButtonClick: () => void;
nextIteratorButtonClick: () => void;
}
Loading