1
0
Fork 0
mirror of https://github.com/koalyptus/TableFilter.git synced 2024-06-03 14:32:21 +02:00
TableFilter/docs/file/src/tablefilter.js.html
koalyptus 4481fbe361 publish Docs to gh-pages (auto)
branch:       master
SHA:          c7d6de72f7
range SHA:    81f31a3106fb...c7d6de72f785
build id:     375208741
build number: 1103
2018-05-05 08:21:30 +00:00

3242 lines
116 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<base data-ice="baseUrl" href="../../">
<title data-ice="title">src/tablefilter.js | tablefilter</title>
<link type="text/css" rel="stylesheet" href="css/style.css">
<link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css">
<script src="script/prettify/prettify.js"></script>
<script src="script/manual.js"></script>
<meta name="description" content="A Javascript library making HTML tables filterable and a bit more"><meta property="twitter:card" content="summary"><meta property="twitter:title" content="tablefilter"><meta property="twitter:description" content="A Javascript library making HTML tables filterable and a bit more"></head>
<body class="layout-container" data-ice="rootContainer">
<header>
<a href="./">Home</a>
<a href="identifiers.html">Reference</a>
<a href="source.html">Source</a>
<div class="search-box">
<span>
<img src="./image/search.png">
<span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span>
</span>
<ul class="search-result"></ul>
</div>
<a style="position:relative; top:3px;" href="https://github.com/koalyptus/TableFilter.git"><img width="20px" src="./image/github.png"></a></header>
<nav class="navigation" data-ice="nav"><div>
<ul>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/emitter.js~Emitter.html">Emitter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/feature.js~Feature.html">Feature</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/tablefilter.js~TableFilter.html">TableFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-has">has</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-addClass">addClass</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createCheckItem">createCheckItem</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createElm">createElm</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createOpt">createOpt</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createText">createText</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-elm">elm</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getFirstTextNode">getFirstTextNode</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getText">getText</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-hasClass">hasClass</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-removeClass">removeClass</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-removeElm">removeElm</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-tag">tag</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-addEvt">addEvt</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-cancelEvt">cancelEvt</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isKeyPressed">isKeyPressed</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-keyCode">keyCode</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-removeEvt">removeEvt</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-stopEvt">stopEvt</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-targetEvt">targetEvt</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-parse">parse</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-defaultsArr">defaultsArr</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-defaultsBool">defaultsBool</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-defaultsFn">defaultsFn</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-defaultsNb">defaultsNb</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-defaultsStr">defaultsStr</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-dateSortAsc">dateSortAsc</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-dateSortDesc">dateSortDesc</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-ignoreCase">ignoreCase</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-numSortAsc">numSortAsc</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-numSortDesc">numSortDesc</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-sortDateStr">sortDateStr</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-sortNumberStr">sortNumberStr</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-contains">contains</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isEmpty">isEmpty</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-matchCase">matchCase</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-rgxEsc">rgxEsc</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-trim">trim</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-EMPTY_FN">EMPTY_FN</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isArray">isArray</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isBoolean">isBoolean</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isEmpty">isEmpty</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isFn">isFn</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isNull">isNull</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isNumber">isNumber</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isObj">isObj</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isString">isString</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isUndef">isUndef</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-AUTO_FILTER_DELAY">AUTO_FILTER_DELAY</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-CELL_TAG">CELL_TAG</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-CHECKLIST">CHECKLIST</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-DATE">DATE</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-DOWN_ARROW_KEY">DOWN_ARROW_KEY</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-ENTER_KEY">ENTER_KEY</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-ESC_KEY">ESC_KEY</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-FEATURES">FEATURES</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-FORMATTED_NUMBER">FORMATTED_NUMBER</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-HEADER_TAG">HEADER_TAG</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-INPUT">INPUT</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-IP_ADDRESS">IP_ADDRESS</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-MULTIPLE">MULTIPLE</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-NONE">NONE</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-NUMBER">NUMBER</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-SELECT">SELECT</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-STRING">STRING</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-TAB_KEY">TAB_KEY</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-UP_ARROW_KEY">UP_ARROW_KEY</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-root">root</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extensions-advancedgrid">extensions/advancedGrid</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extensions/advancedGrid/adapterEzEditTable.js~AdapterEzEditTable.html">AdapterEzEditTable</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extensions-colops">extensions/colOps</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extensions/colOps/colOps.js~ColOps.html">ColOps</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extensions-colsvisibility">extensions/colsVisibility</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extensions/colsVisibility/colsVisibility.js~ColsVisibility.html">ColsVisibility</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extensions-filtersvisibility">extensions/filtersVisibility</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extensions/filtersVisibility/filtersVisibility.js~FiltersVisibility.html">FiltersVisibility</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extensions-sort">extensions/sort</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extensions/sort/adapterSortabletable.js~AdapterSortableTable.html">AdapterSortableTable</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#modules">modules</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/alternateRows.js~AlternateRows.html">AlternateRows</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/baseDropdown.js~BaseDropdown.html">BaseDropdown</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/checkList.js~CheckList.html">CheckList</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/clearButton.js~ClearButton.html">ClearButton</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/dateType.js~DateType.html">DateType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/dropdown.js~Dropdown.html">Dropdown</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/gridLayout.js~GridLayout.html">GridLayout</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/hash.js~Hash.html">Hash</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/help.js~Help.html">Help</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/highlightKeywords.js~HighlightKeyword.html">HighlightKeyword</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/loader.js~Loader.html">Loader</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/markActiveColumns.js~MarkActiveColumns.html">MarkActiveColumns</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/noResults.js~NoResults.html">NoResults</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/paging.js~Paging.html">Paging</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/popupFilter.js~PopupFilter.html">PopupFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/rowsCounter.js~RowsCounter.html">RowsCounter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/state.js~State.html">State</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/statusBar.js~StatusBar.html">StatusBar</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/storage.js~Storage.html">Storage</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/modules/toolbar.js~Toolbar.html">Toolbar</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-hasHashChange">hasHashChange</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-hasStorage">hasStorage</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-CENTER">CENTER</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LEFT">LEFT</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RIGHT">RIGHT</a></span></span></li>
</ul>
</div>
</nav>
<div class="content" data-ice="content"><h1 data-ice="title">src/tablefilter.js</h1>
<pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">import {addEvt, cancelEvt, stopEvt, targetEvt, isKeyPressed} from &apos;./event&apos;;
import {
addClass, createElm, createOpt, elm, getText, getFirstTextNode,
removeClass, tag
} from &apos;./dom&apos;;
import {contains, matchCase, rgxEsc, trim} from &apos;./string&apos;;
import {isEmpty as isEmptyString} from &apos;./string&apos;;
import {
isArray, isEmpty, isFn, isNumber, isObj, isString, isUndef, EMPTY_FN,
isBoolean
} from &apos;./types&apos;;
import {parse as parseNb} from &apos;./number&apos;;
import {
defaultsBool, defaultsStr, defaultsFn,
defaultsNb, defaultsArr
} from &apos;./settings&apos;;
import {root} from &apos;./root&apos;;
import {Emitter} from &apos;./emitter&apos;;
import {Dropdown} from &apos;./modules/dropdown&apos;;
import {CheckList} from &apos;./modules/checkList&apos;;
import {
INPUT, SELECT, MULTIPLE, CHECKLIST, NONE,
ENTER_KEY, TAB_KEY, ESC_KEY, UP_ARROW_KEY, DOWN_ARROW_KEY,
CELL_TAG, AUTO_FILTER_DELAY, NUMBER, DATE, FORMATTED_NUMBER,
FEATURES
} from &apos;./const&apos;;
let doc = root.document;
/**
* Makes HTML tables filterable and a bit more :)
*
* @export
* @class TableFilter
*/
export class TableFilter {
/**
* Creates an instance of TableFilter
* requires `table` or `id` arguments, `row` and `configuration` optional
* @param {HTMLTableElement} table Table DOM element
* @param {String} id Table id
* @param {Number} row index indicating the 1st row
* @param {Object} configuration object
*/
constructor(...args) {
/**
* ID of current instance
* @type {String}
* @private
*/
this.id = null;
/**
* Current version
* @type {String}
*/
this.version = &apos;{VERSION}&apos;;
/**
* Current year
* @type {Number}
* @private
*/
this.year = new Date().getFullYear();
/**
* HTML Table DOM element
* @type {DOMElement}
* @private
*/
this.tbl = null;
/**
* Calculated row&apos;s index from which starts filtering once filters
* are generated
* @type {Number}
*/
this.refRow = null;
/**
* Index of the headers row
* @type {Number}
* @private
*/
this.headersRow = null;
/**
* Configuration object
* @type {Object}
* @private
*/
this.cfg = {};
/**
* Number of rows that can be filtered
* @type {Number}
* @private
*/
this.nbFilterableRows = 0;
/**
* Number of cells in the reference row
* @type {Number}
* @private
*/
this.nbCells = null;
/**
* Has a configuration object
* @type {Object}
* @private
*/
this.hasConfig = false;
/** @private */
this.initialized = false;
let startRow;
// TODO: use for-of
args.forEach((arg) =&gt; {
if (typeof arg === &apos;object&apos; &amp;&amp; arg.nodeName === &apos;TABLE&apos;) {
this.tbl = arg;
this.id = arg.id || `tf_${new Date().getTime()}_`;
this.tbl.id = this.id;
} else if (isString(arg)) {
this.id = arg;
this.tbl = elm(arg);
} else if (isNumber(arg)) {
startRow = arg;
} else if (isObj(arg)) {
this.cfg = arg;
this.hasConfig = true;
}
});
if (!this.tbl || this.tbl.nodeName !== &apos;TABLE&apos;) {
throw new Error(`Could not instantiate TableFilter: HTML table
DOM element not found.`);
}
if (this.getRowsNb(true) === 0) {
throw new Error(`Could not instantiate TableFilter: HTML table
requires at least 1 row.`);
}
// configuration object
let f = this.cfg;
/**
* Event emitter instance
* @type {Emitter}
*/
this.emitter = new Emitter();
// start row
this.refRow = isUndef(startRow) ? 2 : (startRow + 1);
/**
* Collection of filter type by column
* @type {Array}
* @private
*/
this.filterTypes = [].map.call(
(this.dom().rows[this.refRow] || this.dom().rows[0]).cells,
(cell, idx) =&gt; {
let colType = this.cfg[`col_${idx}`];
return !colType ? INPUT : colType.toLowerCase();
});
/**
* Base path for static assets
* @type {String}
*/
this.basePath = defaultsStr(f.base_path, &apos;tablefilter/&apos;);
/*** filters&apos; grid properties ***/
/**
* Enable/disable filters
* @type {Boolean}
*/
this.fltGrid = defaultsBool(f.grid, true);
/**
* Enable/disable grid layout (fixed headers)
* @type {Object|Boolean}
*/
this.gridLayout = isObj(f.grid_layout) || Boolean(f.grid_layout);
/**
* Filters row index
* @type {Number}
*/
this.filtersRowIndex = defaultsNb(f.filters_row_index, 0);
/**
* Headers row index
* @type {Number}
*/
this.headersRow = defaultsNb(f.headers_row_index,
(this.filtersRowIndex === 0 ? 1 : 0));
/**
* Define the type of cell containing a filter (td/th)
* @type {String}
*/
this.fltCellTag = defaultsStr(f.filters_cell_tag, CELL_TAG);
/**
* List of filters IDs
* @type {Array}
* @private
*/
this.fltIds = [];
/**
* List of valid rows indexes (rows visible upon filtering)
* @type {Array}
* @private
*/
this.validRowsIndex = [];
/*** filters&apos; grid appearance ***/
/**
* Path for stylesheets
* @type {String}
*/
this.stylePath = this.getStylePath();
/**
* Main stylesheet path
* @type {String}
*/
this.stylesheet = this.getStylesheetPath();
/**
* Main stylesheet ID
* @type {String}
* @private
*/
this.stylesheetId = this.id + &apos;_style&apos;;
/**
* Css class for the filters row
* @type {String}
*/
this.fltsRowCssClass = defaultsStr(f.flts_row_css_class, &apos;fltrow&apos;);
/**
* Enable/disable icons (paging, reset button)
* @type {Boolean}
*/
this.enableIcons = defaultsBool(f.enable_icons, true);
/**
* Enable/disable alternating rows
* @type {Boolean}
*/
this.alternateRows = Boolean(f.alternate_rows);
/**
* Columns widths array
* @type {Array}
*/
this.colWidths = defaultsArr(f.col_widths, []);
/**
* Default column width when column widths are defined
*/
this.defaultColWidth = defaultsNb(f.default_col_width, 100);
/**
* Css class for a filter element
* @type {String}
*/
this.fltCssClass = defaultsStr(f.flt_css_class, &apos;flt&apos;);
/**
* Css class for multiple select filters
* @type {String}
*/
this.fltMultiCssClass = defaultsStr(f.flt_multi_css_class, &apos;flt_multi&apos;);
/**
* Css class for small filter (when submit button is active)
* @type {String}
*/
this.fltSmallCssClass = defaultsStr(f.flt_small_css_class, &apos;flt_s&apos;);
/**
* Css class for single filter type
* @type {String}
*/
this.singleFltCssClass = defaultsStr((f.single_filter || {}).css_class,
&apos;single_flt&apos;);
/*** filters&apos; grid behaviours ***/
/**
* Enable/disable enter key for input type filters
* @type {Boolean}
*/
this.enterKey = defaultsBool(f.enter_key, true);
/**
* Callback fired before filtering process starts
* @type {Function}
*/
this.onBeforeFilter = defaultsFn(f.on_before_filter, EMPTY_FN);
/**
* Callback fired after filtering process is completed
* @type {Function}
*/
this.onAfterFilter = defaultsFn(f.on_after_filter, EMPTY_FN);
/**
* Enable/disable case sensitivity filtering
* @type {Boolean}
*/
this.caseSensitive = Boolean(f.case_sensitive);
/**
* Indicate whether exact match filtering is enabled on a per column
* basis
* @type {Boolean}
* @private
*/
this.hasExactMatchByCol = isArray(f.columns_exact_match);
/**
* Exact match filtering per column array
* @type {Array}
*/
this.exactMatchByCol = this.hasExactMatchByCol ?
f.columns_exact_match : [];
/**
* Globally enable/disable exact match filtering
* @type {Boolean}
*/
this.exactMatch = Boolean(f.exact_match);
/**
* Ignore diacritics globally or on a column basis
* @type {Boolean|Array}
*/
this.ignoreDiacritics = f.ignore_diacritics;
/**
* Enable/disable linked filters filtering mode
* @type {Boolean}
*/
this.linkedFilters = Boolean(f.linked_filters);
/**
* Enable/disable readonly state for excluded options when
* linked filters filtering mode is on
* @type {Boolean}
*/
this.disableExcludedOptions = Boolean(f.disable_excluded_options);
/**
* Active filter ID
* @type {String}
* @private
*/
this.activeFilterId = null;
/**
* Determine if there are excluded rows from filtering
* @type {Boolean}
* @private
*/
this.hasExcludedRows = Boolean(isArray(f.exclude_rows) &amp;&amp;
f.exclude_rows.length &gt; 0);
/**
* List of row indexes to be excluded from filtering
* @type {Array}
*/
this.excludeRows = defaultsArr(f.exclude_rows, []);
/**
* List of containers IDs where external filters will be generated
* @type {Array}
*/
this.externalFltIds = defaultsArr(f.external_flt_ids, []);
/**
* Callback fired after filters are generated
* @type {Function}
*/
this.onFiltersLoaded = defaultsFn(f.on_filters_loaded, EMPTY_FN);
/**
* Enable/disable single filter mode
* @type {Boolean|Object}
*/
this.singleFlt = isObj(f.single_filter) ||
Boolean(f.single_filter);
/**
* Specify columns to be excluded from single filter search, by default
* searching in all columns:
* single_filter: {
* exclude_cols: [2, 7]
* }
*/
this.singleFltExcludeCols = isObj(f.single_filter) &amp;&amp;
isArray(f.single_filter.exclude_cols) ?
f.single_filter.exclude_cols : [];
/**
* Callback fired after a row is validated during filtering
* @type {Function}
*/
this.onRowValidated = defaultsFn(f.on_row_validated, EMPTY_FN);
/**
* Specify which column implements a custom cell parser to retrieve the
* cell value:
* cell_parser: {
* cols: [0, 2],
* parse: function(tf, cell, colIndex) {
* // custom cell parser logic here
* return cellValue;
* }
* }
* @type {Object}
*/
this.cellParser = isObj(f.cell_parser) &amp;&amp; isFn(f.cell_parser.parse) &amp;&amp;
isArray(f.cell_parser.cols) ?
f.cell_parser : { cols: [], parse: EMPTY_FN };
/**
* Global watermark text for input filter type or watermark for each
* filter if an array is supplied
* @type {String|Array}
*/
this.watermark = f.watermark || &apos;&apos;;
/**
* Indicate whether watermark is on a per column basis
* @type {Boolean}
* @private
*/
this.isWatermarkArray = isArray(this.watermark);
/**
* Indicate whether help UI component is disabled
* @type {Boolean}
*/
this.help = isUndef(f.help_instructions) ? undefined :
(isObj(f.help_instructions) || Boolean(f.help_instructions));
/**
* Indicate whether pop-up filters UI is enabled
* @type {Boolean|Object}
*/
this.popupFilters = isObj(f.popup_filters) || Boolean(f.popup_filters);
/**
* Indicate whether filtered (active) columns indicator is enabled
* @type {Boolean}
*/
this.markActiveColumns = isObj(f.mark_active_columns) ||
Boolean(f.mark_active_columns);
/*** select filter&apos;s customisation and behaviours ***/
/**
* Text for clear option in drop-down filter types (1st option)
* @type {String|Array}
*/
this.clearFilterText = defaultsStr(f.clear_filter_text, &apos;Clear&apos;);
/**
* Indicate whether empty option is enabled in drop-down filter types
* @type {Boolean}
*/
this.enableEmptyOption = Boolean(f.enable_empty_option);
/**
* Text for empty option in drop-down filter types
* @type {String}
*/
this.emptyText = defaultsStr(f.empty_text, &apos;(Empty)&apos;);
/**
* Indicate whether non-empty option is enabled in drop-down filter
* types
* @type {Boolean}
*/
this.enableNonEmptyOption = Boolean(f.enable_non_empty_option);
/**
* Text for non-empty option in drop-down filter types
* @type {String}
*/
this.nonEmptyText = defaultsStr(f.non_empty_text, &apos;(Non empty)&apos;);
/**
* Indicate whether drop-down filter types filter the table by default
* on change event
* @type {Boolean}
*/
this.onSlcChange = defaultsBool(f.on_change, true);
/**
* Make drop-down filter types options sorted in alpha-numeric manner
* by default globally or on a column basis
* @type {Boolean|Array}
*/
this.sortSlc = isUndef(f.sort_select) ? true :
isArray(f.sort_select) ? f.sort_select : Boolean(f.sort_select);
/**
* Indicate whether options in drop-down filter types are sorted in a
* ascending numeric manner
* @type {Boolean}
* @private
*/
this.isSortNumAsc = Boolean(f.sort_num_asc);
/**
* List of columns implementing options sorting in a ascending numeric
* manner
* @type {Array}
*/
this.sortNumAsc = this.isSortNumAsc ? f.sort_num_asc : [];
/**
* Indicate whether options in drop-down filter types are sorted in a
* descending numeric manner
* @type {Boolean}
* @private
*/
this.isSortNumDesc = Boolean(f.sort_num_desc);
/**
* List of columns implementing options sorting in a descending numeric
* manner
* @type {Array}
*/
this.sortNumDesc = this.isSortNumDesc ? f.sort_num_desc : [];
/**
* Indicate whether drop-down filter types are populated on demand at
* first usage
* @type {Boolean}
*/
this.loadFltOnDemand = Boolean(f.load_filters_on_demand);
/**
* Indicate whether custom drop-down filter options are implemented
* @type {Boolean}
*/
this.hasCustomOptions = isObj(f.custom_options);
/**
* Custom options definition of a per column basis, ie:
* custom_options: {
* cols:[0, 1],
* texts: [
* [&apos;a0&apos;, &apos;b0&apos;, &apos;c0&apos;],
* [&apos;a1&apos;, &apos;b1&apos;, &apos;c1&apos;]
* ],
* values: [
* [&apos;a0&apos;, &apos;b0&apos;, &apos;c0&apos;],
* [&apos;a1&apos;, &apos;b1&apos;, &apos;c1&apos;]
* ],
* sorts: [false, true]
* }
*
* @type {Object}
*/
this.customOptions = f.custom_options;
/*** Filter operators ***/
/**
* Regular expression operator for input filter. Defaults to &apos;rgx:&apos;
* @type {String}
*/
this.rgxOperator = defaultsStr(f.regexp_operator, &apos;rgx:&apos;);
/**
* Empty cells operator for input filter. Defaults to &apos;[empty]&apos;
* @type {String}
*/
this.emOperator = defaultsStr(f.empty_operator, &apos;[empty]&apos;);
/**
* Non-empty cells operator for input filter. Defaults to &apos;[nonempty]&apos;
* @type {String}
*/
this.nmOperator = defaultsStr(f.nonempty_operator, &apos;[nonempty]&apos;);
/**
* Logical OR operator for input filter. Defaults to &apos;||&apos;
* @type {String}
*/
this.orOperator = defaultsStr(f.or_operator, &apos;||&apos;);
/**
* Logical AND operator for input filter. Defaults to &apos;&amp;&amp;&apos;
* @type {String}
*/
this.anOperator = defaultsStr(f.and_operator, &apos;&amp;&amp;&apos;);
/**
* Greater than operator for input filter. Defaults to &apos;&gt;&apos;
* @type {String}
*/
this.grOperator = defaultsStr(f.greater_operator, &apos;&gt;&apos;);
/**
* Lower than operator for input filter. Defaults to &apos;&lt;&apos;
* @type {String}
*/
this.lwOperator = defaultsStr(f.lower_operator, &apos;&lt;&apos;);
/**
* Lower than or equal operator for input filter. Defaults to &apos;&lt;=&apos;
* @type {String}
*/
this.leOperator = defaultsStr(f.lower_equal_operator, &apos;&lt;=&apos;);
/**
* Greater than or equal operator for input filter. Defaults to &apos;&gt;=&apos;
* @type {String}
*/
this.geOperator = defaultsStr(f.greater_equal_operator, &apos;&gt;=&apos;);
/**
* Inequality operator for input filter. Defaults to &apos;!&apos;
* @type {String}
*/
this.dfOperator = defaultsStr(f.different_operator, &apos;!&apos;);
/**
* Like operator for input filter. Defaults to &apos;*&apos;
* @type {String}
*/
this.lkOperator = defaultsStr(f.like_operator, &apos;*&apos;);
/**
* Strict equality operator for input filter. Defaults to &apos;=&apos;
* @type {String}
*/
this.eqOperator = defaultsStr(f.equal_operator, &apos;=&apos;);
/**
* Starts with operator for input filter. Defaults to &apos;=&apos;
* @type {String}
*/
this.stOperator = defaultsStr(f.start_with_operator, &apos;{&apos;);
/**
* Ends with operator for input filter. Defaults to &apos;=&apos;
* @type {String}
*/
this.enOperator = defaultsStr(f.end_with_operator, &apos;}&apos;);
// this.curExp = f.cur_exp || &apos;^[&#xA5;&#xA3;&#x20AC;$]&apos;;
/**
* Stored values separator
* @type {String}
*/
this.separator = defaultsStr(f.separator, &apos;,&apos;);
/**
* Enable rows counter UI component
* @type {Boolean|Object}
*/
this.rowsCounter = isObj(f.rows_counter) || Boolean(f.rows_counter);
/**
* Enable status bar UI component
* @type {Boolean|Object}
*/
this.statusBar = isObj(f.status_bar) || Boolean(f.status_bar);
/**
* Enable activity/spinner indicator UI component
* @type {Boolean|Object}
*/
this.loader = isObj(f.loader) || Boolean(f.loader);
/*** validation - reset buttons/links ***/
/**
* Enable filters submission button
* @type {Boolean}
*/
this.displayBtn = Boolean(f.btn);
/**
* Define filters submission button text
* @type {String}
*/
this.btnText = defaultsStr(f.btn_text, (!this.enableIcons ? &apos;Go&apos; : &apos;&apos;));
/**
* Css class for filters submission button
* @type {String}
*/
this.btnCssClass = defaultsStr(f.btn_css_class,
(!this.enableIcons ? &apos;btnflt&apos; : &apos;btnflt_icon&apos;));
/**
* Enable clear button
* @type {Object|Boolean}
*/
this.btnReset = isObj(f.btn_reset) || Boolean(f.btn_reset);
/**
* Callback fired before filters are cleared
* @type {Function}
*/
this.onBeforeReset = defaultsFn(f.on_before_reset, EMPTY_FN);
/**
* Callback fired after filters are cleared
* @type {Function}
*/
this.onAfterReset = defaultsFn(f.on_after_reset, EMPTY_FN);
/**
* Enable paging component
* @type {Object|Boolean}
*/
this.paging = isObj(f.paging) || Boolean(f.paging);
/**
* Number of hidden rows
* @type {Number}
* @private
*/
this.nbHiddenRows = 0;
/**
* Enable auto-filter behaviour, table is filtered when a user
* stops typing
* @type {Object|Boolean}
*/
this.autoFilter = isObj(f.auto_filter) || Boolean(f.auto_filter);
/**
* Auto-filter delay in milliseconds
* @type {Number}
*/
this.autoFilterDelay = isObj(f.auto_filter) &amp;&amp;
isNumber(f.auto_filter.delay) ?
f.auto_filter.delay : AUTO_FILTER_DELAY;
/**
* Indicate whether user is typing
* @type {Boolean}
* @private
*/
this.isUserTyping = null;
/**
* Auto-filter interval ID
* @type {String}
* @private
*/
this.autoFilterTimer = null;
/**
* Enable keyword highlighting behaviour
* @type {Boolean}
*/
this.highlightKeywords = Boolean(f.highlight_keywords);
/**
* Enable no results message UI component
* @type {Object|Boolean}
*/
this.noResults = isObj(f.no_results_message) ||
Boolean(f.no_results_message);
/**
* Enable state persistence
* @type {Object|Boolean}
*/
this.state = isObj(f.state) || Boolean(f.state);
/*** data types ***/
/**
* Enable date type module
* @type {Boolean}
* @private
*/
this.dateType = true;
/**
* Define default locale, default to &apos;en&apos; as per Sugar Date module:
* https://sugarjs.com/docs/#/DateLocales
* @type {String}
*/
this.locale = defaultsStr(f.locale, &apos;en&apos;);
/**
* Define thousands separator &apos;,&apos; or &apos;.&apos;, defaults to &apos;,&apos;
* @type {String}
*/
this.thousandsSeparator = defaultsStr(f.thousands_separator, &apos;,&apos;);
/**
* Define decimal separator &apos;,&apos; or &apos;.&apos;, defaults to &apos;.&apos;
* @type {String}
*/
this.decimalSeparator = defaultsStr(f.decimal_separator, &apos;.&apos;);
/**
* Define data types on a column basis, possible values &apos;string&apos;,
* &apos;number&apos;, &apos;formatted-number&apos;, &apos;date&apos;, &apos;ipaddress&apos; ie:
* col_types : [
* &apos;string&apos;, &apos;date&apos;, &apos;number&apos;,
* { type: &apos;formatted-number&apos;, decimal: &apos;,&apos;, thousands: &apos;.&apos; },
* { type: &apos;date&apos;, locale: &apos;en-gb&apos; },
* { type: &apos;date&apos;, format: [&apos;{dd}-{months}-{yyyy|yy}&apos;] }
* ]
*
* Refer to https://sugarjs.com/docs/#/DateParsing for exhaustive
* information on date parsing formats supported by Sugar Date
* @type {Array}
*/
this.colTypes = isArray(f.col_types) ? f.col_types : [];
/*** ids prefixes ***/
/**
* Main prefix
* @private
*/
this.prfxTf = &apos;TF&apos;;
/**
* Filter&apos;s ID prefix (inputs - selects)
* @private
*/
this.prfxFlt = &apos;flt&apos;;
/**
* Button&apos;s ID prefix
* @private
*/
this.prfxValButton = &apos;btn&apos;;
/**
* Responsive Css class
* @private
*/
this.prfxResponsive = &apos;resp&apos;;
/*** extensions ***/
/**
* List of loaded extensions
* @type {Array}
*/
this.extensions = defaultsArr(f.extensions, []);
/*** themes ***/
/**
* Enable default theme
* @type {Boolean}
*/
this.enableDefaultTheme = Boolean(f.enable_default_theme);
/**
* Determine whether themes are enables
* @type {Boolean}
* @private
*/
this.hasThemes = (this.enableDefaultTheme || isArray(f.themes));
/**
* List of themes, ie:
* themes: [{ name: &apos;skyblue&apos; }]
* @type {Array}
*/
this.themes = defaultsArr(f.themes, []);
/**
* Define path to themes assets, defaults to
* &apos;tablefilter/style/themes/&apos;. Usage:
* themes: [{ name: &apos;skyblue&apos; }]
* @type {Array}
*/
this.themesPath = this.getThemesPath();
/**
* Enable responsive layout
* @type {Boolean}
*/
this.responsive = Boolean(f.responsive);
/**
* Enable toolbar component
* @type {Object|Boolean}
*/
this.toolbar = isObj(f.toolbar) || Boolean(f.toolbar);
/**
* Features registry
* @private
*/
this.Mod = {};
/**
* Extensions registry
* @private
*/
this.ExtRegistry = {};
// conditionally instantiate required features
this.instantiateFeatures(
Object.keys(FEATURES).map((item) =&gt; FEATURES[item])
);
}
/**
* Initialise features and layout
*/
init() {
if (this.initialized) {
return;
}
// import main stylesheet
this.import(this.stylesheetId, this.getStylesheetPath(), null, &apos;link&apos;);
let Mod = this.Mod;
let inpclass;
//loads theme
this.loadThemes();
const { dateType, help, state, markActiveColumns, gridLayout, loader,
highlightKeyword, popupFilter, rowsCounter, statusBar, clearButton,
alternateRows, noResults, paging, toolbar } = FEATURES;
//explicitly initialise features in given order
this.initFeatures([
dateType,
help,
state,
markActiveColumns,
gridLayout,
loader,
highlightKeyword,
popupFilter
]);
//filters grid is not generated
if (!this.fltGrid) {
this._initNoFilters();
} else {
let fltrow = this._insertFiltersRow();
this.nbCells = this.getCellsNb(this.refRow);
this.nbFilterableRows = this.getRowsNb();
let n = this.singleFlt ? 1 : this.nbCells;
//build filters
for (let i = 0; i &lt; n; i++) {
this.emitter.emit(&apos;before-filter-init&apos;, this, i);
let fltCell = createElm(this.fltCellTag),
col = this.getFilterType(i);
if (this.singleFlt) {
fltCell.colSpan = this.nbCells;
}
if (!this.gridLayout) {
fltrow.appendChild(fltCell);
}
inpclass = (i === n - 1 &amp;&amp; this.displayBtn) ?
this.fltSmallCssClass : this.fltCssClass;
//only 1 input for single search
if (this.singleFlt) {
col = INPUT;
inpclass = this.singleFltCssClass;
}
//drop-down filters
if (col === SELECT || col === MULTIPLE) {
Mod.dropdown = Mod.dropdown || new Dropdown(this);
Mod.dropdown.init(i, this.isExternalFlt(), fltCell);
}
// checklist
else if (col === CHECKLIST) {
Mod.checkList = Mod.checkList || new CheckList(this);
Mod.checkList.init(i, this.isExternalFlt(), fltCell);
} else {
this._buildInputFilter(i, inpclass, fltCell);
}
// this adds submit button
if (i === n - 1 &amp;&amp; this.displayBtn) {
this._buildSubmitButton(
this.isExternalFlt() ?
elm(this.externalFltIds[i]) :
fltCell
);
}
this.emitter.emit(&apos;after-filter-init&apos;, this, i);
}
this.emitter.on([&apos;filter-focus&apos;],
(tf, filter) =&gt; this.setActiveFilterId(filter.id));
}//if this.fltGrid
/* Features */
if (this.hasExcludedRows) {
this.emitter.on([&apos;after-filtering&apos;], () =&gt; this.setExcludeRows());
this.setExcludeRows();
}
this.initFeatures([
rowsCounter,
statusBar,
clearButton,
alternateRows,
noResults,
paging,
toolbar
]);
this.setColWidths();
//TF css class is added to table
if (!this.gridLayout) {
addClass(this.dom(), this.prfxTf);
if (this.responsive) {
addClass(this.dom(), this.prfxResponsive);
}
if (this.colWidths.length &gt; 0) {
this.setFixedLayout();
}
}
/* Load extensions */
this.initExtensions();
// Subscribe to events
if (this.linkedFilters) {
this.emitter.on([&apos;after-filtering&apos;], () =&gt; this.linkFilters());
}
this.initialized = true;
this.onFiltersLoaded(this);
this.emitter.emit(&apos;initialized&apos;, this);
}
/**
* Detect &lt;enter&gt; key
* @param {Event} evt
*/
detectKey(evt) {
if (!this.enterKey) {
return;
}
if (isKeyPressed(evt, [ENTER_KEY])) {
this.filter();
cancelEvt(evt);
stopEvt(evt);
} else {
this.isUserTyping = true;
root.clearInterval(this.autoFilterTimer);
this.autoFilterTimer = null;
}
}
/**
* Filter&apos;s keyup event: if auto-filter on, detect user is typing and filter
* columns
* @param {Event} evt
*/
onKeyUp(evt) {
if (!this.autoFilter) {
return;
}
this.isUserTyping = false;
function filter() {
root.clearInterval(this.autoFilterTimer);
this.autoFilterTimer = null;
if (!this.isUserTyping) {
this.filter();
this.isUserTyping = null;
}
}
if (isKeyPressed(evt,
[ENTER_KEY, TAB_KEY, ESC_KEY, UP_ARROW_KEY, DOWN_ARROW_KEY])) {
root.clearInterval(this.autoFilterTimer);
this.autoFilterTimer = null;
} else {
if (this.autoFilterTimer !== null) {
return;
}
this.autoFilterTimer = root.setInterval(
filter.bind(this),
this.autoFilterDelay);
}
}
/**
* Filter&apos;s keydown event: if auto-filter on, detect user is typing
*/
onKeyDown() {
if (this.autoFilter) {
this.isUserTyping = true;
}
}
/**
* Filter&apos;s focus event
* @param {Event} evt
*/
onInpFocus(evt) {
let elm = targetEvt(evt);
this.emitter.emit(&apos;filter-focus&apos;, this, elm);
}
/**
* Filter&apos;s blur event: if auto-filter on, clear interval on filter blur
*/
onInpBlur() {
if (this.autoFilter) {
this.isUserTyping = false;
root.clearInterval(this.autoFilterTimer);
}
this.emitter.emit(&apos;filter-blur&apos;, this);
}
/**
* Insert filters row at initialization
*/
_insertFiltersRow() {
// TODO: prevent filters row generation for popup filters too,
// to reduce and simplify headers row index adjusting across lib modules
// (GridLayout, PopupFilter etc)
if (this.gridLayout) {
return;
}
let fltrow;
let thead = tag(this.dom(), &apos;thead&apos;);
if (thead.length &gt; 0) {
fltrow = thead[0].insertRow(this.filtersRowIndex);
} else {
fltrow = this.dom().insertRow(this.filtersRowIndex);
}
fltrow.className = this.fltsRowCssClass;
if (this.isExternalFlt()) {
fltrow.style.display = NONE;
}
this.emitter.emit(&apos;filters-row-inserted&apos;, this, fltrow);
return fltrow;
}
/**
* Initialize filtersless table
*/
_initNoFilters() {
if (this.fltGrid) {
return;
}
this.refRow = this.refRow &gt; 0 ? this.refRow - 1 : 0;
this.nbFilterableRows = this.getRowsNb();
}
/**
* Build input filter type
* @param {Number} colIndex Column index
* @param {String} cssClass Css class applied to filter
* @param {DOMElement} container Container DOM element
*/
_buildInputFilter(colIndex, cssClass, container) {
let col = this.getFilterType(colIndex);
let externalFltTgtId = this.isExternalFlt() ?
this.externalFltIds[colIndex] : null;
let inpType = col === INPUT ? &apos;text&apos; : &apos;hidden&apos;;
let inp = createElm(INPUT,
[&apos;id&apos;, this.buildFilterId(colIndex)],
[&apos;type&apos;, inpType], [&apos;ct&apos;, colIndex]);
if (inpType !== &apos;hidden&apos; &amp;&amp; this.watermark) {
inp.setAttribute(&apos;placeholder&apos;,
this.isWatermarkArray ? (this.watermark[colIndex] || &apos;&apos;) :
this.watermark
);
}
inp.className = cssClass || this.fltCssClass;
addEvt(inp, &apos;focus&apos;, (evt) =&gt; this.onInpFocus(evt));
//filter is appended in custom element
if (externalFltTgtId) {
elm(externalFltTgtId).appendChild(inp);
} else {
container.appendChild(inp);
}
this.fltIds.push(inp.id);
addEvt(inp, &apos;keypress&apos;, (evt) =&gt; this.detectKey(evt));
addEvt(inp, &apos;keydown&apos;, () =&gt; this.onKeyDown());
addEvt(inp, &apos;keyup&apos;, (evt) =&gt; this.onKeyUp(evt));
addEvt(inp, &apos;blur&apos;, () =&gt; this.onInpBlur());
}
/**
* Build submit button
* @param {DOMElement} container Container DOM element
*/
_buildSubmitButton(container) {
let btn = createElm(INPUT,
[&apos;type&apos;, &apos;button&apos;],
[&apos;value&apos;, this.btnText]
);
btn.className = this.btnCssClass;
//filter is appended in container element
container.appendChild(btn);
addEvt(btn, &apos;click&apos;, () =&gt; this.filter());
}
/**
* Istantiate the collection of features required by the
* configuration and add them to the features registry. A feature is
* described by a `class` and `name` fields and and optional `property`
* field:
* {
* class: AClass,
* name: &apos;aClass&apos;
* }
* @param {Array} [features=[]]
* @private
*/
instantiateFeatures(features = []) {
features.forEach((feature) =&gt; {
// TODO: remove the property field.
// Due to naming convention inconsistencies, a `property`
// field is added to allow a conditional instanciation based
// on that property on TableFilter, if supplied.
feature.property = feature.property || feature.name;
if (!this.hasConfig || this[feature.property] === true ||
feature.enforce === true) {
let {class: Cls, name} = feature;
this.Mod[name] = this.Mod[name] || new Cls(this);
}
});
}
/**
* Initialise the passed features collection. A feature is described by a
* `class` and `name` fields and and optional `property` field:
* {
* class: AClass,
* name: &apos;aClass&apos;
* }
* @param {Array} [features=[]]
* @private
*/
initFeatures(features = []) {
features.forEach((feature) =&gt; {
let {property, name} = feature;
if (this[property] === true &amp;&amp; this.Mod[name]) {
this.Mod[name].init();
}
});
}
/**
* Return a feature instance for a given name
* @param {String} name Name of the feature
* @return {Object}
*/
feature(name) {
return this.Mod[name];
}
/**
* Initialise all the extensions defined in the configuration object
*/
initExtensions() {
let exts = this.extensions;
if (exts.length === 0) {
return;
}
// Set config&apos;s publicPath dynamically for Webpack...
__webpack_public_path__ = this.basePath;
this.emitter.emit(&apos;before-loading-extensions&apos;, this);
exts.forEach((ext) =&gt; {
this.loadExtension(ext);
});
this.emitter.emit(&apos;after-loading-extensions&apos;, this);
}
/**
* Load an extension module
* @param {Object} ext Extension config object
*/
loadExtension(ext) {
if (!ext || !ext.name || this.hasExtension(ext.name)) {
return;
}
let {name, path} = ext;
let modulePath;
if (name &amp;&amp; path) {
modulePath = ext.path + name;
} else {
name = name.replace(&apos;.js&apos;, &apos;&apos;);
modulePath = &apos;extensions/{}/{}&apos;.replace(/{}/g, name);
}
// Require pattern for Webpack
require([&apos;./&apos; + modulePath], (mod) =&gt; {
/* eslint-disable */
let inst = new mod.default(this, ext);
/* eslint-enable */
inst.init();
this.ExtRegistry[name] = inst;
});
}
/**
* Get an extension instance
* @param {String} name Name of the extension
* @return {Object} Extension instance
*/
extension(name) {
return this.ExtRegistry[name];
}
/**
* Check passed extension name exists
* @param {String} name Name of the extension
* @return {Boolean}
*/
hasExtension(name) {
return !isEmpty(this.ExtRegistry[name]);
}
/**
* Register the passed extension instance with associated name
* @param {Object} inst Extension instance
* @param {String} name Name of the extension
*/
registerExtension(inst, name) {
this.ExtRegistry[name] = inst;
}
/**
* Destroy all the extensions store in extensions registry
*/
destroyExtensions() {
let reg = this.ExtRegistry;
Object.keys(reg).forEach((key) =&gt; {
reg[key].destroy();
reg[key] = undefined;
});
}
/**
* Load themes defined in the configuration object
*/
loadThemes() {
if (!this.hasThemes) {
return;
}
let themes = this.themes;
this.emitter.emit(&apos;before-loading-themes&apos;, this);
//Default theme config
if (this.enableDefaultTheme) {
let defaultTheme = { name: &apos;default&apos; };
this.themes.push(defaultTheme);
}
themes.forEach((theme, i) =&gt; {
let {name, path} = theme;
let styleId = this.prfxTf + name;
if (name &amp;&amp; !path) {
path = this.themesPath + name + &apos;/&apos; + name + &apos;.css&apos;;
}
else if (!name &amp;&amp; theme.path) {
name = &apos;theme{0}&apos;.replace(&apos;{0}&apos;, i);
}
if (!this.isImported(path, &apos;link&apos;)) {
this.import(styleId, path, null, &apos;link&apos;);
}
});
// Enable loader indicator
this.loader = true;
this.emitter.emit(&apos;after-loading-themes&apos;, this);
}
/**
* Return stylesheet DOM element for a given theme name
* @return {DOMElement} stylesheet element
*/
getStylesheet(name = &apos;default&apos;) {
return elm(this.prfxTf + name);
}
/**
* Destroy filter grid
*/
destroy() {
if (!this.initialized) {
return;
}
let emitter = this.emitter;
if (this.isExternalFlt() &amp;&amp; !this.popupFilters) {
this.removeExternalFlts();
}
this.destroyExtensions();
this.validateAllRows();
// broadcast destroy event modules and extensions are subscribed to
emitter.emit(&apos;destroy&apos;, this);
if (this.fltGrid &amp;&amp; !this.gridLayout) {
this.dom().deleteRow(this.filtersRowIndex);
}
// unsubscribe to events
if (this.hasExcludedRows) {
emitter.off([&apos;after-filtering&apos;], () =&gt; this.setExcludeRows());
}
if (this.linkedFilters) {
emitter.off([&apos;after-filtering&apos;], () =&gt; this.linkFilters());
}
this.emitter.off([&apos;filter-focus&apos;],
(tf, filter) =&gt; this.setActiveFilterId(filter.id));
removeClass(this.dom(), this.prfxTf);
removeClass(this.dom(), this.prfxResponsive);
this.nbHiddenRows = 0;
this.validRowsIndex = [];
this.fltIds = [];
this.initialized = false;
}
/**
* Remove all the external column filters
*/
removeExternalFlts() {
if (!this.isExternalFlt()) {
return;
}
let ids = this.externalFltIds;
ids.forEach((id) =&gt; {
let externalFlt = elm(id);
if (externalFlt) {
externalFlt.innerHTML = &apos;&apos;;
}
});
}
/**
* Check if given column implements a filter with custom options
* @param {Number} colIndex Column&apos;s index
* @return {Boolean}
*/
isCustomOptions(colIndex) {
return this.hasCustomOptions &amp;&amp;
this.customOptions.cols.indexOf(colIndex) !== -1;
}
/**
* Returns an array [[value0, value1 ...],[text0, text1 ...]] with the
* custom options values and texts
* @param {Number} colIndex Column&apos;s index
* @return {Array}
*/
getCustomOptions(colIndex) {
if (isEmpty(colIndex) || !this.isCustomOptions(colIndex)) {
return;
}
let customOptions = this.customOptions;
let cols = customOptions.cols;
let optTxt = [], optArray = [];
let index = cols.indexOf(colIndex);
let slcValues = customOptions.values[index];
let slcTexts = customOptions.texts[index];
let slcSort = customOptions.sorts[index];
for (let r = 0, len = slcValues.length; r &lt; len; r++) {
optArray.push(slcValues[r]);
if (slcTexts[r]) {
optTxt.push(slcTexts[r]);
} else {
optTxt.push(slcValues[r]);
}
}
if (slcSort) {
optArray.sort();
optTxt.sort();
}
return [optArray, optTxt];
}
/**
* Filter the table by retrieving the data from each cell in every single
* row and comparing it to the search term for current column. A row is
* hidden when all the search terms are not found in inspected row.
*/
filter() {
if (!this.fltGrid || !this.initialized) {
return;
}
let emitter = this.emitter;
//fire onbefore callback
this.onBeforeFilter(this);
emitter.emit(&apos;before-filtering&apos;, this);
let hiddenRows = 0;
this.validRowsIndex = [];
// search args
let searchArgs = this.getFiltersValue();
let eachRow = this.eachRow();
eachRow(
(row, k) =&gt; {
// already filtered rows display re-init
row.style.display = &apos;&apos;;
let cells = row.cells;
let nbCells = cells.length;
let occurence = [],
isMatch = true,
//only for single filter search
isSingleFltMatch = false;
// this loop retrieves cell data
for (let j = 0; j &lt; nbCells; j++) {
//searched keyword
let sA = searchArgs[this.singleFlt ? 0 : j];
if (sA === &apos;&apos;) {
continue;
}
let cellValue = matchCase(this.getCellValue(cells[j]),
this.caseSensitive);
//multiple search parameter operator ||
let sAOrSplit = sA.toString().split(this.orOperator),
//multiple search || parameter boolean
hasMultiOrSA = sAOrSplit.length &gt; 1,
//multiple search parameter operator &amp;&amp;
sAAndSplit = sA.toString().split(this.anOperator),
//multiple search &amp;&amp; parameter boolean
hasMultiAndSA = sAAndSplit.length &gt; 1;
//detect operators or array query
if (isArray(sA) || hasMultiOrSA || hasMultiAndSA) {
let cS, s;
let found = false;
if (isArray(sA)) {
s = sA;
} else {
s = hasMultiOrSA ? sAOrSplit : sAAndSplit;
}
// isolate search term and check occurence in cell data
for (let w = 0, len = s.length; w &lt; len; w++) {
cS = trim(s[w]);
found = this._match(cS, cellValue, j);
if (found) {
emitter.emit(&apos;highlight-keyword&apos;, this,
cells[j], cS);
}
if ((hasMultiOrSA &amp;&amp; found) ||
(hasMultiAndSA &amp;&amp; !found)) {
break;
}
if (isArray(sA) &amp;&amp; found) {
break;
}
}
occurence[j] = found;
}
//single search parameter
else {
occurence[j] = this._match(trim(sA), cellValue, j);
if (occurence[j]) {
emitter.emit(&apos;highlight-keyword&apos;, this, cells[j],
sA);
}
}
if (!occurence[j]) {
isMatch = false;
}
if (this.singleFlt &amp;&amp;
this.singleFltExcludeCols.indexOf(j) === -1 &amp;&amp;
occurence[j]) {
isSingleFltMatch = true;
}
emitter.emit(&apos;cell-processed&apos;, this, j, cells[j]);
}//for j
if (isSingleFltMatch) {
isMatch = true;
}
this.validateRow(k, isMatch);
if (!isMatch) {
hiddenRows++;
}
emitter.emit(&apos;row-processed&apos;, this, k,
this.validRowsIndex.length, isMatch);
},
// continue condition
(row) =&gt; row.cells.length !== this.nbCells
);
this.nbHiddenRows = hiddenRows;
//fire onafterfilter callback
this.onAfterFilter(this);
emitter.emit(&apos;after-filtering&apos;, this, searchArgs);
}
/**
* Match search term in cell data
* @param {String} term Search term
* @param {String} cellValue Cell data
* @param {Number} colIdx Column index
* @return {Boolean}
* @private
*/
_match(term, cellValue, colIdx) {
let numData;
let decimal = this.getDecimal(colIdx);
let reLe = new RegExp(this.leOperator),
reGe = new RegExp(this.geOperator),
reL = new RegExp(this.lwOperator),
reG = new RegExp(this.grOperator),
reD = new RegExp(this.dfOperator),
reLk = new RegExp(rgxEsc(this.lkOperator)),
reEq = new RegExp(this.eqOperator),
reSt = new RegExp(this.stOperator),
reEn = new RegExp(this.enOperator),
// re_an = new RegExp(this.anOperator),
// re_cr = new RegExp(this.curExp),
reEm = this.emOperator,
reNm = this.nmOperator,
reRe = new RegExp(rgxEsc(this.rgxOperator));
term = matchCase(term, this.caseSensitive);
let occurence = false;
//Search arg operator tests
let hasLO = reL.test(term),
hasLE = reLe.test(term),
hasGR = reG.test(term),
hasGE = reGe.test(term),
hasDF = reD.test(term),
hasEQ = reEq.test(term),
hasLK = reLk.test(term),
// hatermN = re_an.test(term),
hasST = reSt.test(term),
hasEN = reEn.test(term),
hasEM = (reEm === term),
hasNM = (reNm === term),
hasRE = reRe.test(term);
// Check for dates or resolve date type
if (this.hasType(colIdx, [DATE])) {
let dte1, dte2;
let dateType = this.Mod.dateType;
let isValidDate = dateType.isValid.bind(dateType);
let parseDate = dateType.parse.bind(dateType);
let locale = dateType.getLocale(colIdx);
// Search arg dates tests
let isLDate = hasLO &amp;&amp;
isValidDate(term.replace(reL, &apos;&apos;), locale);
let isLEDate = hasLE &amp;&amp;
isValidDate(term.replace(reLe, &apos;&apos;), locale);
let isGDate = hasGR &amp;&amp;
isValidDate(term.replace(reG, &apos;&apos;), locale);
let isGEDate = hasGE &amp;&amp;
isValidDate(term.replace(reGe, &apos;&apos;), locale);
let isDFDate = hasDF &amp;&amp;
isValidDate(term.replace(reD, &apos;&apos;), locale);
let isEQDate = hasEQ &amp;&amp;
isValidDate(term.replace(reEq, &apos;&apos;), locale);
dte1 = parseDate(cellValue, locale);
// lower equal date
if (isLEDate) {
dte2 = parseDate(term.replace(reLe, &apos;&apos;), locale);
occurence = dte1 &lt;= dte2;
}
// lower date
else if (isLDate) {
dte2 = parseDate(term.replace(reL, &apos;&apos;), locale);
occurence = dte1 &lt; dte2;
}
// greater equal date
else if (isGEDate) {
dte2 = parseDate(term.replace(reGe, &apos;&apos;), locale);
occurence = dte1 &gt;= dte2;
}
// greater date
else if (isGDate) {
dte2 = parseDate(term.replace(reG, &apos;&apos;), locale);
occurence = dte1 &gt; dte2;
}
// different date
else if (isDFDate) {
dte2 = parseDate(term.replace(reD, &apos;&apos;), locale);
occurence = dte1.toString() !== dte2.toString();
}
// equal date
else if (isEQDate) {
dte2 = parseDate(term.replace(reEq, &apos;&apos;), locale);
occurence = dte1.toString() === dte2.toString();
}
// searched keyword with * operator doesn&apos;t have to be a date
else if (reLk.test(term)) {// like date
occurence = contains(term.replace(reLk, &apos;&apos;), cellValue,
false, this.caseSensitive);
}
else if (isValidDate(term)) {
dte2 = parseDate(term, locale);
occurence = dte1.toString() === dte2.toString();
}
//empty
else if (hasEM) {
occurence = isEmptyString(cellValue);
}
//non-empty
else if (hasNM) {
occurence = !isEmptyString(cellValue);
} else {
occurence = contains(term, cellValue,
this.isExactMatch(colIdx), this.caseSensitive);
}
} else {
// Convert to number anyways to auto-resolve type in case not
// defined by configuration. Order is important first try to
// parse formatted number then fallback to Number coercion
// to avoid false positives with Number
numData = parseNb(cellValue, decimal) || Number(cellValue);
// first checks if there is any operator (&lt;,&gt;,&lt;=,&gt;=,!,*,=,{,},
// rgx:)
//regexp
if (hasRE) {
//in case regexp throws
try {
//operator is removed
let srchArg = term.replace(reRe, &apos;&apos;);
let rgx = new RegExp(srchArg);
occurence = rgx.test(cellValue);
} catch (ex) {
occurence = false;
}
}
// lower equal
else if (hasLE) {
occurence = numData &lt;= parseNb(
term.replace(reLe, &apos;&apos;),
decimal
);
}
//greater equal
else if (hasGE) {
occurence = numData &gt;= parseNb(
term.replace(reGe, &apos;&apos;),
decimal
);
}
//lower
else if (hasLO) {
occurence = numData &lt; parseNb(
term.replace(reL, &apos;&apos;),
decimal
);
}
//greater
else if (hasGR) {
occurence = numData &gt; parseNb(
term.replace(reG, &apos;&apos;),
decimal
);
}
//different
else if (hasDF) {
occurence = contains(term.replace(reD, &apos;&apos;), cellValue,
false, this.caseSensitive) ? false : true;
}
//like
else if (hasLK) {
occurence = contains(term.replace(reLk, &apos;&apos;), cellValue,
false, this.caseSensitive);
}
//equal
else if (hasEQ) {
occurence = contains(term.replace(reEq, &apos;&apos;), cellValue,
true, this.caseSensitive);
}
//starts with
else if (hasST) {
occurence = cellValue.indexOf(term.replace(reSt, &apos;&apos;)) === 0 ?
true : false;
}
//ends with
else if (hasEN) {
let searchArg = term.replace(reEn, &apos;&apos;);
occurence =
cellValue.lastIndexOf(searchArg, cellValue.length - 1) ===
(cellValue.length - 1) - (searchArg.length - 1) &amp;&amp;
cellValue.lastIndexOf(searchArg, cellValue.length - 1)
&gt; -1 ? true : false;
}
//empty
else if (hasEM) {
occurence = isEmptyString(cellValue);
}
//non-empty
else if (hasNM) {
occurence = !isEmptyString(cellValue);
} else {
// If numeric type data, perform a strict equality test and
// fallback to unformatted number string comparison
if (numData &amp;&amp;
this.hasType(colIdx, [NUMBER, FORMATTED_NUMBER]) &amp;&amp;
!this.singleFlt) {
// parseNb can return 0 for strings which are not
// formatted numbers, in that case return the original
// string. TODO: handle this in parseNb
term = parseNb(term, decimal) || term;
occurence = numData === term ||
contains(term.toString(), numData.toString(),
this.isExactMatch(colIdx), this.caseSensitive);
} else {
// Finally test search term is contained in cell data
occurence = contains(
term,
cellValue,
this.isExactMatch(colIdx),
this.caseSensitive,
this.ignoresDiacritics(colIdx)
);
}
}
}//else
return occurence;
}
/**
* Return the data of a specified column
* @param {Number} colIndex Column index
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Array} [exclude=[]] List of row indexes to be excluded
* @return Flat list of data for a column
*/
getColumnData(colIndex, includeHeaders = false, exclude = []) {
return this.getColValues(colIndex, includeHeaders, true, exclude);
}
/**
* Return the values of a specified column
* @param {Number} colIndex Column index
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Array} [exclude=[]] List of row indexes to be excluded
* @return Flat list of values for a column
*/
getColumnValues(colIndex, includeHeaders = false, exclude = []) {
return this.getColValues(colIndex, includeHeaders, false, exclude);
}
/**
* Return the data of a specified column
* @param {Number} colIndex Column index
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Boolean} [typed=false] Return a typed value
* @param {Array} [exclude=[]] List of row indexes to be excluded
* @return {Array} Flat list of data for a column
* @private
*/
getColValues(
colIndex,
includeHeaders = false,
typed = false,
exclude = []
) {
let colValues = [];
let getContent = typed ? this.getCellData.bind(this) :
this.getCellValue.bind(this);
if (includeHeaders) {
colValues.push(this.getHeadersText()[colIndex]);
}
let eachRow = this.eachRow();
eachRow((row, i) =&gt; {
// checks if current row index appears in exclude array
let isExludedRow = exclude.indexOf(i) !== -1;
let cells = row.cells;
// checks if row has exact cell # and is not excluded
if (cells.length === this.nbCells &amp;&amp; !isExludedRow) {
let data = getContent(cells[colIndex]);
colValues.push(data);
}
});
return colValues;
}
/**
* Return the filter&apos;s value of a specified column
* @param {Number} index Column index
* @return {String} Filter value
*/
getFilterValue(index) {
if (!this.fltGrid) {
return;
}
let fltValue = &apos;&apos;;
let flt = this.getFilterElement(index);
if (!flt) {
return fltValue;
}
let fltColType = this.getFilterType(index);
if (fltColType !== MULTIPLE &amp;&amp; fltColType !== CHECKLIST) {
fltValue = flt.value;
}
//mutiple select
else if (fltColType === MULTIPLE) {
fltValue = this.feature(&apos;dropdown&apos;).getValues(index);
}
//checklist
else if (fltColType === CHECKLIST) {
fltValue = this.feature(&apos;checkList&apos;).getValues(index);
}
//return an empty string if collection is empty or contains a single
//empty string
if (isArray(fltValue) &amp;&amp; fltValue.length === 0 ||
(fltValue.length === 1 &amp;&amp; fltValue[0] === &apos;&apos;)) {
fltValue = &apos;&apos;;
}
return fltValue;
}
/**
* Return the filters&apos; values
* @return {Array} List of filters&apos; values
*/
getFiltersValue() {
if (!this.fltGrid) {
return;
}
let searchArgs = [];
this.fltIds.forEach((id, i) =&gt; {
let fltValue = this.getFilterValue(i);
if (isArray(fltValue)) {
searchArgs.push(fltValue);
} else {
searchArgs.push(trim(fltValue));
}
});
return searchArgs;
}
/**
* Return the ID of a specified column&apos;s filter
* @param {Number} index Column&apos;s index
* @return {String} ID of the filter element
*/
getFilterId(index) {
if (!this.fltGrid) {
return;
}
return this.fltIds[index];
}
/**
* Return the list of ids of filters matching a specified type.
* Note: hidden filters are also returned
*
* @param {String} type Filter type string (&apos;input&apos;, &apos;select&apos;, &apos;multiple&apos;,
* &apos;checklist&apos;)
* @param {Boolean} bool If true returns columns indexes instead of IDs
* @return {[type]} List of element IDs or column indexes
*/
getFiltersByType(type, bool) {
if (!this.fltGrid) {
return;
}
let arr = [];
for (let i = 0, len = this.fltIds.length; i &lt; len; i++) {
let fltType = this.getFilterType(i);
if (fltType === type.toLowerCase()) {
let a = bool ? i : this.fltIds[i];
arr.push(a);
}
}
return arr;
}
/**
* Return the filter&apos;s DOM element for a given column
* @param {Number} index Column&apos;s index
* @return {DOMElement}
*/
getFilterElement(index) {
return elm(this.fltIds[index]);
}
/**
* Return the number of cells for a given row index
* @param {Number} rowIndex Index of the row
* @return {Number} Number of cells
*/
getCellsNb(rowIndex = 0) {
let tr = this.dom().rows[rowIndex &gt;= 0 ? rowIndex : 0];
return tr ? tr.cells.length : 0;
}
/**
* Return the number of working rows starting from reference row if
* defined
* @param {Boolean} includeHeaders Include the headers row(s)
* @return {Number} Number of working rows
*/
getRowsNb(includeHeaders) {
let nbRows = this.getWorkingRows().length;
if (this.dom().tHead) {
return includeHeaders ?
nbRows + this.dom().querySelectorAll(&apos;thead &gt; tr&apos;).length :
nbRows;
}
return includeHeaders ? nbRows : nbRows - this.refRow;
}
/**
* Return the collection of the working rows, that is, the rows belonging
* to the tbody section(s)
* @returns {Array}
*/
getWorkingRows() {
return doc.querySelectorAll(`table#${this.id} &gt; tbody &gt; tr`);
}
/**
* Return the text content of a given cell
* @param {DOMElement} Cell&apos;s DOM element
* @return {String}
*/
getCellValue(cell) {
let idx = cell.cellIndex;
let cellParser = this.cellParser;
// Invoke cellParser for this column if any
if (cellParser.cols.indexOf(idx) !== -1) {
return cellParser.parse(this, cell, idx);
} else {
return getText(cell);
}
}
/**
* Return the typed data of a given cell based on the column type definition
* @param {DOMElement} cell Cell&apos;s DOM element
* @return {String|Number|Date}
*/
getCellData(cell) {
let colIndex = cell.cellIndex;
let value = this.getCellValue(cell);
if (this.hasType(colIndex, [FORMATTED_NUMBER])) {
return parseNb(value, this.getDecimal(colIndex));
}
else if (this.hasType(colIndex, [NUMBER])) {
return Number(value);
}
else if (this.hasType(colIndex, [DATE])){
let dateType = this.Mod.dateType;
return dateType.parse(value, dateType.getLocale(colIndex));
}
return value;
}
/**
* Return the table data based on its columns data type definitions
* with following structure:
* [
* [rowIndex, [data0, data1...]],
* [rowIndex, [data0, data1...]]
* ]
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Boolean} [excludeHiddenCols=false] Exclude hidden columns
* @return {Array}
*/
getData(includeHeaders = false, excludeHiddenCols = false) {
return this.getTableData(includeHeaders, excludeHiddenCols, true);
}
/**
* Return the table values with following structure:
* [
* [rowIndex, [value0, value1...]],
* [rowIndex, [value0, value1...]]
* ]
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Boolean} [excludeHiddenCols=false] Exclude hidden columns
* @return {Array}
*/
getValues(includeHeaders = false, excludeHiddenCols = false) {
return this.getTableData(includeHeaders, excludeHiddenCols, false);
}
/**
* Return the table data with following structure:
* [
* [rowIndex, [value0, value1...]],
* [rowIndex, [value0, value1...]]
* ]
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Boolean} [excludeHiddenCols=false] Exclude hidden columns
* @param {Boolean} [typed=false] Return typed value
* @return {Array}
* @private
*
* TODO: provide an API returning data in JSON format
*/
getTableData(
includeHeaders = false,
excludeHiddenCols = false,
typed = false
) {
let tblData = [];
let getContent = typed ? this.getCellData.bind(this) :
this.getCellValue.bind(this);
if (includeHeaders) {
let headers = this.getHeadersText(excludeHiddenCols);
tblData.push([this.getHeadersRowIndex(), headers]);
}
let eachRow = this.eachRow();
eachRow((row, k) =&gt; {
let rowData = [k, []];
let cells = row.cells;
for (let j = 0, len = cells.length; j &lt; len; j++) {
if (excludeHiddenCols &amp;&amp; this.hasExtension(&apos;colsVisibility&apos;)) {
if (this.extension(&apos;colsVisibility&apos;).isColHidden(j)) {
continue;
}
}
let cellContent = getContent(cells[j]);
rowData[1].push(cellContent);
}
tblData.push(rowData);
});
return tblData;
}
/**
* Return the filtered table data based on its columns data type definitions
* with following structure:
* [
* [rowIndex, [data0, data1...]],
* [rowIndex, [data0, data1...]]
* ]
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Boolean} [excludeHiddenCols=false] Exclude hidden columns
* @return {Array}
*
* TODO: provide an API returning data in JSON format
*/
getFilteredData(includeHeaders = false, excludeHiddenCols = false) {
return this.filteredData(includeHeaders, excludeHiddenCols, true);
}
/**
* Return the filtered table values with following structure:
* [
* [rowIndex, [value0, value1...]],
* [rowIndex, [value0, value1...]]
* ]
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Boolean} [excludeHiddenCols=false] Exclude hidden columns
* @return {Array}
*
* TODO: provide an API returning data in JSON format
*/
getFilteredValues(includeHeaders = false, excludeHiddenCols = false) {
return this.filteredData(includeHeaders, excludeHiddenCols, false);
}
/**
* Return the filtered data with following structure:
* [
* [rowIndex, [value0, value1...]],
* [rowIndex, [value0, value1...]]
* ]
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Boolean} [excludeHiddenCols=false] Exclude hidden columns
* @param {Boolean} [typed=false] Return typed value
* @return {Array}
* @private
*
* TODO: provide an API returning data in JSON format
*/
filteredData(
includeHeaders = false,
excludeHiddenCols = false,
typed = false
) {
if (this.validRowsIndex.length === 0) {
return [];
}
let rows = this.dom().rows,
filteredData = [];
let getContent = typed ? this.getCellData.bind(this) :
this.getCellValue.bind(this);
if (includeHeaders) {
let headers = this.getHeadersText(excludeHiddenCols);
filteredData.push([this.getHeadersRowIndex(), headers]);
}
let validRows = this.getValidRows(true);
for (let i = 0; i &lt; validRows.length; i++) {
let rData = [this.validRowsIndex[i], []],
cells = rows[this.validRowsIndex[i]].cells;
for (let k = 0; k &lt; cells.length; k++) {
if (excludeHiddenCols &amp;&amp; this.hasExtension(&apos;colsVisibility&apos;)) {
if (this.extension(&apos;colsVisibility&apos;).isColHidden(k)) {
continue;
}
}
let cellValue = getContent(cells[k]);
rData[1].push(cellValue);
}
filteredData.push(rData);
}
return filteredData;
}
/**
* Return the filtered data for a given column index
* @param {any} colIndex Colmun&apos;s index
* @param {boolean} [includeHeaders=false] Optional Include headers row
* @param {any} [exclude=[]] Optional List of row indexes to be excluded
* @return {Array} Flat list of typed values [data0, data1, data2...]
*
* TODO: provide an API returning data in JSON format
*/
getFilteredColumnData(colIndex, includeHeaders = false, exclude = []) {
return this.getFilteredDataCol(
colIndex, includeHeaders, true, exclude, false);
}
/**
* Return the filtered and visible data for a given column index
* @param {any} colIndex Colmun&apos;s index
* @param {boolean} [includeHeaders=false] Optional Include headers row
* @param {any} [exclude=[]] Optional List of row indexes to be excluded
* @return {Array} Flat list of typed values [data0, data1, data2...]
*
* TODO: provide an API returning data in JSON format
*/
getVisibleColumnData(colIndex, includeHeaders = false, exclude = []) {
return this.getFilteredDataCol(
colIndex, includeHeaders, true, exclude, true);
}
/**
* Return the filtered values for a given column index
* @param {any} colIndex Colmun&apos;s index
* @param {boolean} [includeHeaders=false] Optional Include headers row
* @param {any} [exclude=[]] Optional List of row indexes to be excluded
* @return {Array} Flat list of values [&apos;value0&apos;, &apos;value1&apos;, &apos;value2&apos;...]
*
* TODO: provide an API returning data in JSON format
*/
getFilteredColumnValues(colIndex, includeHeaders = false, exclude = []) {
return this.getFilteredDataCol(
colIndex, includeHeaders, false, exclude, false);
}
/**
* Return the filtered and visible values for a given column index
* @param {any} colIndex Colmun&apos;s index
* @param {boolean} [includeHeaders=false] Optional Include headers row
* @param {any} [exclude=[]] Optional List of row indexes to be excluded
* @return {Array} Flat list of values [&apos;value0&apos;, &apos;value1&apos;, &apos;value2&apos;...]
*
* TODO: provide an API returning data in JSON format
*/
getVisibleColumnValues(colIndex, includeHeaders = false, exclude = []) {
return this.getFilteredDataCol(
colIndex, includeHeaders, false, exclude, true);
}
/**
* Return the filtered data for a given column index
* @param {Number} colIndex Colmun&apos;s index
* @param {Boolean} [includeHeaders=false] Include headers row
* @param {Boolean} [typed=false] Return typed value
* @param {Array} [exclude=[]] List of row indexes to be excluded
* @param {Boolean} [visible=true] Return only filtered and visible data
* (relevant for paging)
* @return {Array} Flat list of values [&apos;val0&apos;,&apos;val1&apos;,&apos;val2&apos;...]
* @private
*
* TODO: provide an API returning data in JSON format
*/
getFilteredDataCol(
colIndex,
includeHeaders = false,
typed = false,
exclude = [],
visible = true
) {
if (isUndef(colIndex)) {
return [];
}
let rows = this.dom().rows;
let getContent = typed ? this.getCellData.bind(this) :
this.getCellValue.bind(this);
// ensure valid rows index do not contain excluded rows and row is
// displayed
let validRows = this.getValidRows(true).filter((rowIdx) =&gt; {
return exclude.indexOf(rowIdx) === -1 &amp;&amp;
(visible ?
this.getRowDisplay(rows[rowIdx]) !== &apos;none&apos; :
true);
});
// convert column value to expected type if necessary
let validColValues = validRows.map((rowIdx) =&gt; {
return getContent(rows[rowIdx].cells[colIndex]);
});
if (includeHeaders) {
validColValues.unshift(this.getHeadersText()[colIndex]);
}
return validColValues;
}
/**
* Get the display value of a row
* @param {HTMLTableRowElement} row DOM element of the row
* @return {String} Usually &apos;none&apos; or &apos;&apos;
*/
getRowDisplay(row) {
return row.style.display;
}
/**
* Validate/invalidate row by setting the &apos;validRow&apos; attribute on the row
* @param {Number} rowIndex Index of the row
* @param {Boolean} isValid
*/
validateRow(rowIndex, isValid) {
let row = this.dom().rows[rowIndex];
if (!row || !isBoolean(isValid)) {
return;
}
// always visible rows are valid
if (this.excludeRows.indexOf(rowIndex) !== -1) {
isValid = true;
}
let displayFlag = isValid ? &apos;&apos; : NONE,
validFlag = isValid ? &apos;true&apos; : &apos;false&apos;;
row.style.display = displayFlag;
if (this.paging) {
row.setAttribute(&apos;validRow&apos;, validFlag);
}
if (isValid) {
if (this.validRowsIndex.indexOf(rowIndex) === -1) {
this.validRowsIndex.push(rowIndex);
}
this.onRowValidated(this, rowIndex);
this.emitter.emit(&apos;row-validated&apos;, this, rowIndex);
}
}
/**
* Validate all filterable rows
*/
validateAllRows() {
if (!this.initialized) {
return;
}
this.validRowsIndex = [];
for (let k = this.refRow; k &lt; this.nbFilterableRows; k++) {
this.validateRow(k, true);
}
}
/**
* Set search value to a given filter
* @param {Number} index Column&apos;s index
* @param {String or Array} query searcharg Search term
*/
setFilterValue(index, query = &apos;&apos;) {
if (!this.fltGrid) {
return;
}
let slc = this.getFilterElement(index),
fltColType = this.getFilterType(index);
if (!slc) {
return;
}
if (fltColType !== MULTIPLE &amp;&amp; fltColType !== CHECKLIST) {
if (this.loadFltOnDemand &amp;&amp; !this.initialized) {
this.emitter.emit(&apos;build-select-filter&apos;, this, index,
this.linkedFilters, this.isExternalFlt());
}
slc.value = query;
}
//multiple selects
else if (fltColType === MULTIPLE) {
let values = isArray(query) ? query :
query.split(&apos; &apos; + this.orOperator + &apos; &apos;);
if (this.loadFltOnDemand &amp;&amp; !this.initialized) {
this.emitter.emit(&apos;build-select-filter&apos;, this, index,
this.linkedFilters, this.isExternalFlt());
}
this.emitter.emit(&apos;select-options&apos;, this, index, values);
}
//checklist
else if (fltColType === CHECKLIST) {
let values = [];
if (this.loadFltOnDemand &amp;&amp; !this.initialized) {
this.emitter.emit(&apos;build-checklist-filter&apos;, this, index,
this.linkedFilters);
}
if (isArray(query)) {
values = query;
} else {
query = matchCase(query, this.caseSensitive);
values = query.split(&apos; &apos; + this.orOperator + &apos; &apos;);
}
this.emitter.emit(&apos;select-checklist-options&apos;, this, index, values);
}
}
/**
* Make passed or default working table element width fixed
* @param {TableElement} tbl optional table DOM element
*/
setFixedLayout(tbl = this.dom()) {
let colWidths = this.colWidths;
let tableWidth = tbl.clientWidth;
if (colWidths.length &gt; 0) {
let defaultWidth = this.defaultColWidth;
tableWidth = colWidths
.reduce((x, y) =&gt;
parseInt((x || defaultWidth), 10) +
parseInt((y || defaultWidth), 10)
);
}
tbl.style.width = `${tableWidth}px`;
tbl.style.tableLayout = &apos;fixed&apos;;
}
/**
* Set passed or default working table columns&apos; widths with configuration
* values
* @param {TableElement} tbl optional table DOM element
*/
setColWidths(tbl = this.dom()) {
let colWidths = this.colWidths;
if (colWidths.length === 0) {
return;
}
let colTags = tag(tbl, &apos;col&apos;);
let tblHasColTag = colTags.length &gt; 0;
let frag = !tblHasColTag ? doc.createDocumentFragment() : null;
this.eachCol((k) =&gt; {
let col;
if (tblHasColTag) {
col = colTags[k];
} else {
col = createElm(&apos;col&apos;);
frag.appendChild(col);
}
col.style.width = colWidths[k];
});
if (!tblHasColTag) {
tbl.insertBefore(frag, tbl.firstChild);
}
}
/**
* Exclude rows from actions
*/
setExcludeRows() {
if (!this.hasExcludedRows) {
return;
}
this.excludeRows.forEach((rowIdx) =&gt; this.validateRow(rowIdx, true));
}
/**
* Clear all the filters&apos; values
*/
clearFilters() {
if (!this.fltGrid) {
return;
}
this.emitter.emit(&apos;before-clearing-filters&apos;, this);
this.onBeforeReset(this, this.getFiltersValue());
for (let i = 0, len = this.fltIds.length; i &lt; len; i++) {
this.setFilterValue(i, &apos;&apos;);
}
this.filter();
this.onAfterReset(this);
this.emitter.emit(&apos;after-clearing-filters&apos;, this);
}
/**
* Return the ID of the current active filter
* @return {String}
*/
getActiveFilterId() {
return this.activeFilterId;
}
/**
* Set the ID of the current active filter
* @param {String} filterId Element ID
*/
setActiveFilterId(filterId) {
this.activeFilterId = filterId;
}
/**
* Return the column index for a given filter ID
* @param {string} [filterId=&apos;&apos;] Filter ID
* @return {Number} Column index
*/
getColumnIndexFromFilterId(filterId = &apos;&apos;) {
let idx = filterId.split(&apos;_&apos;)[0];
idx = idx.split(this.prfxFlt)[1];
return parseInt(idx, 10);
}
/**
* Build filter element ID for a given column index
* @param {any} colIndex
* @return {String} Filter element ID string
* @private
*/
buildFilterId(colIndex) {
return `${this.prfxFlt}${colIndex}_${this.id}`;
}
/**
* Check if has external filters
* @returns {Boolean}
* @private
*/
isExternalFlt() {
return this.externalFltIds.length &gt; 0;
}
/**
* Returns styles path
* @returns {String}
* @private
*/
getStylePath() {
return defaultsStr(this.config.style_path, this.basePath + &apos;style/&apos;);
}
/**
* Returns main stylesheet path
* @returns {String}
* @private
*/
getStylesheetPath() {
return defaultsStr(this.config.stylesheet,
this.getStylePath() + &apos;tablefilter.css&apos;);
}
/**
* Returns themes path
* @returns {String}
* @private
*/
getThemesPath() {
return defaultsStr(this.config.themes_path,
this.getStylePath() + &apos;themes/&apos;);
}
/**
* Make specified column&apos;s filter active
* @param colIndex Index of a column
*/
activateFilter(colIndex) {
if (isUndef(colIndex)) {
return;
}
this.setActiveFilterId(this.getFilterId(colIndex));
}
/**
* Refresh the filters subject to linking (&apos;select&apos;, &apos;multiple&apos;,
* &apos;checklist&apos; type)
*/
linkFilters() {
if (!this.linkedFilters || !this.activeFilterId) {
return;
}
let slcA1 = this.getFiltersByType(SELECT, true),
slcA2 = this.getFiltersByType(MULTIPLE, true),
slcA3 = this.getFiltersByType(CHECKLIST, true),
slcIndex = slcA1.concat(slcA2);
slcIndex = slcIndex.concat(slcA3);
slcIndex.forEach((colIdx) =&gt; {
let curSlc = this.getFilterElement(colIdx);
let slcSelectedValue = this.getFilterValue(colIdx);
//1st option needs to be inserted
if (this.loadFltOnDemand) {
let opt0 = createOpt(this.getClearFilterText(colIdx), &apos;&apos;);
curSlc.innerHTML = &apos;&apos;;
curSlc.appendChild(opt0);
}
if (slcA3.indexOf(colIdx) !== -1) {
this.emitter.emit(&apos;build-checklist-filter&apos;, this, colIdx,
true);
} else {
this.emitter.emit(&apos;build-select-filter&apos;, this, colIdx,
true);
}
this.setFilterValue(colIdx, slcSelectedValue);
});
}
/**
* Determine if passed filter column implements exact query match
* @param {Number} colIndex Column index
* @return {Boolean}
*/
isExactMatch(colIndex) {
let fltType = this.getFilterType(colIndex);
return this.exactMatchByCol[colIndex] || this.exactMatch ||
fltType !== INPUT;
}
/**
* Check if passed row is valid
* @param {Number} rowIndex Row index
* @return {Boolean}
*/
isRowValid(rowIndex) {
return this.getValidRows().indexOf(rowIndex) !== -1;
}
/**
* Check if passed row is visible
* @param {Number} rowIndex Row index
* @return {Boolean}
*/
isRowDisplayed(rowIndex) {
let row = this.dom().rows[rowIndex];
return this.getRowDisplay(row) === &apos;&apos;;
}
/**
* Check if specified column filter ignores diacritics.
* Note this is only applicable to input filter types.
* @param {Number} colIndex Column index
* @return {Boolean}
*/
ignoresDiacritics(colIndex) {
let ignoreDiac = this.ignoreDiacritics;
if (isArray(ignoreDiac)) {
return ignoreDiac[colIndex];
}
return Boolean(ignoreDiac);
}
/**
* Return clear all text for specified filter column
* @param {Number} colIndex Column index
* @return {String}
*/
getClearFilterText(colIndex) {
let clearText = this.clearFilterText;
if (isArray(clearText)) {
return clearText[colIndex];
}
return clearText;
}
/**
* Column iterator invoking continue and break condition callbacks if any
* then calling supplied callback for each item
* @param {Function} [fn=EMPTY_FN] callback
* @param {Function} [continueFn=EMPTY_FN] continue condition callback
* @param {Function} [breakFn=EMPTY_FN] break condition callback
*/
eachCol(fn = EMPTY_FN, continueFn = EMPTY_FN, breakFn = EMPTY_FN) {
let len = this.getCellsNb(this.refRow);
for (let i = 0; i &lt; len; i++) {
if (continueFn(i) === true) {
continue;
}
if (breakFn(i) === true) {
break;
}
fn(i);
}
}
/**
* Rows iterator starting from supplied row index or defaulting to reference
* row index. Closure function accepts a callback function and optional
* continue and break callbacks.
* @param {Number} startIdx Row index from which filtering starts
*/
eachRow(startIdx = this.refRow) {
return (fn = EMPTY_FN, continueFn = EMPTY_FN, breakFn = EMPTY_FN) =&gt; {
let rows = this.dom().rows;
let len = this.getRowsNb(true);
for (let i = startIdx; i &lt; len; i++) {
if (continueFn(rows[i], i) === true) {
continue;
}
if (breakFn(rows[i], i) === true) {
break;
}
fn(rows[i], i);
}
};
}
/**
* Check if passed script or stylesheet is already imported
* @param {String} filePath Ressource path
* @param {String} type Possible values: &apos;script&apos; or &apos;link&apos;
* @return {Boolean}
*/
isImported(filePath, type = &apos;script&apos;) {
let imported = false,
attr = type === &apos;script&apos; ? &apos;src&apos; : &apos;href&apos;,
files = tag(doc, type);
for (let i = 0, len = files.length; i &lt; len; i++) {
if (isUndef(files[i][attr])) {
continue;
}
if (files[i][attr].match(filePath)) {
imported = true;
break;
}
}
return imported;
}
/**
* Import script or stylesheet
* @param {String} fileId Ressource ID
* @param {String} filePath Ressource path
* @param {Function} callback Callback
* @param {String} type Possible values: &apos;script&apos; or &apos;link&apos;
*/
import(fileId, filePath, callback, type = &apos;script&apos;) {
if (this.isImported(filePath, type)) {
return;
}
let o = this,
isLoaded = false,
file,
head = tag(doc, &apos;head&apos;)[0];
if (type.toLowerCase() === &apos;link&apos;) {
file = createElm(&apos;link&apos;,
[&apos;id&apos;, fileId], [&apos;type&apos;, &apos;text/css&apos;],
[&apos;rel&apos;, &apos;stylesheet&apos;], [&apos;href&apos;, filePath]
);
} else {
file = createElm(&apos;script&apos;,
[&apos;id&apos;, fileId],
[&apos;type&apos;, &apos;text/javascript&apos;], [&apos;src&apos;, filePath]
);
}
//Browser &lt;&gt; IE onload event works only for scripts, not for stylesheets
file.onload = file.onreadystatechange = () =&gt; {
if (!isLoaded &amp;&amp;
(!this.readyState || this.readyState === &apos;loaded&apos; ||
this.readyState === &apos;complete&apos;)) {
isLoaded = true;
if (typeof callback === &apos;function&apos;) {
callback.call(null, o);
}
}
};
file.onerror = () =&gt; {
throw new Error(`TableFilter could not load: ${filePath}`);
};
head.appendChild(file);
}
/**
* Check if table has filters grid
* @return {Boolean}
*/
isInitialized() {
return this.initialized;
}
/**
* Get list of filter IDs
* @return {Array} List of filters ids
*/
getFiltersId() {
return this.fltIds || [];
}
/**
* Get filtered (valid) rows indexes
* @param {Boolean} reCalc Force calculation of filtered rows list
* @return {Array} List of row indexes
*/
getValidRows(reCalc) {
if (!reCalc) {
return this.validRowsIndex;
}
this.validRowsIndex = [];
let eachRow = this.eachRow();
eachRow((row) =&gt; {
if (!this.paging) {
if (this.getRowDisplay(row) !== NONE) {
this.validRowsIndex.push(row.rowIndex);
}
} else {
if (row.getAttribute(&apos;validRow&apos;) === &apos;true&apos; ||
row.getAttribute(&apos;validRow&apos;) === null) {
this.validRowsIndex.push(row.rowIndex);
}
}
});
return this.validRowsIndex;
}
/**
* Get the index of the row containing the filters
* @return {Number}
*/
getFiltersRowIndex() {
return this.filtersRowIndex;
}
/**
* Get the index of the headers row
* @return {Number}
*/
getHeadersRowIndex() {
return this.headersRow;
}
/**
* Get the row index from where the filtering process start (1st filterable
* row)
* @return {Number}
*/
getStartRowIndex() {
return this.refRow;
}
/**
* Get the index of the last row
* @return {Number}
*/
getLastRowIndex() {
let nbRows = this.getRowsNb(true);
return (nbRows - 1);
}
/**
* Determine whether the specified column has one of the passed types
* @param {Number} colIndex Column index
* @param {Array} [types=[]] List of column types
* @return {Boolean}
*/
hasType(colIndex, types = []) {
if (this.colTypes.length === 0) {
return false;
}
let colType = this.colTypes[colIndex];
if (isObj(colType)) {
colType = colType.type;
}
return types.indexOf(colType) !== -1;
}
/**
* Get the header DOM element for a given column index
* @param {Number} colIndex Column index
* @return {Element}
*/
getHeaderElement(colIndex) {
let table = this.gridLayout ? this.Mod.gridLayout.headTbl : this.dom();
let tHead = tag(table, &apos;thead&apos;);
let rowIdx = this.getHeadersRowIndex();
let header;
if (tHead.length === 0) {
header = table.rows[rowIdx].cells[colIndex];
}
if (tHead.length === 1) {
header = tHead[0].rows[rowIdx].cells[colIndex];
}
return header;
}
/**
* Return the list of headers&apos; text
* @param {Boolean} excludeHiddenCols Optional: exclude hidden columns
* @return {Array} list of headers&apos; text
*/
getHeadersText(excludeHiddenCols = false) {
let headers = [];
this.eachCol(
(j) =&gt; {
let header = this.getHeaderElement(j);
let headerText = getFirstTextNode(header);
headers.push(headerText);
},
// continue condition function
(j) =&gt; {
if (excludeHiddenCols &amp;&amp; this.hasExtension(&apos;colsVisibility&apos;)) {
return this.extension(&apos;colsVisibility&apos;).isColHidden(j);
}
return false;
}
);
return headers;
}
/**
* Return the filter type for a specified column
* @param {Number} colIndex Column&apos;s index
* @return {String}
*/
getFilterType(colIndex) {
return this.filterTypes[colIndex];
}
/**
* Get the total number of filterable rows
* @return {Number}
*/
getFilterableRowsNb() {
return this.getRowsNb(false);
}
/**
* Return the total number of valid rows
* @param {Boolean} [reCalc=false] Forces calculation of filtered rows
* @return {Number}
*/
getValidRowsNb(reCalc = false) {
return this.getValidRows(reCalc).length;
}
/**
* Return the working DOM element
* @return {HTMLTableElement}
*/
dom() {
return this.tbl;
}
/**
* Return the decimal separator for supplied column as per column type
* configuration or global setting
* @param {Number} colIndex Column index
* @returns {String} &apos;.&apos; or &apos;,&apos;
*/
getDecimal(colIndex) {
let decimal = this.decimalSeparator;
if (this.hasType(colIndex, [FORMATTED_NUMBER])) {
let colType = this.colTypes[colIndex];
if (colType.hasOwnProperty(&apos;decimal&apos;)) {
decimal = colType.decimal;
}
}
return decimal;
}
/**
* Get the configuration object (literal object)
* @return {Object}
*/
config() {
return this.cfg;
}
}
</code></pre>
</div>
<footer class="footer">
Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(1.1.0)</span><img src="./image/esdoc-logo-mini-black.png"></a>
</footer>
<script src="script/search_index.js"></script>
<script src="script/search.js"></script>
<script src="script/pretty-print.js"></script>
<script src="script/inherited-summary.js"></script>
<script src="script/test-summary.js"></script>
<script src="script/inner-link.js"></script>
<script src="script/patch-for-local.js"></script>
</body>
</html>