(function (app) { 'use strict'; // A filter is per-column and has one of two shapes: // - free-text: { kind: 'contains', value: '' } // - enum: { kind: 'enum', value: ['', ...] } // An empty value (empty string or empty array) matches everything. // // The render layer only emits the free-text shape; enum is kept here // for back-compat with any inline-context test fixtures that seed // filter state directly. defaultFilterFor always returns text. function isEnumColumn(col) { return Array.isArray(col.enum) && col.enum.length > 0; } function defaultFilterFor(_col) { return { kind: 'contains', value: '' }; } function rowMatches(filter, cellValue) { if (filter.kind === 'enum') { if (!Array.isArray(filter.value) || filter.value.length === 0) { return true; } const s = cellValue == null ? '' : String(cellValue); return filter.value.indexOf(s) !== -1; } // contains if (!filter.value) { return true; } const needle = String(filter.value).toLowerCase(); const hay = cellValue == null ? '' : String(cellValue).toLowerCase(); return hay.indexOf(needle) !== -1; } function isEmpty(filter) { if (filter.kind === 'enum') { return !Array.isArray(filter.value) || filter.value.length === 0; } return !filter.value; } function apply(rows, columns, filterMap, resolveField) { return rows.filter(function (row) { for (let i = 0; i < columns.length; i++) { const col = columns[i]; const filter = filterMap[col.field]; if (!filter || isEmpty(filter)) { continue; } const cellValue = resolveField(row.data, col.field); if (!rowMatches(filter, cellValue)) { return false; } } return true; }); } app.modules.filters = { defaultFilterFor: defaultFilterFor, isEnumColumn: isEnumColumn, isEmpty: isEmpty, apply: apply }; })(window.tablesApp);