From c4e50b74ada96135b4df6b71c860612ef9c72f9c Mon Sep 17 00:00:00 2001 From: Patrick Michalina Date: Sat, 27 Jul 2019 20:47:32 -0500 Subject: [PATCH] feat(grid-list): add containerIdPrefix property to prevent polluting element IDs (#193) --- .../common/grid/grid.component.html | 2 +- .../common/grid/grid.component.spec.ts | 56 +++++++++++++++++-- .../common/grid/grid.component.ts | 27 ++++++++- .../common/ng-grid-list.config.interfaces.ts | 8 +++ .../common/ng-grid-list.module.defaults.ts | 1 + .../common/ng-grid-list.module.ts | 13 +++-- .../common/ng-grid-list.tokens.ts | 1 + 7 files changed, 96 insertions(+), 12 deletions(-) diff --git a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.html b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.html index 750495c3..835e3f10 100644 --- a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.html +++ b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.html @@ -17,7 +17,7 @@ [floGridListDragDropGridRef]="this" [style.flex-basis.%]="item.flexBasis" [style.padding-top.%]="item.padTop" - [attr.id]="item?.value?.id || '__fs_gs_some__' + idx"> + [attr.id]="item?.containerId">
diff --git a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.spec.ts b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.spec.ts index 4dbc9496..09390459 100644 --- a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.spec.ts +++ b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.spec.ts @@ -1,7 +1,6 @@ import { async, TestBed, fakeAsync, tick, discardPeriodicTasks } from '@angular/core/testing' import { FloGridListViewComponent } from './grid.component' import { FloGridListModule } from '../ng-grid-list.module' -import { DEFAULT_FLO_GRID_LIST_DEFAULT_VIEWCOUNT, DEFAULT_FLO_GRID_LIST_ASPECT_RATIO } from '../ng-grid-list.module.defaults' import { take } from 'rxjs/operators' import { PLATFORM_ID, Component, NgModule } from '@angular/core' import { By } from '@angular/platform-browser' @@ -10,9 +9,14 @@ import { FLO_GRID_LIST_OVERLAY_START, FLO_GRID_LIST_OVERLAY_FADEOUT, FLO_GRID_LIST_OVERLAY_THROTTLE, FLO_GRID_LIST_MAX_HEIGHT, FLO_GRID_LIST_SELECTED_INDEX, FLO_GRID_LIST_OVERLAY_STATIC, FLO_GRID_LIST_ITEMS, FLO_GRID_LIST_DRAG_DROP_ENABLED, FLO_GRID_LIST_ASPECT_RATIO, - FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY, - FLO_GRID_LIST_TRACK_BY_FN + FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY, FLO_GRID_LIST_TRACK_BY_FN, + FLO_GRID_LIST_CONTAINER_ID_PREFIX } from '../ng-grid-list.tokens' +import { + DEFAULT_FLO_GRID_LIST_DEFAULT_VIEWCOUNT, + DEFAULT_FLO_GRID_LIST_ASPECT_RATIO, + DEFAULT_FLO_GRID_LIST_CONTAINER_ID_PREFIX +} from '../ng-grid-list.module.defaults' // tslint:disable: readonly-keyword // tslint:disable: no-object-mutation @@ -24,7 +28,7 @@ import {
Overlay controls go here
-
{{ item.value.value }}
+
{{ item.value.value }}
EMPTY
` @@ -144,6 +148,50 @@ describe(FloGridListViewComponent.name, () => { it('should start with token value', () => expect(createSut().instance.maxheight).toEqual(TestBed.get(FLO_GRID_LIST_MAX_HEIGHT))) }) + describe('containerIdPrefix property', () => { + it('should double bind', () => testInputProperty('containerIdPrefix', '_cool_prefx_yo_')) + it('should expose setter function', () => testInputPropSetFunc('containerIdPrefix', 'setContainerIdPrefix', '_cool_prefx_yo_')) + it('should start with token value', () => + expect(createSut().instance.containerIdPrefix).toEqual(TestBed.get(FLO_GRID_LIST_CONTAINER_ID_PREFIX))) + it('should start with default token value', () => + expect(createSut().instance.containerIdPrefix).toEqual(DEFAULT_FLO_GRID_LIST_CONTAINER_ID_PREFIX)) + + it('should separate container IDs and content IDs', () => { + const sut = createSut() + sut.hoistInstance.items = [SAMPLE_ITEM_1] + sut.hoistFixture.detectChanges() + + const prefixedIds = sut.fixture.queryAll(By.css('#__fs_grid__1')) + const innerIds = sut.fixture.queryAll(By.css('#t_1')) + + expect(prefixedIds.length).toEqual(1) + expect(innerIds.length).toEqual(1) + }) + + it('should configure via module', () => { + TestBed.resetTestingModule() + TestBed.configureTestingModule({ + imports: [FloGridTestingModule, FloGridListModule.config({ + overlay: { + throttle: 6000, + fadeout: 1 + }, + containerIdPrefix: '-test_prefix_config-' + })] + }).compileComponents() + + const sut = createSut() + sut.hoistInstance.items = [SAMPLE_ITEM_1] + sut.hoistFixture.detectChanges() + + const prefixedIds = sut.fixture.queryAll(By.css('#-test_prefix_config-1')) + const innerIds = sut.fixture.queryAll(By.css('#t_1')) + + expect(prefixedIds.length).toEqual(1) + expect(innerIds.length).toEqual(1) + }) + }) + describe('trackByFn property', () => { it('should double bind', () => testInputProperty('trackByFn', () => true)) it('should expose setter function', () => testInputPropSetFunc('trackByFn', 'setTrackByFn', (idx: number) => idx + 1)) diff --git a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.ts b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.ts index 472a2541..5ab3fb02 100644 --- a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.ts +++ b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.ts @@ -31,7 +31,8 @@ import { IFloGridListBaseItem, FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY, FLO_GRID_LIST_ASPECT_RATIO, - FLO_GRID_LIST_TRACK_BY_FN + FLO_GRID_LIST_TRACK_BY_FN, + FLO_GRID_LIST_CONTAINER_ID_PREFIX } from '../ng-grid-list.tokens' export interface IViewItem { @@ -73,7 +74,8 @@ export class FloGridListViewComponent implem @Inject(FLO_GRID_LIST_OVERLAY_NG_STYLE) private _overlayNgStyle: Object, @Inject(FLO_GRID_LIST_DRAG_DROP_ENABLED) private _dragDropEnabled: boolean, @Inject(FLO_GRID_LIST_ASPECT_RATIO) private _aspectRatio: number, - @Inject(FLO_GRID_LIST_TRACK_BY_FN) private _trackByFn: TrackByFunction> + @Inject(FLO_GRID_LIST_TRACK_BY_FN) private _trackByFn: TrackByFunction>, + @Inject(FLO_GRID_LIST_CONTAINER_ID_PREFIX) private _containerIdPrefix: string ) { } @HostListener('fullscreenchange') @@ -335,6 +337,19 @@ export class FloGridListViewComponent implem this.trackByFn = fn } + @Input() + get containerIdPrefix() { + return this._containerIdPrefix + } + set containerIdPrefix(prefix: string) { + this._containerIdPrefix = prefix + this.containerIdPrefixChange.next(prefix) + } + + public setContainerIdPrefix(prefix: string) { + this.containerIdPrefix = prefix + } + public readonly isFullscreen = () => isPlatformServer(this._platformId) ? false : 1 >= window.outerHeight - window.innerHeight get baseMaxWidth() { @@ -380,6 +395,7 @@ export class FloGridListViewComponent implem @Output() public readonly shouldSelectNextEmptyChange = new Subject() @Output() public readonly aspectRatioChange = new Subject() @Output() public readonly trackByFnChange = new Subject>() + @Output() public readonly containerIdPrefixChange = new Subject() @Output() public readonly cdRefChange = merge(this.selectedIdChange, this.selectedIndexChange, this.itemsChange, this.countChange) @Output() public readonly viewItemChange = this.viewItemSource.asObservable().pipe(shareReplay(1)) @@ -427,6 +443,8 @@ export class FloGridListViewComponent implem this._cdRef.markForCheck() } + readonly constructContainerId = (token: string | number) => `${this.containerIdPrefix}${token}` + createViewItems = () => { const square = Math.ceil(Math.sqrt(this.count)) @@ -443,7 +461,10 @@ export class FloGridListViewComponent implem padTop: this.aspectRatioPercentage / square, isShowingBorder: isSelected && this.count > 1, isSelected, - isNotSelected: !isSelected + isNotSelected: !isSelected, + containerId: value.map(i => i.id) + .map(this.constructContainerId) + .valueOr(this.constructContainerId(idx)) } }) } diff --git a/projects/flosportsinc/ng-grid-list/common/ng-grid-list.config.interfaces.ts b/projects/flosportsinc/ng-grid-list/common/ng-grid-list.config.interfaces.ts index 9badcb0e..2be9c831 100644 --- a/projects/flosportsinc/ng-grid-list/common/ng-grid-list.config.interfaces.ts +++ b/projects/flosportsinc/ng-grid-list/common/ng-grid-list.config.interfaces.ts @@ -46,6 +46,14 @@ export interface FloGridListModuleConfiguration { /** Starting selection box. Defaults to 0 */ readonly selectedIndex: number + /** + * Prefix the grid-list-item container ID's so they do not conflict downstream + * if ID is used elsewhere in the application. + * Defaults to '__fs_grid__' which would give the outer div + * items the following pattern:
+ **/ + readonly containerIdPrefix: string + /** When view count increases, set selection box to next empty square */ readonly autoSelectNextEmptyOnCountChange: boolean diff --git a/projects/flosportsinc/ng-grid-list/common/ng-grid-list.module.defaults.ts b/projects/flosportsinc/ng-grid-list/common/ng-grid-list.module.defaults.ts index 1490ea43..bc745fca 100644 --- a/projects/flosportsinc/ng-grid-list/common/ng-grid-list.module.defaults.ts +++ b/projects/flosportsinc/ng-grid-list/common/ng-grid-list.module.defaults.ts @@ -4,6 +4,7 @@ export const DEFAULT_FLO_GRID_LIST_MIN_VIEWCOUNT = 1 export const DEFAULT_FLO_GRID_LIST_MAX_VIEWCOUNT = 25 export const DEFAULT_FLO_GRID_LIST_MAX_HEIGHT = 800 export const DEFAULT_FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY = false +export const DEFAULT_FLO_GRID_LIST_CONTAINER_ID_PREFIX = '__fs_grid__' export const DEFAULT_FLO_GRID_LIST_OVERLAY_ENABLED = true export const DEFAULT_FLO_GRID_LIST_OVERLAY_START = true diff --git a/projects/flosportsinc/ng-grid-list/common/ng-grid-list.module.ts b/projects/flosportsinc/ng-grid-list/common/ng-grid-list.module.ts index 2b9ec503..cce7f082 100644 --- a/projects/flosportsinc/ng-grid-list/common/ng-grid-list.module.ts +++ b/projects/flosportsinc/ng-grid-list/common/ng-grid-list.module.ts @@ -12,7 +12,9 @@ import { FLO_GRID_LIST_OVERLAY_NG_STYLE, FLO_GRID_LIST_MAX_HEIGHT, FLO_GRID_LIST_SELECTED_INDEX, FLO_GRID_LIST_OVERLAY_STATIC, FLO_GRID_LIST_ITEMS, FLO_GRID_LIST_DRAG_DROP_ENABLED, FLO_GRID_LIST_DRAG_DROP_FROM_LISTS_ENABLED, FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY, - FLO_GRID_LIST_AUTO_FILL_FROM_LIST_ON_LOAD, FLO_GRID_LIST_ASPECT_RATIO, FLO_GRID_LIST_TRACK_BY_FN, IFloGridListBaseItem + FLO_GRID_LIST_AUTO_FILL_FROM_LIST_ON_LOAD, FLO_GRID_LIST_ASPECT_RATIO, + FLO_GRID_LIST_TRACK_BY_FN, IFloGridListBaseItem, + FLO_GRID_LIST_CONTAINER_ID_PREFIX } from './ng-grid-list.tokens' import { DEFAULT_FLO_GRID_LIST_MIN_VIEWCOUNT, @@ -31,7 +33,8 @@ import { DEFAULT_FLO_GRID_LIST_DRAG_DROP_LISTS_ENABLED, DEFAULT_FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY, DEFAULT_FLO_GRID_LIST_AUTO_FILL_FROM_LIST_ON_LOAD, - DEFAULT_FLO_GRID_LIST_ASPECT_RATIO + DEFAULT_FLO_GRID_LIST_ASPECT_RATIO, + DEFAULT_FLO_GRID_LIST_CONTAINER_ID_PREFIX } from './ng-grid-list.module.defaults' export function defaultFloGridListGuidGenerator() { @@ -89,7 +92,8 @@ export function defaultFloGridListTrackByFn() { { provide: FLO_GRID_LIST_DRAG_DROP_FROM_LISTS_ENABLED, useValue: DEFAULT_FLO_GRID_LIST_DRAG_DROP_LISTS_ENABLED }, { provide: FLO_GRID_LIST_AUTO_FILL_FROM_LIST_ON_LOAD, useValue: DEFAULT_FLO_GRID_LIST_AUTO_FILL_FROM_LIST_ON_LOAD }, { provide: FLO_GRID_LIST_ASPECT_RATIO, useValue: DEFAULT_FLO_GRID_LIST_ASPECT_RATIO }, - { provide: FLO_GRID_LIST_TRACK_BY_FN, useFactory: defaultFloGridListTrackByFn } + { provide: FLO_GRID_LIST_TRACK_BY_FN, useFactory: defaultFloGridListTrackByFn }, + { provide: FLO_GRID_LIST_CONTAINER_ID_PREFIX, useValue: DEFAULT_FLO_GRID_LIST_CONTAINER_ID_PREFIX } ] }) export class FloGridListModule { @@ -114,7 +118,8 @@ export class FloGridListModule { { provide: FLO_GRID_LIST_DRAG_DROP_ENABLED, useValue: cfg.dragDrop && cfg.dragDrop.enabled !== undefined ? cfg.dragDrop.enabled : DEFAULT_FLO_GRID_LIST_DRAG_DROP_ENABLED }, { provide: FLO_GRID_LIST_DRAG_DROP_FROM_LISTS_ENABLED, useValue: cfg.dragDrop && cfg.dragDrop.allowFromLists !== undefined ? cfg.dragDrop.allowFromLists : DEFAULT_FLO_GRID_LIST_DRAG_DROP_LISTS_ENABLED }, { provide: FLO_GRID_LIST_AUTO_FILL_FROM_LIST_ON_LOAD, useValue: cfg.list && cfg.list.fillInitialListValues !== undefined ? cfg.list.fillInitialListValues : DEFAULT_FLO_GRID_LIST_DRAG_DROP_LISTS_ENABLED }, - { provide: FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY, useValue: cfg.autoSelectNextEmptyOnCountChange !== undefined ? cfg.autoSelectNextEmptyOnCountChange : DEFAULT_FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY } + { provide: FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY, useValue: cfg.autoSelectNextEmptyOnCountChange !== undefined ? cfg.autoSelectNextEmptyOnCountChange : DEFAULT_FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY }, + { provide: FLO_GRID_LIST_CONTAINER_ID_PREFIX, useValue: cfg.containerIdPrefix !== undefined ? cfg.containerIdPrefix : DEFAULT_FLO_GRID_LIST_CONTAINER_ID_PREFIX }, ] } } diff --git a/projects/flosportsinc/ng-grid-list/common/ng-grid-list.tokens.ts b/projects/flosportsinc/ng-grid-list/common/ng-grid-list.tokens.ts index e7796bd2..264eb305 100644 --- a/projects/flosportsinc/ng-grid-list/common/ng-grid-list.tokens.ts +++ b/projects/flosportsinc/ng-grid-list/common/ng-grid-list.tokens.ts @@ -9,6 +9,7 @@ export const FLO_GRID_LIST_MAX_COUNT = new InjectionToken('fs.grid.list.count.ma export const FLO_GRID_LIST_MAX_HEIGHT = new InjectionToken('fs.grid.list.maxheight') export const FLO_GRID_LIST_SELECTED_INDEX = new InjectionToken('fs.grid.list.selectedIndex') export const FLO_GRID_LIST_AUTO_SELECT_NEXT_EMPTY = new InjectionToken('fs.grid.list.selectNext') +export const FLO_GRID_LIST_CONTAINER_ID_PREFIX = new InjectionToken('fs.grid.list.id.prefix') export const FLO_GRID_LIST_GUID_GEN = new InjectionToken('fs.grid.list.guid')