Files
pulse-signage/src/web/lib/list-query.js
T
2026-08-01 21:41:44 +01:00

106 lines
3.0 KiB
JavaScript

// Shared helpers for parsing and sorting web list query state.
function parsePageNumber(value) {
const pageNumber = Math.floor(Number(value) || 1);
return Math.max(1, pageNumber);
}
function getSearchQuery(req) {
return String(req && req.query && req.query.search || '').trim();
}
function getSortQuery(req) {
return String(req && req.query && req.query.sort || '').trim();
}
function getSortDirectionQuery(req) {
return String(req && req.query && req.query.direction || '').trim().toLowerCase() === 'desc' ? 'desc' : 'asc';
}
function normalizeSortDirection(value) {
return String(value || '').trim().toLowerCase() === 'desc' ? 'desc' : 'asc';
}
function getComparableSortValue(rawValue) {
const value = String(rawValue || '').trim();
if (!value) {
return { type: 'empty', value: '' };
}
const numericValue = Number(value.replace(/,/g, ''));
if (!Number.isNaN(numericValue)) {
return { type: 'number', value: numericValue };
}
const dateValue = Date.parse(value);
if (!Number.isNaN(dateValue)) {
return { type: 'date', value: dateValue };
}
return { type: 'string', value: value.toLowerCase() };
}
function compareSortValues(leftValue, rightValue) {
if (leftValue.type === 'empty' && rightValue.type === 'empty') {
return 0;
}
if (leftValue.type === 'empty') {
return 1;
}
if (rightValue.type === 'empty') {
return -1;
}
if (leftValue.type === rightValue.type) {
if (leftValue.value < rightValue.value) {
return -1;
}
if (leftValue.value > rightValue.value) {
return 1;
}
return 0;
}
return String(leftValue.value).localeCompare(String(rightValue.value), undefined, { numeric: true, sensitivity: 'base' });
}
function sortRows(rows, accessor, sortDirection) {
const multiplier = normalizeSortDirection(sortDirection) === 'desc' ? -1 : 1;
return (Array.isArray(rows) ? rows.slice() : []).sort(function (leftRow, rightRow) {
return compareSortValues(getComparableSortValue(accessor(leftRow)), getComparableSortValue(accessor(rightRow))) * multiplier;
});
}
function createSearchMatcher(searchTerm, fields) {
const query = String(searchTerm || '').trim().toLowerCase();
if (!query) {
return function () {
return true;
};
}
const normalizedFields = Array.isArray(fields) ? fields : [];
return function (item) {
const haystack = normalizedFields.map(function (field) {
if (typeof field === 'function') {
return field(item);
}
return item && field ? item[field] : '';
}).map(function (value) {
return String(value || '').trim().toLowerCase();
}).join(' ');
return haystack.indexOf(query) !== -1;
};
}
module.exports = {
parsePageNumber: parsePageNumber,
getSearchQuery: getSearchQuery,
getSortQuery: getSortQuery,
normalizeSortDirection: normalizeSortDirection,
getSortDirectionQuery: getSortDirectionQuery,
getComparableSortValue: getComparableSortValue,
compareSortValues: compareSortValues,
sortRows: sortRows,
createSearchMatcher: createSearchMatcher
};