diff --git a/index.html b/index.html
index 1a3588e..7a33202 100644
--- a/index.html
+++ b/index.html
@@ -99,6 +99,11 @@
data,
inlineFilters: true,
dynamicRowHeight: true,
+ // filterRows(keyword, cells, colIndex) {
+ // return cells
+ // .filter(cell => cell.content.includes(keyword))
+ // .map(cell => cell.rowIndex);
+ // },
getEditor(colIndex, rowIndex, value, parent) {
// editing obj only for date field
if (colIndex != 6) return;
diff --git a/src/cellmanager.js b/src/cellmanager.js
index c5b81bd..68260d2 100644
--- a/src/cellmanager.js
+++ b/src/cellmanager.js
@@ -13,6 +13,7 @@ export default class CellManager {
'wrapper',
'options',
'style',
+ 'header',
'bodyScrollable',
'columnmanager',
'rowmanager',
@@ -121,6 +122,10 @@ export default class CellManager {
this.activateFilter(colIndex);
return true;
});
+
+ $.on(this.header, 'focusin', '.dt-filter', () => {
+ this.unfocusCell(this.$focusedCell);
+ });
}
}
@@ -246,6 +251,19 @@ export default class CellManager {
this.highlightRowColumnHeader($cell);
}
+ unfocusCell($cell) {
+ if (!$cell) return;
+
+ // remove cell border
+ $cell.classList.remove('dt-cell--focus');
+ this.$focusedCell = null;
+
+ // reset header background
+ if (this.lastHeaders) {
+ this.lastHeaders.forEach(header => header.classList.remove('dt-cell--highlight'));
+ }
+ }
+
highlightRowColumnHeader($cell) {
const {
colIndex,
diff --git a/src/columnmanager.js b/src/columnmanager.js
index 8214795..58b4e47 100644
--- a/src/columnmanager.js
+++ b/src/columnmanager.js
@@ -269,24 +269,26 @@ export default class ColumnManager {
bindFilter() {
if (!this.options.inlineFilters) return;
const handler = e => {
- const $filterCell = $.closest('.dt-cell', e.target);
- const {
- colIndex
- } = $.data($filterCell);
+ this.$filterCell = $.closest('.dt-cell', e.target);
+ const { colIndex } = $.data(this.$filterCell);
const keyword = e.target.value;
- this.datamanager.filterRows(keyword, colIndex)
- .then(({
- rowsToHide,
- rowsToShow
- }) => {
- this.rowmanager.hideRows(rowsToHide);
- this.rowmanager.showRows(rowsToShow);
- });
+ this.applyFilter(keyword, colIndex);
};
$.on(this.header, 'keydown', '.dt-filter', debounce(handler, 300));
}
+ applyFilter(keyword, colIndex) {
+ this.datamanager.filterRows(keyword, colIndex)
+ .then(({
+ rowsToHide,
+ rowsToShow
+ }) => {
+ this.rowmanager.hideRows(rowsToHide);
+ this.rowmanager.showRows(rowsToShow);
+ });
+ }
+
applyDefaultSortOrder() {
// sort rows if any 1 column has a default sortOrder set
const columnsToSort = this.getColumns().filter(col => col.sortOrder !== 'none');
diff --git a/src/datamanager.js b/src/datamanager.js
index 6d38fee..d73cbaa 100644
--- a/src/datamanager.js
+++ b/src/datamanager.js
@@ -11,7 +11,6 @@ export default class DataManager {
this.sortRows = nextTick(this.sortRows, this);
this.switchColumn = nextTick(this.switchColumn, this);
this.removeColumn = nextTick(this.removeColumn, this);
- this.filterRows = nextTick(this.filterRows, this);
}
init(data, columns) {
@@ -423,31 +422,36 @@ export default class DataManager {
}
filterRows(keyword, colIndex) {
- let rowsToHide = [];
- let rowsToShow = [];
const cells = this.rows.map(row => row[colIndex]);
+ let result = this.options.filterRows(keyword, cells, colIndex);
- cells.forEach(cell => {
- const hay = String(cell.content || '').toLowerCase();
- const needle = (keyword || '').toLowerCase();
+ if (!result) {
+ result = this.getAllRowIndices();
+ }
- if (!needle || hay.includes(needle)) {
- rowsToShow.push(cell.rowIndex);
- } else {
- rowsToHide.push(cell.rowIndex);
- }
+ if (!result.then) {
+ result = Promise.resolve(result);
+ }
+
+ return result.then(rowsToShow => {
+ this._filteredRows = rowsToShow;
+
+ const rowsToHide = this.getAllRowIndices()
+ .filter(index => !rowsToShow.includes(index));
+
+ return {
+ rowsToHide,
+ rowsToShow
+ };
});
-
- this._filteredRows = rowsToShow;
-
- return {
- rowsToHide,
- rowsToShow
- };
}
getFilteredRowIndices() {
- return this._filteredRows || this.rows.map(row => row.meta.rowIndex);
+ return this._filteredRows || this.getAllRowIndices();
+ }
+
+ getAllRowIndices() {
+ return this.rows.map(row => row.meta.rowIndex);
}
getRowCount() {
diff --git a/src/defaults.js b/src/defaults.js
index 6742c98..ca10dd6 100644
--- a/src/defaults.js
+++ b/src/defaults.js
@@ -1,3 +1,5 @@
+import filterRows from './filterRows';
+
export default {
columns: [],
data: [],
@@ -40,6 +42,7 @@ export default {
desc: '↓',
none: ''
},
+ filterRows: filterRows,
freezeMessage: '',
getEditor: null,
serialNoColumn: true,
diff --git a/src/filterRows.js b/src/filterRows.js
new file mode 100644
index 0000000..fec0831
--- /dev/null
+++ b/src/filterRows.js
@@ -0,0 +1,93 @@
+import { isNumber } from './utils';
+
+export default function filterRows(keyword, cells, colIndex) {
+ let filter = guessFilter(keyword);
+ let filterMethod = getFilterMethod(filter);
+
+ if (filterMethod) {
+ return filterMethod(filter.text, cells);
+ }
+
+ return cells.map(cell => cell.rowIndex);
+};
+
+function getFilterMethod(filter) {
+ let filterMethodMap = {
+ contains(keyword, cells) {
+ return cells
+ .filter(cell => {
+ const hay = String(cell.content || '').toLowerCase();
+ const needle = (keyword || '').toLowerCase();
+ return !needle || hay.includes(needle);
+ })
+ .map(cell => cell.rowIndex);
+ },
+
+ greaterThan(keyword, cells) {
+ return cells
+ .filter(cell => {
+ const value = Number(cell.content);
+ return value > keyword;
+ })
+ .map(cell => cell.rowIndex);
+ },
+
+ lessThan(keyword, cells) {
+ return cells
+ .filter(cell => {
+ const value = Number(cell.content);
+ return value < keyword;
+ })
+ .map(cell => cell.rowIndex);
+ },
+
+ range(rangeValues, cells) {
+ return cells
+ .filter(cell => {
+ const value = Number(cell.content);
+ return value >= rangeValues[0] && value <= rangeValues[1];
+ })
+ .map(cell => cell.rowIndex);
+ }
+ };
+
+ return filterMethodMap[filter.type];
+}
+
+function guessFilter(keyword) {
+ if (keyword.length === 1) return {};
+
+ if (keyword.startsWith('>')) {
+ if (isNumber(keyword.slice(1))) {
+ return {
+ type: 'greaterThan',
+ text: Number(keyword.slice(1).trim())
+ };
+ }
+
+ keyword = keyword.slice(1);
+ }
+
+ if (keyword.startsWith('<')) {
+ if (isNumber(keyword.slice(1))) {
+ return {
+ type: 'lessThan',
+ text: Number(keyword.slice(1).trim())
+ };
+ }
+
+ keyword = keyword.slice(1);
+ }
+
+ if (keyword.split(':').length === 2 && keyword.split(':').every(isNumber)) {
+ return {
+ type: 'range',
+ text: keyword.split(':').map(v => v.trim()).map(Number)
+ };
+ }
+
+ return {
+ type: 'contains',
+ text: keyword.toLowerCase()
+ };
+}
diff --git a/src/rowmanager.js b/src/rowmanager.js
index 881f32d..c161aa5 100644
--- a/src/rowmanager.js
+++ b/src/rowmanager.js
@@ -277,7 +277,7 @@ export default class RowManager {
getFilterInput(props) {
const dataAttr = makeDataAttributeString(props);
- return ``;
+ return ``;
}
selector(rowIndex) {