diff --git a/src/js/modules/Filter/defaults/filters.js b/src/js/modules/Filter/defaults/filters.js index 4c8bc44ff..7ec13600b 100644 --- a/src/js/modules/Filter/defaults/filters.js +++ b/src/js/modules/Filter/defaults/filters.js @@ -105,4 +105,111 @@ export default { return false; } }, -}; \ No newline at end of file + + // Smart filter + // Supports ., !, <, >, <=, >=, = and falls back to like filter + "smart": function (filterVal, rowVal, rowData, filterParams) { + const search = filterVal.trim(); + + // searching . returns all non-empty cells + if (search === ".") return !(rowVal === null || rowVal == ""); + // searching ! returns all empty cells + if (search === "!") return rowVal === null || rowVal == ""; + + // number comparisons - use existing filters + if (search.indexOf("<=") === 0) + return this["<="]( + parseFloat(search.substring(2)), + rowVal, + rowData, + filterParams + ); + if (search.indexOf(">=") === 0) + return this[">="]( + parseFloat(search.substring(2)), + rowVal, + rowData, + filterParams + ); + if (search.indexOf("<") === 0) + return this["<"]( + parseFloat(search.substring(1)), + rowVal, + rowData, + filterParams + ); + if (search.indexOf(">") === 0) + return this[">"]( + parseFloat(search.substring(1)), + rowVal, + rowData, + filterParams + ); + if (search.indexOf("=") === 0) + return this["="](search.substring(1).trim(), rowVal, rowData, filterParams); + + // we got a string like "ne ci" + // convert this to "ne AND ci" to find "New York City" + if (search.includes(" ")) { + // Split by spaces and join with AND for fuzzy search + const terms = search.split(/\s+/).filter((term) => term.length > 0); + if (terms.length > 1) { + const fuzzySearch = terms.join(" AND "); + return this["smarter"](fuzzySearch, rowVal, rowData, filterParams); + } + } + + // otherwise we use the regular like filter + return this["like"](search, rowVal, rowData, filterParams); + }, + + // Smarter filter + // Just like the smart filter but you can combine multiple filters (AND/OR) + // Examples: + // - "john AND smith" - both terms must match + // - "john OR jane" - either term must match + // - ">100 AND <500" - value must be between 100 and 500 + // - "! OR foo" - either empty or foo + "smarter": function (filterVal, rowVal, rowData, filterParams) { + const search = filterVal.trim(); + + // If no search value, show all rows + if (!search) return true; + + // Split by AND/OR operators while preserving the operators + const parts = search.split(/\s+(AND|OR)\s+/i); + + // If no operators found, use the original smart filter + if (parts.length === 1) { + return this["smart"](search, rowVal, rowData, filterParams); + } + + // Process each part and operator + let result = null; + let currentOperator = null; + + for (let i = 0; i < parts.length; i++) { + const part = parts[i].trim(); + + if (part === "AND" || part === "OR") { + currentOperator = part; + continue; + } + + // Apply the smart filter to this part + const partResult = this["smart"](part, rowVal, rowData, filterParams); + + // Combine results based on operator + if (result === null) { + result = partResult; + } else if (currentOperator === "AND") { + result = result && partResult; + } else if (currentOperator === "OR") { + result = result || partResult; + } + } + + return result !== null ? result : true; + }, + +};