UNPKG

sematable

Version:

Client side sorting, pagination, and text filter for redux/react based apps

313 lines (268 loc) 10.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _reselect = require('reselect'); var _common = require('./common'); var _PageSize = require('./PageSize'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function paginate(rows, _ref) { var page = _ref.page, pageSize = _ref.pageSize; if (pageSize < 1) { return rows.slice(0); } var start = page * pageSize; return rows.slice(start, start + pageSize); } /** * rows - original data * filters - list of selected filters * filterText - currently entered text in filter input * columns - column definitions */ function filter() { var rows = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var filters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var filterText = arguments[2]; var columns = arguments[3]; var filteredRows = rows.slice(0); if (filters.length === 0 && !filterText) { return filteredRows; } var filtersArr = _lodash2.default.isArray(filters) ? filters : [filters]; var textFilters = [].concat(_toConsumableArray(filterText ? [filterText.toLowerCase()] : []), _toConsumableArray(filtersArr.filter(function (f) { return f.textFilter; }).map(function (f) { return f.value; }))); var valueFilters = filtersArr.filter(function (f) { return f.valueFilter; }); // apply text filters across all columns if (textFilters.length > 0) { filteredRows = _lodash2.default.filter(rows, function (row) { return _lodash2.default.some(columns, function (column) { if (!column.searchable) { return false; } var normalized = String(_lodash2.default.get(row, column.key)).toLowerCase(); return _lodash2.default.every(textFilters, function (f) { return normalized.indexOf(f) > -1; }); }); }); } // apply value filters on filterable columns if (valueFilters.length > 0) { var groups = _lodash2.default.groupBy(valueFilters, 'key'); filteredRows = _lodash2.default.filter(filteredRows, function (row) { return _lodash2.default.every(groups, function (groupFilters, groupKey) { var value = _lodash2.default.get(row, groupKey); return _lodash2.default.some(groupFilters, function (f) { return f.value === value; }); }); }); } return filteredRows; } function sort(rows, _ref2) { var sortKey = _ref2.sortKey, direction = _ref2.direction; var cloned = rows.slice(0); if (!sortKey) { return cloned; } return cloned.sort(function (a, b) { var sortVal = 0; var valueA = _lodash2.default.get(a, sortKey); var valueB = _lodash2.default.get(b, sortKey); if (valueA > valueB || valueB === undefined) { sortVal = 1; } else if (valueA < valueB || valueA === undefined) { sortVal = -1; } if (direction === 'desc') { sortVal *= -1; } return sortVal; }); } var selectors = {}; // wrapped in function as we use the same selectors for multiple tables // if we don't wrap selectors like this, they would never memoize/cache results // as we use it for multiple tables (each table has different state) exports.default = function (tableName) { if (selectors[tableName]) { return selectors[tableName]; } var tableProp = function tableProp(state, prop) { return state.sematable[tableName] ? _lodash2.default.get(state.sematable[tableName], prop) : undefined; }; var tableOrComponentProp = function tableOrComponentProp(state, props, prop) { if (props && props[prop] !== undefined) { return props[prop]; } return state.sematable[tableName] ? _lodash2.default.get(state.sematable[tableName], prop) : undefined; }; var getIsInitialized = function getIsInitialized(state) { return state.sematable[tableName] !== undefined; }; var getInitialData = function getInitialData(state) { return tableProp(state, 'initialData'); }; var getEditing = function getEditing(state) { return tableProp(state, 'editing'); }; var getFilter = function getFilter(state) { return tableProp(state, 'filter'); }; var getFilterText = function getFilterText(state) { return tableProp(state, 'filterText'); }; var getColumns = function getColumns(state) { return tableProp(state, 'columns'); }; var getPage = function getPage(state) { return tableProp(state, 'page'); }; var getPrimaryKey = function getPrimaryKey(state) { return tableProp(state, 'primaryKey'); }; var getPageSize = function getPageSize(state, props) { return tableOrComponentProp(state, props, 'pageSize'); }; var getPageSizes = function getPageSizes(state) { return tableProp(state, 'pageSizes'); }; var getUserSelection = function getUserSelection(state) { return tableProp(state, 'userSelection'); }; var getSelectAll = function getSelectAll(state) { return tableProp(state, 'selectAll'); }; var getSortInfo = function getSortInfo(state) { return { sortKey: tableProp(state, 'sortKey'), direction: tableProp(state, 'direction') }; }; var getSelectEnabled = function getSelectEnabled(state) { return tableProp(state, 'configs.selectEnabled'); }; var getFilterClassNamePrefix = function getFilterClassNamePrefix(state) { return tableProp(state, 'configs.filterClassNamePrefix'); }; var getFiltered = (0, _reselect.createSelector)(getInitialData, getFilter, getFilterText, getColumns, function (initialData, filters, filterText, columns) { return filter(initialData, filters, filterText, columns); }); var getFilterOptions = (0, _reselect.createSelector)(getInitialData, getColumns, function (initialData, columns) { var options = []; var columnMap = _lodash2.default.keyBy(columns, 'key'); var values = {}; // set predefined values columns.forEach(function (column) { if (column.filterable && column.filterValues) { values[column.key] = column.filterValues; } }); // collect values for columns that don't have predefined values initialData.forEach(function (row) { columns.forEach(function (column) { if (!column.filterable || column.filterValues) { return; } if (!values[column.key]) { values[column.key] = []; } var columnValues = values[column.key]; var value = _lodash2.default.get(row, column.key); if (!columnValues.includes(value)) { columnValues.push(value); } }); }); _lodash2.default.forOwn(values, function (columnValues, key) { columnValues.forEach(function (value) { var column = columnMap[key]; options.push((0, _common.createValueFilter)(column, value)); }); }); return options; }); var getPageInfo = (0, _reselect.createSelector)(getPage, getPageSize, getFiltered, getPageSizes, function (page, pageSize, filtered, pageSizes) { if (pageSize === _PageSize.PAGE_SIZE_ALL_VALUE) { // we are showing all rows return { page: page, pageSize: pageSize, pageSizes: pageSizes, pageCount: 1 }; } var pageCount = Math.ceil(filtered.length / pageSize); // When initial data changes (and therefore filtered data), we might have // less data than before. If that's the case the current page value might // be invalid. We fix that by setting it to last page. var validPage = page; if (page > pageCount - 1) { validPage = pageCount - 1; } return { page: validPage, pageSize: pageSize, pageSizes: pageSizes, pageCount: pageCount }; }); var getSorted = (0, _reselect.createSelector)(getFiltered, getSortInfo, function (filtered, sortInfo) { return sort(filtered, sortInfo); }); var getVisible = (0, _reselect.createSelector)(getSorted, getPageInfo, function (sorted, pageInfo) { return paginate(sorted, pageInfo); }); var getSelectedRows = (0, _reselect.createSelector)(getFiltered, getColumns, getUserSelection, getSelectAll, getPrimaryKey, getSelectEnabled, function (filtered, columns, userSelection, selectAll, primaryKey, selectEnabled) { var includesKey = function includesKey(row) { return _lodash2.default.includes(userSelection, _lodash2.default.get(row, primaryKey)); }; if (selectAll) { var selectable = filtered; // if not all rows are selectable, apply selectEnabled function to filter selectable if (selectEnabled) { selectable = _lodash2.default.filter(selectable, selectEnabled); } if (_lodash2.default.isEmpty(userSelection)) { return selectable; } // when select all is enabled, userSelection acts as "not selected" rows return _lodash2.default.reject(selectable, includesKey); } // when select all is not enabled, userSelection acts as "selected" rows return _lodash2.default.filter(filtered, includesKey); }); var isTableEditing = (0, _reselect.createSelector)(getEditing, function (editing) { return editing; }); selectors[tableName] = { getInitialData: getInitialData, getIsInitialized: getIsInitialized, getFilter: getFilter, getFilterText: getFilterText, getColumns: getColumns, getSortInfo: getSortInfo, getPageInfo: getPageInfo, getVisible: getVisible, getSelectedRows: getSelectedRows, getSelectAll: getSelectAll, getPrimaryKey: getPrimaryKey, getFilterOptions: getFilterOptions, getFilterClassNamePrefix: getFilterClassNamePrefix, getFiltered: getFiltered, isTableEditing: isTableEditing }; return selectors[tableName]; };