UNPKG

@govbr-ds/core

Version:

Padrão Digital de Governo

365 lines (338 loc) 11.6 kB
import Collapse from '../../partial/js/behavior/collapse' import Dropdown from '../../partial/js/behavior/dropdown' /** Classe para instanciar um objeto BRTable*/ /* eslint-disable complexity */ class BRTable { /** * Instancia do objeto * @param {string} name - Nome do componente em minúsculo * @param {object} component - Objeto referenciando a raiz do componente DOM * @param {number} sequence - 'índice do componente para sobreposição' */ constructor(name, component, sequence) { this.name = name this.component = component this._header = this.component.querySelector('.header, .table-header') this._table = this.component.querySelector('table') this._sequence = sequence this._setBehaviors() } /** * Define comportamentos do componente * @private */ _setBehaviors() { this._makeResponsiveTable() this._setHeaderWidth() this._searchBehavior() this._dropdownBehavior() this._collpaseBehavior() this._densityBehavior() this._setClickActions() } /** * Configura reponsividade da tabela * @private */ _makeResponsiveTable() { const responsiveClass = 'responsive' if (!this.component.querySelector(`.${responsiveClass}`)) { const responsiveElement = document.createElement('div') responsiveElement.classList.add(responsiveClass) responsiveElement.appendChild(this._table) this._header.after(responsiveElement) } } /** * Configura rolagem * @private */ _makeScroller() { const scrollerTag = document.createElement('div') scrollerTag.classList.add('scroller') for (const header of this._table.querySelectorAll('thead tr th')) { const clonedHeader = document.createElement('div') clonedHeader.classList.add('item') clonedHeader.innerHTML = header.innerHTML if (header.offsetWidth) { clonedHeader.style.flex = `1 0 ${header.offsetWidth}px` } scrollerTag.appendChild(clonedHeader) const checkbox = clonedHeader.querySelector('.br-checkbox') if (checkbox) { const input = checkbox.querySelector('input') const label = checkbox.querySelector('label') input.id = `${input.id}-clone` label.setAttribute('for', input.id) } } return scrollerTag } /** * Configura largura do cabeçalho * @private */ _setHeaderWidth() { for (const clonedHeader of this.component.querySelectorAll('.headers > div')) { for (const [index, header] of this.component.querySelectorAll('table thead tr th').entries()) { clonedHeader.children[index].style.flex = `1 0 ${header.offsetWidth}px` } } } /** * Configura coportamento do dropdown * @private */ _dropdownBehavior() { this.component.querySelectorAll('[data-toggle="dropdown"]').forEach((trigger) => { const config = { iconToHide: 'fa-chevron-up', iconToShow: 'fa-chevron-down', trigger, useIcons: true, } this.dropdown = new Dropdown(config) this.dropdown.setBehavior() }) } /** * Configura comportamento de colapsar * @private */ _collpaseBehavior() { this.component.querySelectorAll('[data-toggle="collapse"]').forEach((trigger) => { const config = { iconToHide: 'fa-chevron-up', iconToShow: 'fa-chevron-down', trigger, useIcons: true, } const collapse = new Collapse(config) collapse.setBehavior() }) } /** * Configura comportamento da busca * @private */ _searchBehavior() { if (this.component.dataset.search) { const trigger = this.component.querySelector('[data-toggle="search"]') const target = this.component.querySelector('.search-bar') const dismiss = this.component.querySelector('[data-dismiss="search"]') const inputField = target ? target.querySelector('input') : null // Verifica se os elementos existem antes de continuar if (trigger && target && dismiss && inputField) { // Inicializar this._searchInit(trigger) // Abre busca trigger.addEventListener('click', () => { return this._searchOpen(trigger, target) }) // Fecha busca dismiss.addEventListener('click', () => { return this._searchClose(trigger, target) }) // Fecha busca ao pressionar "Esc" inputField.addEventListener('keydown', (event) => { if (event.key === 'Escape') { this._searchClose(trigger, target) } }) } else { console.error('Um ou mais elementos necessários para a busca não foram encontrados.') } } } /** * Inicializa a busca * @private * @param {object} trigger - Objeto referente ao elemento que dispara a ação */ _searchInit(trigger) { trigger.setAttribute('aria-expanded', 'false') } /** * Abre a busca * @private * @param {object} trigger - Objeto referente ao elemento que dispara a ação * @param {object} target - Objeto referente ao alvo da ação */ _searchOpen(trigger, target) { trigger.setAttribute('aria-expanded', 'true') target.classList.add('show') target.parentElement.classList.add('show') target.querySelector('input').focus() } /** * Fecha a busca * @private * @param {object} trigger - Objeto referente ao elemento que dispara a ação * @param {object} target - Objeto referente ao alvo da ação */ _searchClose(trigger, target) { target.querySelector('input').value = '' target.classList.remove('show') target.parentElement.classList.remove('show') trigger.focus() trigger.setAttribute('aria-expanded', 'false') } /** * Configura densidades * @private */ _densityBehavior() { const desityTriggers = this.component.querySelectorAll('[data-density]') for (const desityTrigger of desityTriggers) { desityTrigger.addEventListener('click', (element) => { this.component.classList.remove('small', 'medium', 'large') this.component.classList.add(desityTrigger.dataset.density) this._hideDensityDropdown() // this.dropdown._setTriggerVisibilityStatus() }) } } /** * Esconde o dropdown de densidades * @private */ _hideDensityDropdown(idTarget) { var element = this.component.querySelector('.actions-trigger ') // Verifica se o elemento existe e se possui a classe 'dropdown' if (element && element.classList.contains('dropdown')) { // Remove a classe 'dropdown' element.classList.remove('dropdown') } var elementList = this.component.querySelector('.actions-trigger .br-list') elementList.setAttribute('data-visible', false) elementList.setAttribute('aria-expanded', false) elementList.setAttribute('hidden', '') } /** * Configura ações de clique * @private */ _setClickActions() { const headerCheckbox = this.component.querySelector('.headers [type="checkbox"]') const tableCheckboxes = this.component.querySelectorAll('tbody [type="checkbox"]') const selectedBar = this.component.querySelector('.selected-bar') const checkAlls = this.component.querySelectorAll('[data-toggle="check-all"]') for (const checkAll of checkAlls) { checkAll.addEventListener('click', () => { this._checkAllTable(selectedBar, tableCheckboxes, headerCheckbox) if (checkAll.parentElement.classList.contains('br-list')) { } }) } if (tableCheckboxes) { for (const checkbox of tableCheckboxes) { checkbox.addEventListener('change', () => { this._checkRow(checkbox, selectedBar, tableCheckboxes, headerCheckbox) }) } } } /** * Configura seleção da linha * @private * @param {object} checkbox - Objeto referente ao checkbox * @param {boolean} check - define se a linha deve ser selecionada */ _setRow(checkbox, check) { const tr = checkbox.parentNode.parentNode.parentNode if (check) { tr.classList.add('is-selected') checkbox.parentNode.classList.add('is-inverted') checkbox.checked = true } else { tr.classList.remove('is-selected') checkbox.parentNode.classList.remove('is-inverted') checkbox.checked = false } } /** * Configura seleção da linha * @private * @param {object} checkbox - Objeto referente ao checkbox * @param {object} selectedBar - Objeto referente a barra contextual * @param {object} tableCheckboxes - Objeto referente a lista de checkboxes * @param {object} headerCheckbox - Objeto referente ao checkbox do header */ _checkRow(checkbox, selectedBar, tableCheckboxes, headerCheckbox) { const check = checkbox.checked this._setRow(checkbox, check) this._setSelectedBar(check ? 1 : -1, selectedBar, tableCheckboxes, headerCheckbox) } /** * Seleciona todas as linhas * @private * @param {object} tableCheckboxes - Objeto referente a lista de checkboxes */ _checkAllRows(tableCheckboxes) { for (const checkbox of tableCheckboxes) { this._setRow(checkbox, true) } } /** * Desseleciona todas as linhas * @private * @param {object} tableCheckboxes - Objeto referente a lista de checkboxes */ _uncheckAllRows(tableCheckboxes) { for (const checkbox of tableCheckboxes) { this._setRow(checkbox, false) } } /** * Seleciona toda a tabela * @private * @param {object} selectedBar - Objeto referente a barra contextual * @param {object} tableCheckboxes - Objeto referente a lista de checkboxes * @param {object} headerCheckbox - Objeto referente ao checkbox do header */ _checkAllTable(selectedBar, tableCheckboxes, headerCheckbox) { let count = tableCheckboxes.length const infoCount = selectedBar.querySelector('.info .count') const total = parseInt(infoCount.innerHTML, 10) if (total === count) { this._uncheckAllRows(tableCheckboxes) count = -1 * count } else { this._checkAllRows(tableCheckboxes) } this._setSelectedBar(count, selectedBar, tableCheckboxes, headerCheckbox) } /** * Define visualização dos itens selecionados na barra contextual * @private * @param {number} count - número de itens selecionados * @param {object} selectedBar - Objeto referente a barra contextual * @param {object} tableCheckboxes - Objeto referente a lista de checkboxes * @param {object} headerCheckbox - Objeto referente ao checkbox do header */ _setSelectedBar(count, selectedBar, tableCheckboxes, headerCheckbox) { const infoCount = selectedBar.querySelector('.info .count') const infoText = selectedBar.querySelector('.info .text') const total = count < 2 ? parseInt(infoCount.innerHTML, 10) + count : count if (total > 0) { selectedBar.classList.add('show') infoCount.innerHTML = total infoText.innerHTML = total > 1 ? 'itens selecionados' : 'item selecionado' if (headerCheckbox) headerCheckbox.parentNode.classList.add('is-checking') if (total === tableCheckboxes.length) { if (headerCheckbox) { headerCheckbox.checked = true headerCheckbox.parentNode.classList.remove('is-checking') } } } else { infoCount.innerHTML = 0 if (headerCheckbox) { headerCheckbox.checked = false headerCheckbox.parentNode.classList.remove('is-checking') } selectedBar.classList.remove('show') } } } export default BRTable