import { LitElement, PropertyValues, html, nothing, svg } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; import '@digital-realty/ix-icon-button/ix-icon-button.js'; import '@digital-realty/ix-icon/ix-icon.js'; import '@digital-realty/ix-switch/ix-switch.js'; import { IxGridViewStyles } from '../grid-view-styles.js'; import { IxGridColumnFilterStyles } from './grid-column-filter-styles.js'; import type { Column } from '../IxGrid.js'; const triggerKeys = [' ', 'Enter']; const handleIcon = svg` `; @customElement('ix-grid-column-filter') export class IxGridColumnFilter extends LitElement { static readonly styles = [IxGridViewStyles, IxGridColumnFilterStyles]; @query('.dropdown-content') dropdown!: HTMLElement; @property({ type: Array }) columns: Column[] = []; @property({ type: String }) columnsLocalStorageKey: string | undefined = undefined; @property({ type: Boolean }) columnReorderingAllowed: boolean = false; @property({ type: Boolean }) refreshDataOnColumnVisibilityChange: boolean = true; @property({ attribute: false }) requestGridUpdate: any; @state() private isDropdownVisible: boolean = false; @state() disabledColumns: string[] = []; @state() dragEvent: { sourceEl: HTMLElement | null; startId: number; targetId: number; } = { sourceEl: null, startId: -1, targetId: -1, }; connectedCallback() { super.connectedCallback(); document.addEventListener('click', this.outerInteraction); this.initializeLocalStorage(); } disconnectedCallback() { super.disconnectedCallback(); document.removeEventListener('click', this.outerInteraction); } outerInteraction = (e: Event) => { if (!e.composedPath().includes(this)) { this.isDropdownVisible = false; } }; get preservedColumns() { let preservedColumns: Column[] = []; if (this.columnsLocalStorageKey) { preservedColumns = JSON.parse( localStorage.getItem(this.columnsLocalStorageKey) || '[]' ); } return preservedColumns; } initializeLocalStorage() { if (this.preservedColumns.length > 0) { this.disabledColumns = this.preservedColumns .filter(c => c.hidden && this.columns.some(col => col.name === c.name)) .map(c => c.name); this.columns.forEach((column, id) => { if (this.disabledColumns.includes(column.name)) { this.columns[id].hidden = true; } }); } this.dispatchUpdate(); } protected update(changedProperties: PropertyValues): void { super.update(changedProperties); if (changedProperties.has('columnsLocalStorageKey')) { this.initializeLocalStorage(); } } toggleColumn(id: number) { this.columns[id].hidden = !this.columns[id].hidden; this.disabledColumns = this.columns .filter((column: Column) => column.hidden) .map((column: Column) => column.name); if (this.columnsLocalStorageKey) { localStorage.setItem( this.columnsLocalStorageKey, JSON.stringify([...this.columns]) ); } this.dispatchUpdate(); } updateColumn(e: Event, id: number) { const input = e.target as HTMLElement; const el = input.shadowRoot?.querySelector('input'); if (this.columns[id].hidden !== !el?.checked) { this.dispatchEvent( new CustomEvent('columnVisibilityChange', { detail: { column: this.columns[id], }, bubbles: true, composed: true, }) ); } this.columns[id].hidden = !el?.checked; this.disabledColumns = this.columns .filter((column: Column) => column.hidden) .map((column: Column) => column.name); if (this.columnsLocalStorageKey) { localStorage.setItem( this.columnsLocalStorageKey, JSON.stringify([...this.columns]) ); } this.dispatchUpdate(); } dispatchUpdate(columns = this.columns) { this.dispatchEvent( new CustomEvent('columnFilter', { detail: { columns, }, bubbles: true, composed: true, }) ); } dragstart(e: DragEvent) { if (this.columnReorderingAllowed) { const el = e.target as HTMLElement; this.dragEvent.sourceEl = el; el.style.opacity = '0.3'; const id = Number(el.getAttribute('data-id') as string); this.dragEvent.startId = id; } } dragend() { if (this.columnReorderingAllowed) { if (this.dragEvent.startId !== this.dragEvent.targetId) { const reorderedColumns = [...this.columns]; const el = reorderedColumns.splice(this.dragEvent.startId, 1)[0]; reorderedColumns.splice(this.dragEvent.targetId, 0, el); this.dispatchEvent( new CustomEvent('reorderColumns', { detail: { reorderedColumns, }, bubbles: true, composed: true, }) ); } this.dragEvent.sourceEl?.style.removeProperty('opacity'); this.dragEvent = { sourceEl: null, startId: -1, targetId: -1, }; } } dragenter(e: DragEvent) { if (this.columnReorderingAllowed) { const el = e.target as HTMLElement; if (el.classList.contains('drag-target')) { const target = Number(el.getAttribute('data-id') as string); this.dragEvent.targetId = target; } } } handleDropdownToggle(e: Event | KeyboardEvent) { if (e instanceof KeyboardEvent && !triggerKeys.includes(e.key)) { return; } const dropdownListInteraction = e.composedPath().includes(this.dropdown); if (!dropdownListInteraction) { this.isDropdownVisible = !this.isDropdownVisible; } } render() { return html`
${this.disabledColumns.length > 0 ? html`
` : nothing} ${this.isDropdownVisible ? html` ` : nothing}
`; } }