UNPKG

@linzjs/step-ag-grid

Version:

[![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release) > Reusable [ag-grid](https://www.ag-grid.com/) component for LINZ / Toitū te whenua.

160 lines (144 loc) 5.08 kB
/** * General query all by selected. Internal use, use quick operations instead. * * @param selector Selector to use * @param container Optional container * @return HTMLElement array */ import { IconName } from '@linzjs/lui/dist/components/LuiIcon/LuiIcon'; import { wait } from '../util'; const queryAllBySelector = <T extends HTMLElement>(selector: string, container: HTMLElement = document.body): T[] => Array.from(container.querySelectorAll<T>(selector)); /** * Filters for query quick operations. */ export interface IQueryQuick { testId?: string; // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents tagName?: 'button' | 'span' | 'div' | 'input' | 'textarea' | any; text?: string | RegExp; icon?: IconName; ariaLabel?: string; role?: string; classes?: string; child?: IQueryQuick; selector?: string; } const escapeSelectorParam = (param: string): string => param.replace(/["\\]/g, '\\$&'); export const getMatcher = (matcherText: string | RegExp) => { const textMatcher = typeof matcherText === 'string' ? (text?: string) => text != null && text.toLowerCase() === matcherText.toLowerCase() : (text?: string) => text != null && matcherText.test(text); return (e: HTMLElement) => textMatcher(e.innerHTML?.trim()) || textMatcher(e.innerText?.trim()); }; /** * Build selector for quick operations. * * @param props Filters to convert to selector. * @param container Optional container to search in. */ const quickSelector = <T extends HTMLElement>( props: IQueryQuick, container?: HTMLElement, ): { selector: string; els: T[] } => { let selector = ''; let lastIQueryQuick = props; for (let loop: IQueryQuick | undefined = props; loop; loop = loop.child) { lastIQueryQuick = loop; loop.selector && (selector += loop.selector); loop.tagName && (selector += loop.tagName); loop.ariaLabel && (selector += `[aria-label='${escapeSelectorParam(loop.ariaLabel)}']`); loop.role && (selector += `[role="${escapeSelectorParam(loop.role)}"]`); loop.testId && (selector += `[data-testid="${escapeSelectorParam(loop.testId)}"]`); loop.icon && (selector += `[data-icon='${loop.icon}']`); loop.classes && (selector += loop.classes); selector += ' '; } if (selector.trim() == '') { throw 'get/query/findQuick needs at least one defined parameter'; } let els = queryAllBySelector<T>(selector, container); if (lastIQueryQuick.text != null) { const matcher = getMatcher(lastIQueryQuick.text); els = els.filter(matcher); } return { selector: [ selector, typeof lastIQueryQuick.text === 'string' ? JSON.stringify(lastIQueryQuick.text) : lastIQueryQuick.text, ] .filter((r) => r) .join(' '), els, }; }; /** * Query by filter. * * @param filter Filter * @param container Optional container to look in * @return HTMLElement if found else null */ export const queryQuick = <T extends HTMLElement>(filter: IQueryQuick, container?: HTMLElement): T | null => { const { els, selector } = quickSelector<T>(filter, container); if (els.length > 1) { throw `Found multiple(${els.length}) elements by selector ${selector}\n${els .map((el, index) => `${index}: ${el.parentElement?.innerHTML}\n\n`) .join()}`; } return els[0] ?? null; }; /** * Query all by filter. * * @param filter Filter * @param container Optional container to look in * @return HTMLElement array */ export const queryAllQuick = <T extends HTMLElement>(filter: IQueryQuick, container?: HTMLElement): T[] => quickSelector<T>(filter, container)?.els; /** * Get all by filter. * * @param filter Filter * @param container Optional container to look in * @return HTMLElement array. Throws exception if nothing is found. */ export const getAllQuick = <T extends HTMLElement>(filter: IQueryQuick, container?: HTMLElement): T[] => { const els = queryAllQuick(filter, container); if (els.length == 0) { throw Error(`getAllQuick not found, selector: ${quickSelector(filter).selector}`); } return els as T[]; }; /** * Get by filter. * * @param filter Filter * @param container Optional container to look in * @return HTMLElement. Throws exception if not found. */ export const getQuick = (filter: IQueryQuick, container?: HTMLElement): HTMLElement => { const el = queryQuick(filter, container); if (el == null) { throw Error(`getQuick not found, selector: ${quickSelector(filter).selector}`); } return el; }; /** * Find by filter. Waits up to 5 seconds to find filter. * * @param filter Filter * @param container Optional container to look in * @return HTMLElement. Throws exception if not found. */ export const findQuick = async <T extends HTMLElement>(filter: IQueryQuick, container?: HTMLElement): Promise<T> => { const endTime = Date.now() + 1000; while (Date.now() < endTime) { const el = queryQuick<T>(filter, container); if (el) return el; await wait(50); } throw Error(`findQuick not found, selector: ${quickSelector(filter).selector}`); };