import { StringUtils } from "./StringUtils.js"; import DataUnit from "../dataunit/DataUnit.js"; export interface IElementIDInfo { id?: string, dataUnit?: DataUnit } /** * `ElementIDUtils`: O ElementIDUtils é um utilitário responsável por criar e adicionar identificadores únicos aos componentes através do atributo data-element-id. * A finalidade dele é otimizar a automação dos testes e melhorar a eficiência na manipulação dos componentes do Design System, garantindo seleções precisas e seguras. */ export class ElementIDUtils { public static DATA_ELEMENT_ID_ATTRIBUTE_NAME: string = "data-element-id"; public static INTERNAL_INPUT_NAME: string = "embedded"; private static REGEX_DATAUNIT_NAME = /dd:\/\/(.+?)\//; /** * Cria e adiciona a propriedade `data-element-id` em um elemento. * * @param element - Elemento HTML a ser modificado (HTMLElement). * @param suffix - Sufixo/Texto para ser adicionado. * @param iDInfo - ID para ser adicionado. * @returns - O data-element-id gerado. */ public static addIDInfo(element: HTMLElement, suffix?: string, iDInfo?: IElementIDInfo): string { try{ let dataElementID = this.getDataElementID(element, suffix, iDInfo); dataElementID = StringUtils.replaceAccentuatedChars(dataElementID, false); dataElementID = this.addPrefix(iDInfo, dataElementID); element.setAttribute(ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME, dataElementID); return dataElementID; }catch(e){ console.warn(`Erro ao gerar data-element-id: ${element.tagName}`, e); } return ""; } public static addIDInfoIfNotExists(element: HTMLElement, suffix?: string, iDInfo?: IElementIDInfo): string { try{ let dataElementID = element.getAttribute(ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME); if(dataElementID == undefined){ dataElementID = ElementIDUtils.addIDInfo(element, suffix, iDInfo) } return dataElementID; }catch(e){ console.warn(`Erro ao gerar data-element-id: ${element.tagName}`, e); } return ""; } public static getInternalIDInfo(sufix: string){ return `${ElementIDUtils.INTERNAL_INPUT_NAME}_${sufix}`; } /** * Obtém o `data-element-id` do elemento com adição do sufixo e ID. * * @param element - Elemento HTML a ser modificado (HTMLElement). * @param suffix - Sufixo/Texto para ser adicionado. * @param iDInfo - ID para ser adicionado. * @returns - Atributo `data-element-id` do elemento modificado com sufixo e/ou ID. */ private static getDataElementID(element: HTMLElement, suffix?: string, iDInfo?: IElementIDInfo) { const dataElementID = ElementIDUtils.getDataElementIDAttribute(element); if(dataElementID != null){ return this.addSuffix(StringUtils.toCamelCase((dataElementID as string)), suffix, element); } const validAttribute = this.getAttributeValid(element, iDInfo); if(validAttribute) return this.addSuffix(validAttribute, suffix, element); if(suffix) return String(suffix); const tagName = StringUtils.toCamelCase(element.tagName); element.setAttribute(ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME, tagName); return tagName; } /** * Obtém ID válido para o elemento. * * @param element - Elemento HTML a ser modificado (HTMLElement). * @param iDInfo - ID para ser adicionado. * @returns - ID para ser adicionado ao elemento conforme ordem de prioridade. */ private static getAttributeValid(element: HTMLElement, iDInfo?: IElementIDInfo): string | null{ if(iDInfo?.id){ return this.formatDescription(iDInfo?.id); } if(element.hasAttribute("data-field-name")){ return StringUtils.toCamelCase(element.getAttribute("data-field-name") as string); } if(element?.id){ return StringUtils.toCamelCase(element?.id); } if(element.hasAttribute("name")){ return this.formatDescription(element.getAttribute("name")); } if(element.hasAttribute("label")){ return this.formatDescription(element.getAttribute("label")); } if(element.hasAttribute("title")){ return this.formatDescription(element.getAttribute("title")); } return null; } /** * Adiciona sufixo ao atributo `data-element-id` de um elemento, utilizado para montar a hierarquia dos ids dos componentes em tela. * * @param dataElementID - ID para ser adicionado ao `data-element-id`. * @param suffix - Sufixo/Texto para ser adicionado ao `data-element-id`. * @param element - Elemento HTML a ser modificado (HTMLElement). * @returns - `data-element-id` com sufixo. * * @example * Um ez-combo-box tem data-element-id = codparc_input_embedded_combo. * Dentro desse ez-combo-box existe um ez-text-input. O data-element-id teria como sufixo o id 'codparc_input_embedded_combo' referente ao seu pai. */ private static addSuffix(dataElementID: string | null, suffix: string | undefined, element: HTMLElement): string{ if(suffix){ return `${dataElementID}_${StringUtils.toCamelCase(suffix)}`; } if(StringUtils.isEmpty(dataElementID)){ return `${StringUtils.toCamelCase(element.tagName)}`; } return `${dataElementID}_${StringUtils.toCamelCase(element.tagName)}`; } /** * Adiciona a propriedade name do DataUnit como prefixo do data-element-id do elemento. * * @param iDInfo - ID para ser adicionado ao `data-element-id`. * @param dataElementID - Sufixo/Texto para ser adicionado ao `data-element-id`. * @returns - String contendo informação para ser usada no `data-element-id` do elemento. */ private static addPrefix(iDInfo: IElementIDInfo | undefined, dataElementID: string): string { let dataUnitName: string = iDInfo?.dataUnit?.name || ""; dataUnitName = this.parseDataUnitName(dataUnitName); if (iDInfo?.dataUnit && !dataElementID?.startsWith(dataUnitName)) { dataElementID = `${StringUtils.toCamelCase(dataUnitName)}_${dataElementID}` } return dataElementID; } /** * Remove caracteres especiais. * * @param value - Texto que terá os caracteres especiais removidos. * @returns - Retorna a string sem caracteres especiais e em camelCase. */ private static formatDescription(value: string | null): string{ if(!value) return ""; value = StringUtils.replaceAccentuatedChars(value, false); return StringUtils.toCamelCase((value.replace(/[^\w\sÀ-ÖØ-öø-ÿ]/gi, " ")).replace(/\s+/g, ' ').trim()); } private static getDataElementIDAttribute(element: HTMLElement): string | null { if((element as any)[ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME] || element.hasAttribute(ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME)) { return (element as any)[ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME] || element.getAttribute(ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME); } return null; } private static parseDataUnitName(uri:string):string{ if(StringUtils.isEmpty(uri)){ return uri; } const matcher:RegExpExecArray|null = this.REGEX_DATAUNIT_NAME.exec(uri); return matcher?.[1] ?? uri; } }