1
0
Fork 0
mirror of https://github.com/koalyptus/TableFilter.git synced 2024-05-04 07:33:18 +02:00

Merge branch 'master' into 358-increase-coverage

This commit is contained in:
koalyptus 2017-07-30 11:03:29 +10:00
commit 04d8fd3d14
103 changed files with 3313 additions and 2161 deletions

View file

@ -1,18 +1,20 @@
{
"parser": "babel-eslint",
"parserOptions": {
"sourceType": "module"
"sourceType": "module",
"ecmaFeatures": { "modules": true }
},
"rules": {
"max-len": [2, 80, 2, {"ignoreUrls": true}],
"indent": [2, 4, {"SwitchCase": 1}],
"semi": ["error", "always"],
"no-trailing-spaces": 2,
"no-multi-spaces": 2,
"array-bracket-spacing": 2,
"keyword-spacing": ["error", { "after": true, "before": true }],
"max-depth": [2, 7],
"max-statements": [2, 144],
"complexity": [2, 78],
"max-statements": [2, 143],
"complexity": [2, 32],
"no-unused-vars": 2,
"no-eval": 2,
"no-underscore-dangle": 0,
@ -24,9 +26,6 @@
"new-cap": 2,
"radix": [2, "always"]
},
"ecmaFeatures": {
"modules": true
},
"env": {
"es6": true,
"browser": true,

View file

@ -11,6 +11,7 @@ script:
branches:
only:
- master
- /^greenkeeper/.*$/
env:
global:
- secure: A1G8GvJkV0rjy7XCTVdOpTHy3xaoSZZAbMWhI+ikrqBqd8mRz+sB71FhRusouTcYdsT5VfF9Io2doS8LKAeP0TNC34Pp0uvjtsvarzn8a/oNEOuqR3Ub0ws2bmbZIZc+wOpgErKOj1H1QSJAUpd6ZjIuEAbOVXlhGBJz3zUCmcpRDh32CpFKC62oFWeGlvttxPciLLzBfKgkVKEGhPtdGP/xCHL1MCQptYVHZiXwWsaIQ5wHFO6KCVlRrPgdfOL+Yce3mT02iXH6ZjW6U6zA6vYQVQZVD873AkU5RmirYblW+jW1wdvu4UXI71lSH6Z3uXRVnrw1b0TsLVTjP9ZUbCtkTHtLbxYzeDjEukxKoCjpAppIhOtaNIxrdA8oKJAabQYp5X+QK6lkosy0zdT5u2B1+g8unZhsf0y//7lgLUe04iQ7sc1Q6AHiiEGtByaXg4BHNW53bUfKgNnbV4+IbXf8rz5wWOxL2/yWAU/GoiszjqRQfajAXCpSf6SyMjXjhhvQdeFn+Cz6FwdtaxH+tOIY0Hq9Gqy1xrLIkv/httd3O+AbhLrU1c/M0MwlFQue7GeJb7ZyF3KsK7bXvoz2dEqvzHd98NZXiQEqFXCIs77uVh4eZMoYrbEyrkOAgkUZNQYhHh9fuvfynJ/zgUvyA0v3GUvBebq3ybYKD/vqX7s=

View file

@ -1,6 +1,7 @@
[![Build Status](https://api.travis-ci.org/koalyptus/TableFilter.svg?branch=master)](https://travis-ci.org/koalyptus/TableFilter)
[![Document](http://koalyptus.github.io/TableFilter/docs/badge.svg)](https://koalyptus.github.io/TableFilter/docs/source)
[![Document](https://koalyptus.github.io/TableFilter/docs/badge.svg)](https://koalyptus.github.io/TableFilter/docs/source.html)
[![codecov](https://codecov.io/gh/koalyptus/TableFilter/branch/master/graph/badge.svg)](https://codecov.io/gh/koalyptus/TableFilter)
[![Greenkeeper badge](https://badges.greenkeeper.io/koalyptus/TableFilter.svg)](https://greenkeeper.io/)
# TableFilter
@ -32,23 +33,40 @@ git clone https://github.com/koalyptus/TableFilter.git
* You can [download](https://github.com/koalyptus/TableFilter/archive/master.zip) this repository.
* Alternatively, install TableFilter files in your npm enabled project using:
* TableFilter is available on [npm repository](https://www.npmjs.com/package/tablefilter), you can install it from the command line using the following command:
```shell
npm install tablefilter --save-dev
```
```
* or get the future features from the ``next`` release channel:
```shell
npm install tablefilter@next --save-dev
```
* If you don't use `npm`, you can also
[access these files on unpkg](https://unpkg.com/tablefilter/), download them
or point your package manager to them.
* Alternatively you can also [access these files from unpkg CDN](https://unpkg.com/tablefilter/), download them or point your package manager to them.
## Setup
### Using modules
Require `TableFilter`:
```javascript
// ES2015 modules
import TableFilter from 'tablefilter';
// CommonJS or AMD modules
var TableFilter = require('tablefilter');
```
### Using distribution scripts
If you are not using a module system, you can reference the distribution scripts directly in your html pages:
```html
<script src="path_to/node_modules/tablefilter/dist/tablefilter/tablefilter.js"></script>
```
### Placing manually the distribution scripts in your project
Copy the ``tablefilter`` directory under ``dist`` and place it at desired location in your project. Then include the main js file in your page:
```shell
<script src="path/to/my/scripts/tablefilter/tablefilter.js"></script>
```
### Usage
Place the following snippet just under the HTML table and always define a ``base_path`` property in the configuration object to reflect the path to the script
```shell
<script>
@ -62,7 +80,7 @@ If the ``base_path`` property is not specified, it will default to ``/tablefilte
```shell
your-page.html
|— tablefilter
```
```
## Development
This project requires node.js and Grunt to be installed:
@ -77,24 +95,24 @@ Start by installing any dependencies.
```shell
npm install
```
Use
Use
```shell
npm run dev
```
```
command to launch a build / watch cycle and start the local
sever on port ``8080``.
Use
Use
```shell
npm run build
```
```
command to generate a production build.
The
The
```shell
npm run dist
```
command will create a production build, run the tests and finally generate
```
command will create a production build, run the tests and finally generate
the demos:
To run all the tests and generate the coverage report:
@ -115,7 +133,7 @@ to view the coverage report(s), open the `index.html` under the
[online](https://codecov.io/gh/koalyptus/TableFilter).
## Demos
Check out the online [examples](http://koalyptus.github.io/TableFilter/examples)
Check out the online [examples](http://koalyptus.github.io/TableFilter/examples)
or generate the demos locally:
```shell
npm run build:demos
@ -143,7 +161,7 @@ npm run esdoc
```
## Support
* GitHub for reporting bugs and feature requests.
* GitHub for [reporting bugs](https://github.com/koalyptus/TableFilter/blob/master/CONTRIBUTING.md#reporting-bugs) and [feature requests](https://github.com/koalyptus/TableFilter/blob/master/CONTRIBUTING.md#suggesting-enhancements-and-features).
## License
[MIT](LICENSE)

4
dist/starter.html vendored
View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>tablefilter v0.5.6 - Starter</title>
<title>tablefilter v0.5.34 - Starter</title>
</head>
<body>
<h1>tablefilter v0.5.6</h1>
<h1>tablefilter v0.5.34</h1>

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.5.6 by Max Guglielmi
* build date: 2017-04-10T16:27:15.240Z
* tablefilter v0.5.34 by Max Guglielmi
* build date: 2017-07-29T00:57:49.938Z
* MIT License
*/
span.colVisSpan{text-align:left;}span.colVisSpan a.colVis{display:inline-block;padding:7px 5px 0;font-size:inherit;font-weight:inherit;vertical-align:top}div.colVisCont{position:relative;background:#fff;-webkit-box-shadow:3px 3px 2px #888;-moz-box-shadow:3px 3px 2px #888;box-shadow:3px 3px 2px #888;position:absolute;display:none;border:1px solid #ccc;height:auto;width:250px;background-color:#fff;margin:35px 0 0 -100px;z-index:10000;padding:10px 10px 10px 10px;text-align:left;font-size:12px;}div.colVisCont:after,div.colVisCont:before{bottom:100%;left:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}div.colVisCont:after{border-color:rgba(255,255,255,0);border-bottom-color:#fff;border-width:10px;margin-left:-10px}div.colVisCont:before{border-color:rgba(255,255,255,0);border-bottom-color:#ccc;border-width:12px;margin-left:-12px}div.colVisCont p{margin:6px auto 6px auto}div.colVisCont a.colVis{display:initial;font-weight:inherit}ul.cols_checklist{padding:0;margin:0;list-style:none;}ul.cols_checklist label{display:block}ul.cols_checklist input{vertical-align:middle;margin:2px 5px 2px 1px}li.cols_checklist_item{padding:4px;margin:0;}li.cols_checklist_item:hover{background-color:#335ea8;color:#fff}.cols_checklist_slc_item{background-color:#335ea8;color:#fff}

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.5.6 by Max Guglielmi
* build date: 2017-04-10T16:27:15.240Z
* tablefilter v0.5.34 by Max Guglielmi
* build date: 2017-07-29T00:57:49.938Z
* MIT License
*/
span.expClpFlt a.btnExpClpFlt{width:35px;height:35px;display:inline-block;}span.expClpFlt a.btnExpClpFlt:hover{background-color:#f4f4f4}span.expClpFlt img{padding:8px 11px 11px 11px}

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.5.6 by Max Guglielmi
* build date: 2017-04-10T16:27:15.240Z
* tablefilter v0.5.34 by Max Guglielmi
* build date: 2017-07-29T00:57:49.938Z
* MIT License
*/
.activeHeader{background-color:#66afe9 !important;color:#fff !important}
@ -8,8 +8,8 @@
.ezActiveRow{background-color:#2852a8 !important;color:#fff}.ezSelectedRow{background-color:#316ac5 !important;color:#fff}.ezActiveCell{background-color:#d9e8fb !important;color:#000 !important;font-weight:bold}.ezETSelectedCell{background-color:#ffdc61 !important;font-weight:bold;color:#000 !important}.ezUnselectable{-moz-user-select:-moz-none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.ezInputEditor{width:95%;height:auto;font-size:inherit;border:1px solid #aaccf6}.ezTextareaEditor{width:95%;height:35px;font-size:inherit;border:1px solid #aaccf6}.ezSelectEditor{width:100%;font-size:inherit;border:1px solid #aaccf6}.ezModifiedCell{background:transparent url("themes/bg_mod_cell.png") 0 0 no-repeat}select[multiple="multiple"].ezSelectEditor{height:35px}.ezCommandEditor{margin:2px;}.ezCommandEditor button,.ezCommandEditor input[type="button"]{min-height:22px;margin:1px;padding:3px;border:1px solid #ccc;background:#fff;border-radius:4px 4px 4px 4px;-moz-border-radius:4px 4px 4px 4px;}.ezCommandEditor button:hover,.ezCommandEditor input[type="button"]:hover{border:1px solid #999}.ezCommandEditor img{border:0;vertical-align:middle;margin:2px}.ezOpacity{opacity:.6}.alignLeft{text-align:left}.alignCenter{text-align:center}.alignRight{text-align:right}
.div_checklist{width:100%;height:90px;line-height:24px;border:1px solid #f4f4f4;overflow:auto;text-align:left;background-color:#fff;color:#444;}.div_checklist ul.flt_checklist{padding:0 !important;margin:0 !important;list-style:none !important}.div_checklist li.flt_checklist_item{padding:1px !important;margin:0 !important;font-size:10px !important;border-bottom:1px solid #f4f4f4 !important;}.div_checklist li.flt_checklist_item:hover{background-color:#335ea8 !important;color:#fff !important}.div_checklist label{display:block !important}.div_checklist input{vertical-align:middle !important;margin:2px 5px 2px 1px !important}.flt_checklist_item_disabled{background-color:#e5e5e5}.flt_checklist_slc_item{background-color:#335ea8 !important;color:#fff !important}
.fltrow{height:1em;background-color:#eaeaea;}.fltrow td{border-bottom:1px solid #ccc !important;border-top:1px solid #f4f4f4;border-left:1px solid #ccc;border-right:1px solid #f4f4f4;padding:.2em !important;}.fltrow td:last-child{border-right:1px solid #ccc}.btnflt{height:35px;font-family:inherit;font-size:inherit;vertical-align:middle;margin:0 2px 0 2px;padding:0 1px 0 1px}.btnflt_icon{font-family:inherit;font-size:inherit;width:35px;height:35px;cursor:pointer !important;border:0 !important;vertical-align:middle;background:transparent url("themes/btn_filter.png") center center no-repeat !important}.flt,.flt_s,.single_flt{font-family:inherit;display:block;color:#444;background-color:#fff;border:1px inset #f4f4f4;margin:0;padding:0 0 0 .2em;width:100%;height:35px;vertical-align:middle;border-radius:2px;box-sizing:border-box;}.flt:focus,.flt_s:focus,.single_flt:focus{border-color:#66afe9;outline:0 none;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.075) inset,0 0 8px rgba(102,175,233,0.6);-moz-box-shadow:0 1px 1px rgba(0,0,0,0.075) inset,0 0 8px rgba(102,175,233,0.6);box-shadow:0 1px 1px rgba(0,0,0,0.075) inset,0 0 8px rgba(102,175,233,0.6)}select.flt_multi{font-family:inherit;color:#444;background-color:#fff;border:1px solid #f4f4f4;margin:0;padding:.2em;width:100%;height:90px;vertical-align:middle;box-sizing:border-box;}select.flt_multi option{padding-top:5px;padding-bottom:5px}.flt_s{width:60%;box-sizing:initial;display:initial}.single_flt{width:70%;box-sizing:initial;display:initial}div.popUpFilter{position:relative;background:#fff;-webkit-box-shadow:3px 3px 2px #888;-moz-box-shadow:3px 3px 2px #888;box-shadow:3px 3px 2px #888;margin:30px auto 0 0;position:absolute;display:none;width:100px;background-color:#eaeaea;border:1px solid #eaeaea;padding:0}div.popUpFilter:after,div.popUpFilter:before{bottom:100%;left:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}div.popUpFilter:after{border-color:rgba(255,255,255,0);border-bottom-color:#fff;border-width:10px;margin-left:-10px}div.popUpFilter:before{border-color:rgba(255,255,255,0);border-bottom-color:#eaeaea;border-width:12px;margin-left:-12px}
div.grd_Cont{-webkit-box-shadow:4px 4px 10px 0 rgba(50,50,50,0.75);-moz-box-shadow:4px 4px 10px 0 rgba(50,50,50,0.75);box-shadow:4px 4px 10px 0 rgba(50,50,50,0.75);width:800px;height:auto;overflow:hidden;padding:3px 3px 3px 3px;background-color:#c8e0fb;border:1px solid #99bbe8;}div.grd_Cont .fltrow{background-color:transparent}div.grd_Cont .flt{border:1px solid #99bbe8;width:100%;}div.grd_Cont .flt :focus{border:1px solid #558dd9}div.grd_Cont .even{background-color:#fff}div.grd_Cont .odd{background-color:#dfe8f6}div.grd_Cont .no-results{background-color:transparent}div.grd_Cont .sort-arrow{position:initial}div.grd_tblCont{height:400px;width:800px;background:#fff;overflow-x:auto;overflow-y:scroll}div.grd_headTblCont{height:auto;width:800px;overflow:hidden;border-bottom:1px solid #99bbe8;background-color:#c8e0fb}div.grd_tblCont table,div.grd_headTblCont table{border-collapse:collapse;table-layout:fixed;box-sizing:initial}div.grd_tblCont table{border-right:1px solid #99bbe8;box-sizing:initial}div.grd_tblCont table th,div.grd_headTblCont table th,div.grd_headTblCont table td{height:35px;background-color:#c8e0fb;padding:.1em .5em;color:#333;border-right:1px solid #99bbe8 !important;overflow:hidden;text-overflow:ellipsis}div.grd_headTblCont table td{padding:.2em .2em}div.grd_tblCont table td{padding:.5em .7em;border-bottom:1px solid #99bbe8;overflow:hidden;text-overflow:ellipsis}.grd_inf{clear:both;width:auto;height:35px;background-color:#c8e0fb;margin:0;padding:1px 3px 1px 3px;border-top:1px solid #99bbe8;}.grd_inf a{color:#333;text-decoration:none;font-weight:bold;}.grd_inf a:hover{text-decoration:underline;background-color:transparent}.grd_inf input.reset:hover{background-color:transparent}.grd_inf .mdiv{width:40% !important}.grd_inf .ldiv div{border:0}.grd_inf .helpBtn{border:0 !important}.grd_inf div.status{position:absolute;float:none !important;height:auto !important;margin:19px 0 !important;font-size:12px;color:#333;border:0 !important}.grd_inf div.tot{border:0 !important}
.fltrow{height:1em;background-color:#eaeaea;}.fltrow td{border-bottom:1px solid #ccc !important;border-top:1px solid #f4f4f4;border-left:1px solid #ccc;border-right:1px solid #f4f4f4;padding:.2em !important;}.fltrow td:last-child{border-right:1px solid #ccc}.btnflt{height:35px;font-family:inherit;font-size:inherit;vertical-align:middle;margin:0 2px 0 2px;padding:0 1px 0 1px}.btnflt_icon{font-family:inherit;font-size:inherit;width:35px;height:35px;cursor:pointer !important;border:0 !important;vertical-align:middle;background:transparent url("themes/btn_filter.png") center center no-repeat !important}.flt,.flt_s,.single_flt{font-family:inherit;display:block;color:#444;background-color:#fff;border:1px inset #f4f4f4;margin:0;padding:0 0 0 .2em;width:100%;height:35px;vertical-align:middle;border-radius:2px;box-sizing:border-box;}.flt:focus,.flt_s:focus,.single_flt:focus{border-color:#66afe9;outline:0 none;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.075) inset,0 0 8px rgba(102,175,233,0.6);-moz-box-shadow:0 1px 1px rgba(0,0,0,0.075) inset,0 0 8px rgba(102,175,233,0.6);box-shadow:0 1px 1px rgba(0,0,0,0.075) inset,0 0 8px rgba(102,175,233,0.6)}select.flt_multi{font-family:inherit;color:#444;background-color:#fff;border:1px solid #f4f4f4;margin:0;padding:.2em;width:100%;height:90px;vertical-align:middle;box-sizing:border-box;}select.flt_multi option{padding-top:5px;padding-bottom:5px}.flt_s{width:60%;box-sizing:initial;display:initial}.single_flt{width:70%;box-sizing:initial;display:initial}div.popUpFilter{position:relative;background:#fff;-webkit-box-shadow:3px 3px 2px #888;-moz-box-shadow:3px 3px 2px #888;box-shadow:3px 3px 2px #888;margin:30px auto 0 0;position:absolute;display:none;width:100px;background-color:#eaeaea;border:1px solid #eaeaea;padding:0}div.popUpFilter:after,div.popUpFilter:before{bottom:100%;left:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}div.popUpFilter:after{border-color:rgba(255,255,255,0);border-bottom-color:#fff;border-width:10px;margin-left:-10px}div.popUpFilter:before{border-color:rgba(255,255,255,0);border-bottom-color:#eaeaea;border-width:12px;margin-left:-12px}.popUpPlaceholder{position:relative}
div.grd_Cont{-webkit-box-shadow:4px 4px 10px 0 rgba(50,50,50,0.75);-moz-box-shadow:4px 4px 10px 0 rgba(50,50,50,0.75);box-shadow:4px 4px 10px 0 rgba(50,50,50,0.75);width:800px;height:auto;overflow:hidden;background-color:#c8e0fb;border:1px solid #99bbe8;}div.grd_Cont .fltrow{background-color:transparent}div.grd_Cont .flt{border:1px solid #99bbe8;width:100%;}div.grd_Cont .flt :focus{border:1px solid #558dd9}div.grd_Cont .even{background-color:#fff}div.grd_Cont .odd{background-color:#dfe8f6}div.grd_Cont .no-results{background-color:transparent}div.grd_Cont .sort-arrow{position:initial}div.grd_tblCont{height:400px;width:800px;background:#fff;overflow-x:auto;overflow-y:scroll}div.grd_headTblCont{display:block;margin-right:20px;height:auto;overflow:hidden;border-bottom:1px solid #99bbe8;background-color:#c8e0fb}div.grd_tblCont table,div.grd_headTblCont table{border-collapse:collapse;table-layout:fixed;box-sizing:initial}div.grd_tblCont table th,div.grd_headTblCont table th,div.grd_headTblCont table td{height:35px;background-color:#c8e0fb;padding:.1em .5em;color:#333;border-right:1px solid #99bbe8 !important;overflow:hidden;text-overflow:ellipsis}div.grd_headTblCont table td{padding:.2em .2em}div.grd_tblCont table td{padding:.5em .7em;border-bottom:1px solid #99bbe8;overflow:hidden;text-overflow:ellipsis}.grd_inf{clear:both;width:auto;height:35px;background-color:#c8e0fb;margin:0;padding:1px 3px 1px 3px;border-top:1px solid #99bbe8;}.grd_inf a{color:#333;text-decoration:none;font-weight:bold;}.grd_inf a:hover{text-decoration:underline;background-color:transparent}.grd_inf input.reset:hover{background-color:transparent}.grd_inf .mdiv{width:40% !important}.grd_inf .ldiv div{border:0}.grd_inf .helpBtn{border:0 !important}.grd_inf div.status{position:absolute;float:none !important;height:auto !important;margin:19px 0 !important;font-size:12px;color:#333;border:0 !important}.grd_inf div.tot{border:0 !important}
.helpBtn{display:inline-block;height:27px;margin:0;padding:8px 15px 0 15px;vertical-align:top;}.helpBtn:hover{background-color:#f4f4f4}div.helpCont{position:relative;background:#fff;-webkit-box-shadow:3px 3px 2px #888;-moz-box-shadow:3px 3px 2px #888;box-shadow:3px 3px 2px #888;position:absolute;display:none;width:300px;padding:10px;margin:45px 0 0 -150px;border:1px solid #ccc;line-height:20px;font-size:inherit;color:#333;background:#fff;text-align:left;}div.helpCont:after,div.helpCont:before{bottom:100%;left:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}div.helpCont:after{border-color:rgba(255,255,255,0);border-bottom-color:#fff;border-width:10px;margin-left:-10px}div.helpCont:before{border-color:rgba(255,255,255,0);border-bottom-color:#ccc;border-width:12px;margin-left:-12px}div.helpCont a{color:#c00;text-decoration:underline;font-weight:normal}div.helpCont a.close{color:#333 !important;text-decoration:none !important;font-weight:bold;}div.helpCont a.close:hover{text-decoration:none}div.helpCont hr{border:1px solid #ccc}div.helpFooter{margin:10px 0 0 0;}div.helpFooter h4{margin:2px 2px 2px 2px;color:#333}
span.keyword{font-weight:700;font-style:italic;border-bottom:1px dotted #ccc}
.loader{position:absolute;padding:.5em .7em;margin:10em 0 0 3em;width:auto;z-index:1000;font-weight:600;background-color:#a7a7a8;vertical-align:middle;border-radius:10px;color:#fff;text-shadow:1px 1px #333}

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.5.6 by Max Guglielmi
* build date: 2017-04-10T16:27:15.240Z
* tablefilter v0.5.34 by Max Guglielmi
* build date: 2017-07-29T00:57:49.938Z
* MIT License
*/
table.TF{border-left:1px solid #ccc;border-top:none;border-right:none;border-bottom:none;}table.TF th{background:#ebecee url("images/bg_th.jpg") left top repeat-x;border-bottom:1px solid #d0d0d0;border-right:1px solid #d0d0d0;border-left:1px solid #fff;border-top:1px solid #fff;color:#333}table.TF td{border-bottom:1px dotted #999;padding:5px}.fltrow{background-color:#ebecee !important;}.fltrow th,.fltrow td{border-bottom:1px dotted #666 !important;padding:1px 3px 1px 3px !important}.flt,select.flt,select.flt_multi,.flt_s,.single_flt,.div_checklist{border:1px solid #999 !important}input.flt{width:99% !important}.inf{height:$min-height;background:#d7d7d7 url("images/bg_infDiv.jpg") 0 0 repeat-x !important}input.reset{background:transparent url("images/btn_eraser.gif") center center no-repeat !important}.helpBtn:hover{background-color:transparent}.nextPage{background:transparent url("images/btn_next_page.gif") center center no-repeat !important;}.nextPage:hover{background:transparent url("images/btn_over_next_page.gif") center center no-repeat !important}.previousPage{background:transparent url("images/btn_previous_page.gif") center center no-repeat !important;}.previousPage:hover{background:transparent url("images/btn_over_previous_page.gif") center center no-repeat !important}.firstPage{background:transparent url("images/btn_first_page.gif") center center no-repeat !important;}.firstPage:hover{background:transparent url("images/btn_over_first_page.gif") center center no-repeat !important}.lastPage{background:transparent url("images/btn_last_page.gif") center center no-repeat !important;}.lastPage:hover{background:transparent url("images/btn_over_last_page.gif") center center no-repeat !important}div.grd_Cont{background-color:#ebecee !important;border:1px solid #ccc !important;padding:0 !important;}div.grd_Cont .even{background-color:#fff}div.grd_Cont .odd{background-color:#d5d5d5}div.grd_headTblCont{background-color:#ebecee !important;border-bottom:none !important;}div.grd_headTblCont table{border-right:none !important}div.grd_tblCont table th,div.grd_headTblCont table th,div.grd_headTblCont table td{background:#ebecee url("images/bg_th.jpg") left top repeat-x !important;border-bottom:1px solid #d0d0d0 !important;border-right:1px solid #d0d0d0 !important;border-left:1px solid #fff !important;border-top:1px solid #fff !important}div.grd_tblCont table td{border-bottom:1px solid #999 !important}.grd_inf{background:#d7d7d7 url("images/bg_infDiv.jpg") 0 0 repeat-x !important;border-top:1px solid #d0d0d0 !important}.loader{border:1px solid #999}.defaultLoader{width:32px;height:32px;background:transparent url("images/img_loading.gif") 0 0 no-repeat !important}.even{background-color:#fff}.odd{background-color:#d5d5d5}span.expClpFlt a.btnExpClpFlt:hover{background-color:transparent !important}.activeHeader{background:#999 !important}

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.5.6 by Max Guglielmi
* build date: 2017-04-10T16:27:15.240Z
* tablefilter v0.5.34 by Max Guglielmi
* build date: 2017-07-29T00:57:49.938Z
* MIT License
*/
table.TF{border-left:1px dotted #81963b;border-top:none;border-right:0;border-bottom:none;}table.TF th{background:#39424b url("images/bg_headers.jpg") left top repeat-x;border-bottom:0;border-right:1px dotted #d0d0d0;border-left:0;border-top:0;color:#fff}table.TF td{border-bottom:1px dotted #81963b;border-right:1px dotted #81963b;padding:5px}.fltrow{background-color:#81963b !important;}.fltrow th,.fltrow td{border-bottom:1px dotted #39424b !important;border-right:1px dotted #fff !important;border-left:0 !important;border-top:0 !important;padding:1px 3px 1px 3px !important}.flt,select.flt,select.flt_multi,.flt_s,.single_flt,.div_checklist{border:1px solid #687830 !important}input.flt{width:99% !important}.inf{background:#d8d8d8;height:$min-height}input.reset{width:53px;background:transparent url("images/btn_filter.png") center center no-repeat !important}.helpBtn:hover{background-color:transparent}.nextPage{background:transparent url("images/btn_next_page.gif") center center no-repeat !important}.previousPage{background:transparent url("images/btn_previous_page.gif") center center no-repeat !important}.firstPage{background:transparent url("images/btn_first_page.gif") center center no-repeat !important}.lastPage{background:transparent url("images/btn_last_page.gif") center center no-repeat !important}div.grd_Cont{background:#81963b url("images/bg_headers.jpg") left top repeat-x !important;border:1px solid #ccc !important;padding:0 1px 1px 1px !important;}div.grd_Cont .even{background-color:#bccd83}div.grd_Cont .odd{background-color:#fff}div.grd_headTblCont{background-color:#ebecee !important;border-bottom:none !important}div.grd_tblCont table{border-right:none !important;}div.grd_tblCont table td{border-bottom:1px dotted #81963b;border-right:1px dotted #81963b}div.grd_tblCont table th,div.grd_headTblCont table th{background:transparent url("images/bg_headers.jpg") 0 0 repeat-x !important;border-bottom:0 !important;border-right:1px dotted #d0d0d0 !important;border-left:0 !important;border-top:0 !important;padding:0 4px 0 4px !important;color:#fff !important;height:35px !important}div.grd_headTblCont table td{border-bottom:1px dotted #39424b !important;border-right:1px dotted #fff !important;border-left:0 !important;border-top:0 !important;background-color:#81963b !important;padding:1px 3px 1px 3px !important}.grd_inf{background-color:#d8d8d8;border-top:1px solid #d0d0d0 !important}.loader{border:0 !important;background:#81963b !important}.defaultLoader{width:32px;height:32px;background:transparent url("images/img_loading.gif") 0 0 no-repeat !important}.even{background-color:#bccd83}.odd{background-color:#fff}span.expClpFlt a.btnExpClpFlt:hover{background-color:transparent !important}.activeHeader{background:#81963b !important}

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.5.6 by Max Guglielmi
* build date: 2017-04-10T16:27:15.240Z
* tablefilter v0.5.34 by Max Guglielmi
* build date: 2017-07-29T00:57:49.938Z
* MIT License
*/
table.TF{padding:0;color:#000;border-right:1px solid #a4bed4;border-top:1px solid #a4bed4;border-left:1px solid #a4bed4;border-bottom:0;}table.TF th{margin:0;color:inherit;background:#d1e5fe url("images/bg_skyblue.gif") 0 0 repeat-x;border-color:#fdfdfd #a4bed4 #a4bed4 #fdfdfd;border-width:1px;border-style:solid}table.TF td{margin:0;padding:5px;color:inherit;border-bottom:1px solid #a4bed4;border-left:0;border-top:0;border-right:0}.fltrow{background-color:#d1e5fe !important;}.fltrow th,.fltrow td{padding:1px 3px 1px 3px !important}.flt,select.flt,select.flt_multi,.flt_s,.single_flt,.div_checklist{border:1px solid #a4bed4 !important}input.flt{width:99% !important}.inf{background-color:#e3efff !important;border:1px solid #a4bed4;height:$min-height;color:#004a6f}div.tot,div.status{border-right:0 !important}.helpBtn:hover{background-color:transparent}input.reset{background:transparent url("images/icn_clear_filters.png") center center no-repeat !important}.nextPage{background:transparent url("images/btn_next_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.nextPage:hover{background:#ffe4ab url("images/btn_next_page.gif") center center no-repeat !important;border:1px solid #ffb552 !important}.previousPage{background:transparent url("images/btn_prev_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.previousPage:hover{background:#ffe4ab url("images/btn_prev_page.gif") center center no-repeat !important;border:1px solid #ffb552 !important}.firstPage{background:transparent url("images/btn_first_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.firstPage:hover{background:#ffe4ab url("images/btn_first_page.gif") center center no-repeat !important;border:1px solid #ffb552 !important}.lastPage{background:transparent url("images/btn_last_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.lastPage:hover{background:#ffe4ab url("images/btn_last_page.gif") center center no-repeat !important;border:1px solid #ffb552 !important}.activeHeader{background:#ffe4ab !important;border:1px solid #ffb552 !important;color:inherit !important}div.grd_Cont{background-color:#d9eaed !important;border:1px solid #9cc !important;padding:0 !important;}div.grd_Cont .even{background-color:#fff}div.grd_Cont .odd{background-color:#e3efff}div.grd_headTblCont{background-color:#d9eaed !important;border-bottom:none !important}div.grd_tblCont table{border-right:none !important}div.grd_tblCont table th,div.grd_headTblCont table th,div.grd_headTblCont table td{background:#d9eaed url("images/bg_skyblue.gif") left top repeat-x;border-bottom:1px solid #a4bed4;border-right:1px solid #a4bed4 !important;border-left:1px solid #fff !important;border-top:1px solid #fff !important}div.grd_tblCont table td{border-bottom:1px solid #a4bed4 !important;border-right:0 !important;border-left:0 !important;border-top:0 !important}.grd_inf{background-color:#cce2fe;color:#004a6f;border-top:1px solid #9cc !important;}.grd_inf a{text-decoration:none;font-weight:bold}.loader{background-color:#2d8eef;border:1px solid #cce2fe;border-radius:5px}.even{background-color:#fff}.odd{background-color:#e3efff}span.expClpFlt a.btnExpClpFlt:hover{background-color:transparent !important}.ezActiveRow{background-color:#ffdc61 !important;color:inherit}.ezSelectedRow{background-color:#ffe4ab !important;color:inherit}.ezActiveCell{background-color:#fff !important;color:#000 !important;font-weight:bold}.ezETSelectedCell{background-color:#fff !important;font-weight:bold;color:#000 !important}

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.5.6 by Max Guglielmi
* build date: 2017-04-10T16:27:15.240Z
* tablefilter v0.5.34 by Max Guglielmi
* build date: 2017-07-29T00:57:49.938Z
* MIT License
*/
table.TF{padding:0;color:inherit;border-right:1px solid transparent;border-top:1px solid transparent;border-left:1px solid transparent;border-bottom:0;}table.TF th{margin:0;color:inherit;background-color:transparent;border-color:transparent;border-width:1px;border-style:solid;}table.TF th:last-child{border-right:1px solid transparent}table.TF td{margin:0;padding:5px;color:inherit;border-bottom:1px solid transparent;border-left:0;border-top:0;border-right:0}.fltrow{background-color:transparent;}.fltrow th,.fltrow td{padding:1px 3px 1px 3px;border-bottom:1px solid transparent !important;}.fltrow th:last-child,.fltrow td:last-child{border-right:1px solid transparent}.flt,select.flt,select.flt_multi,.flt_s,.single_flt,.div_checklist{border:1px solid #a4bed4}input.flt{width:99% !important}.inf{background-color:transparent;border:1px solid transparent;height:$min-height;color:inherit}div.tot,div.status{border-right:0 !important}.helpBtn:hover{background-color:transparent}input.reset{background:transparent url("images/icn_clear_filters.png") center center no-repeat !important}.nextPage{background:transparent url("images/btn_next_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.nextPage:hover{background:#f7f7f7 url("images/btn_next_page.gif") center center no-repeat !important;border:1px solid #f7f7f7 !important}.previousPage{background:transparent url("images/btn_prev_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.previousPage:hover{background:#f7f7f7 url("images/btn_prev_page.gif") center center no-repeat !important;border:1px solid #f7f7f7 !important}.firstPage{background:transparent url("images/btn_first_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.firstPage:hover{background:#f7f7f7 url("images/btn_first_page.gif") center center no-repeat !important;border:1px solid #f7f7f7 !important}.lastPage{background:transparent url("images/btn_last_page.gif") center center no-repeat !important;border:1px solid transparent !important;}.lastPage:hover{background:#f7f7f7 url("images/btn_last_page.gif") center center no-repeat !important;border:1px solid #f7f7f7 !important}.activeHeader{background:#f7f7f7 !important;border:1px solid transparent;color:inherit !important}div.grd_Cont{-webkit-box-shadow:0 0 0 0 rgba(50,50,50,0.75);-moz-box-shadow:0 0 0 0 rgba(50,50,50,0.75);box-shadow:0 0 0 0 rgba(50,50,50,0.75);background-color:transparent;border:1px solid transparent;padding:0 !important;}div.grd_Cont .even{background-color:transparent}div.grd_Cont .odd{background-color:#f7f7f7}div.grd_headTblCont{background-color:transparent;border-bottom:none !important}div.grd_tblCont table{border-right:none !important}div.grd_tblCont table th,div.grd_headTblCont table th,div.grd_headTblCont table td{background:transparent;border-bottom:1px solid transparent;border-right:1px solid transparent !important;border-left:1px solid transparent;border-top:1px solid transparent}div.grd_tblCont table td{border-bottom:1px solid transparent;border-right:0 !important;border-left:0 !important;border-top:0 !important}.grd_inf{background-color:transparent;color:inherit;border-top:1px solid transparent;}.grd_inf a{text-decoration:none;font-weight:bold}.loader{background-color:#f7f7f7;border:1px solid #f7f7f7;border-radius:5px;color:#000;text-shadow:none}.even{background-color:transparent}.odd{background-color:#f7f7f7}span.expClpFlt a.btnExpClpFlt:hover{background-color:transparent !important}.ezActiveRow{background-color:#ccc !important;color:inherit}.ezSelectedRow{background-color:#ccc !important;color:inherit}.ezActiveCell{background-color:transparent;color:inherit;font-weight:bold}.ezETSelectedCell{background-color:transparent;font-weight:bold;color:inherit}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
{
"name": "tablefilter",
"version": "0.5.6",
"version": "0.5.34",
"description": "A Javascript library making HTML tables filterable and a bit more",
"license": "MIT",
"author": {
@ -39,34 +39,34 @@
},
"devDependencies": {
"babel-core": "^6.24.1",
"babel-eslint": "7.2.1",
"babel-loader": "^6.4.1",
"babel-eslint": "7.2.3",
"babel-loader": "^7.0.0",
"babel-plugin-transform-es2015-classes": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"clean-webpack-plugin": "^0.1.16",
"codecov": "2.1.0",
"codecov": "2.2.0",
"diacritics": "1.3.0",
"format-number": "2.0.2",
"format-number": "3.0.0",
"grunt": "^1.0.1",
"grunt-babel": "^6.0.0",
"grunt-cli": "1.2.0",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-clean": "^1.1.0",
"grunt-contrib-connect": "^1.0.2",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-stylus": "^1.2.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-esdoc": "^0.0.4",
"grunt-eslint": "19.0.0",
"grunt-eslint": "20.0.0",
"grunt-gh-pages": "^2.0.0",
"grunt-qunit-istanbul": "1.0.0",
"grunt-string-replace": "^1.3.1",
"grunt-webpack": "^2.0.1",
"grunt-webpack": "^3.0.0",
"isparta-loader": "2.0.0",
"script-loader": "^0.7.0",
"string-replace-webpack-plugin": "^0.0.5",
"string-replace-webpack-plugin": "^0.1.3",
"sugar-date": "2.0.4",
"webpack": "^2.3.3",
"webpack-dev-server": "^2.4.2"
"webpack": "^3.0.0",
"webpack-dev-server": "^2.4.5"
},
"dependencies": {},
"bugs": {

View file

@ -19,4 +19,4 @@ export const has = (arr, val, caseSensitive) => {
}
}
return false;
}
};

View file

@ -1,3 +1,18 @@
import {DateType} from './modules/dateType';
import {Help} from './modules/help';
import {State} from './modules/state';
import {GridLayout} from './modules/gridLayout';
import {Loader} from './modules/loader';
import {HighlightKeyword} from './modules/highlightKeywords';
import {PopupFilter} from './modules/popupFilter';
import {MarkActiveColumns} from './modules/markActiveColumns';
import {RowsCounter} from './modules/rowsCounter';
import {StatusBar} from './modules/statusBar';
import {ClearButton} from './modules/clearButton';
import {AlternateRows} from './modules/alternateRows';
import {NoResults} from './modules/noResults';
import {Paging} from './modules/paging';
/**
* Filter types
*/
@ -116,3 +131,70 @@ export const IP_ADDRESS = 'ipaddress';
* @type {Number}
*/
export const AUTO_FILTER_DELAY = 750;
/**
* TableFilter features definitions
* @type {Object}
*/
export const FEATURES = {
dateType: {
class: DateType,
name: 'dateType'
},
help: {
class: Help,
name: 'help',
enforce: true
},
state: {
class: State,
name: 'state'
},
markActiveColumns: {
class: MarkActiveColumns,
name: 'markActiveColumns'
},
gridLayout: {
class: GridLayout,
name: 'gridLayout'
},
loader: {
class: Loader,
name: 'loader'
},
highlightKeyword: {
class: HighlightKeyword,
name: 'highlightKeyword',
property: 'highlightKeywords'
},
popupFilter: {
class: PopupFilter,
name: 'popupFilter',
property: 'popupFilters'
},
rowsCounter: {
class: RowsCounter,
name: 'rowsCounter'
},
statusBar: {
class: StatusBar,
name: 'statusBar'
},
clearButton: {
class: ClearButton,
name: 'clearButton',
property: 'btnReset'
},
alternateRows: {
class: AlternateRows,
name: 'alternateRows'
},
noResults: {
class: NoResults,
name: 'noResults'
},
paging: {
class: Paging,
name: 'paging'
}
};

View file

@ -18,7 +18,7 @@ export const getText = (node) => {
return trim(node.innerText);
}
return trim(node.textContent);
}
};
/**
* Returns the first text node contained in the supplied node
@ -32,7 +32,7 @@ export const getFirstTextNode = (node) => {
return n.data;
}
}
}
};
/**
* Creates an html element with given collection of attributes
@ -55,9 +55,8 @@ export const createElm = (...args) => {
el.setAttribute(arg[0], arg[1]);
}
}
return el;
}
};
/**
* Removes passed node from DOM
@ -88,7 +87,7 @@ export const hasClass = (ele, cls) => {
return ele.classList.contains(cls);
}
return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
};
/**
* Adds the specified class to the passed element
@ -111,7 +110,7 @@ export const addClass = (ele, cls) => {
else if (!hasClass(ele, cls)) {
ele.className += ' ' + cls;
}
}
};
/**
* Removes the specified class to the passed element
@ -129,7 +128,7 @@ export const removeClass = (ele, cls) => {
}
let reg = new RegExp('(\\s|^)' + cls + '(\\s|$)', 'g');
ele.className = ele.className.replace(reg, '');
}
};
/**
* Creates and returns an option element
@ -141,11 +140,11 @@ export const removeClass = (ele, cls) => {
export const createOpt = (text, value, isSel) => {
let isSelected = isSel ? true : false;
let opt = isSelected ?
createElm('option', ['value', value], ['selected', 'true']) :
createElm('option', ['value', value]);
createElm('option', ['value', value], ['selected', 'true']) :
createElm('option', ['value', value]);
opt.appendChild(createText(text));
return opt;
}
};
/**
* Creates and returns a checklist item
@ -169,7 +168,7 @@ export const createCheckItem = (id, chkValue, labelText) => {
li.label = label;
li.check = check;
return li;
}
};
/**
* Returns the element matching the supplied Id

View file

@ -1,6 +1,7 @@
import {Feature} from '../../feature';
import {tag} from '../../dom';
import {INPUT} from '../../const';
import {defaultsStr} from '../../settings';
import {root} from '../../root';
const INSTANTIATION_ERROR = `Failed to instantiate EditTable object.
@ -26,13 +27,13 @@ export default class AdapterEzEditTable extends Feature {
* Module description
* @type {String}
*/
this.desc = cfg.description || 'ezEditTable adapter';
this.desc = defaultsStr(cfg.description, 'ezEditTable adapter');
/**
* Filename of ezEditTable library
* @type {String}
*/
this.filename = cfg.filename || 'ezEditTable.js';
this.filename = defaultsStr(cfg.filename, 'ezEditTable.js');
/**
* Path to ezEditTable library
@ -50,13 +51,15 @@ export default class AdapterEzEditTable extends Feature {
* Path to ezEditTable stylesheet
* @type {String}
*/
this.stylesheet = cfg.stylesheet || this.vendorPath + 'ezEditTable.css';
this.stylesheet = defaultsStr(cfg.stylesheet,
this.vendorPath + 'ezEditTable.css');
/**
* Name of ezEditTable stylesheet
* @type {String}
*/
this.stylesheetName = cfg.stylesheet_name || 'ezEditTableCss';
this.stylesheetName = defaultsStr(cfg.stylesheet_name,
'ezEditTableCss');
// Enable the ezEditTable's scroll into view behaviour if grid layout on
cfg.scroll_into_view = cfg.scroll_into_view === false ?
@ -117,7 +120,7 @@ export default class AdapterEzEditTable extends Feature {
//start row for EditTable constructor needs to be calculated
let startRow,
cfg = this.cfg,
thead = tag(tf.tbl, 'thead');
thead = tag(tf.dom(), 'thead');
//if thead exists and startRow not specified, startRow is calculated
//automatically by EditTable
@ -158,7 +161,7 @@ export default class AdapterEzEditTable extends Feature {
et.ClearSelections();
/* eslint-enable */
let cellIndex = selectedElm.cellIndex,
row = tf.tbl.rows[nextRowIndex];
row = tf.dom().rows[nextRowIndex];
if (et.defaultSelection === 'both') {
/* eslint-disable */
slc.SelectRowByIndex(nextRowIndex);
@ -172,7 +175,7 @@ export default class AdapterEzEditTable extends Feature {
}
//Table is filtered
if (tf.validRowsIndex.length !== tf.getRowsNb()) {
let r = tf.tbl.rows[nextRowIndex];
let r = tf.dom().rows[nextRowIndex];
if (r) {
r.scrollIntoView(false);
}
@ -208,7 +211,7 @@ export default class AdapterEzEditTable extends Feature {
paging = tf.feature('paging'),
//pgup/pgdown keys
d = keyCode === 34 || keyCode === 33 ?
(paging && paging.pagingLength || et.nbRowsPerPage) :
(paging && paging.pageLength || et.nbRowsPerPage) :
1;
//If next row is not valid, next valid filtered row needs to be
@ -278,11 +281,11 @@ export default class AdapterEzEditTable extends Feature {
if (tf.feature('paging').nbPages > 1) {
let paging = tf.feature('paging');
//page length is re-assigned in case it has changed
et.nbRowsPerPage = paging.pagingLength;
et.nbRowsPerPage = paging.pageLength;
let validIndexes = tf.validRowsIndex,
validIdxLen = validIndexes.length,
pagingEndRow = parseInt(paging.startPagingRow, 10) +
parseInt(paging.pagingLength, 10);
parseInt(paging.pageLength, 10);
let rowIndex = row.rowIndex;
if ((rowIndex === validIndexes[validIdxLen - 1]) &&

View file

@ -1,9 +1,10 @@
import {Feature} from '../../feature';
import {createText, elm} from '../../dom';
import {isArray, isFn, isUndef, isEmpty, EMPTY_FN} from '../../types';
import {isArray, isEmpty, EMPTY_FN} from '../../types';
import {numSortAsc} from '../../sort';
import {FORMATTED_NUMBER} from '../../const';
import formatNumber from 'format-number';
import {defaultsFn, defaultsArr} from '../../settings';
const EVENTS = [
'after-filtering',
@ -37,15 +38,13 @@ export default class ColOps extends Feature {
* Callback fired before columns operations start
* @type {Function}
*/
this.onBeforeOperation = isFn(opts.on_before_operation) ?
opts.on_before_operation : EMPTY_FN;
this.onBeforeOperation = defaultsFn(opts.on_before_operation, EMPTY_FN);
/**
* Callback fired after columns operations are completed
* @type {Function}
*/
this.onAfterOperation = isFn(opts.on_after_operation) ?
opts.on_after_operation : EMPTY_FN;
this.onAfterOperation = defaultsFn(opts.on_after_operation, EMPTY_FN);
/**
* Configuration options
@ -57,27 +56,27 @@ export default class ColOps extends Feature {
* List of DOM element IDs containing column's calculation result
* @type {Array}
*/
this.labelIds = opts.id || [];
this.labelIds = defaultsArr(opts.id, []);
/**
* List of columns' indexes for calculations
* @type {Array}
*/
this.colIndexes = opts.col || [];
this.colIndexes = defaultsArr(opts.col, []);
/**
* List of operations - possible values: 'sum', 'mean', 'min', 'max',
* 'median', 'q1', 'q3'
* @type {Array}
*/
this.operations = opts.operation || [];
this.operations = defaultsArr(opts.operation, []);
/**
* List of write methods used to write the result - possible values:
* 'innerHTML', 'setValue', 'createTextNode'
* @type {Array}
*/
this.outputTypes = opts.write_method || [];
this.outputTypes = defaultsArr(opts.write_method, []);
/**
* List of format objects used for formatting the result -
@ -85,26 +84,25 @@ export default class ColOps extends Feature {
* configuration options
* @type {Array}
*/
this.formatResults = opts.format_result || [];
this.formatResults = defaultsArr(opts.format_result, []);
/**
* List of row indexes displaying the results
* @type {Array}
*/
this.totRowIndexes = opts.tot_row_index || [];
this.totRowIndexes = defaultsArr(opts.tot_row_index, []);
/**
* List of row indexes excluded from calculations
* @type {Array}
*/
this.excludeRows = opts.exclude_row || [];
this.excludeRows = defaultsArr(opts.exclude_row, []);
/**
* List of decimal precision for calculation results
* @type {Array}
*/
this.decimalPrecisions = isUndef(opts.decimal_precision) ?
2 : opts.decimal_precision;
this.decimalPrecisions = defaultsArr(opts.decimal_precision, 2);
this.enable();
}
@ -151,9 +149,8 @@ export default class ColOps extends Feature {
this.emitter.emit('before-column-operation', tf, this);
let { colIndexes, operations: colOperations, outputTypes,
totRowIndexes, excludeRows, formatResults } = this;
let decimalPrecisions = isUndef(this.decimalPrecisions) ?
2 : this.decimalPrecisions;
totRowIndexes, excludeRows, formatResults,
decimalPrecisions } = this;
//nuovella: determine unique list of columns to operate on
let uIndexes = [];
@ -164,7 +161,7 @@ export default class ColOps extends Feature {
});
let nbCols = uIndexes.length,
rows = tf.tbl.rows,
rows = tf.dom().rows,
colValues = [];
for (let u = 0; u < nbCols; u++) {

View file

@ -3,9 +3,14 @@ import {
addClass, removeClass, createCheckItem, createElm, elm, removeElm,
getText
} from '../../dom';
import {isFn, EMPTY_FN} from '../../types';
import {isUndef, EMPTY_FN} from '../../types';
import {addEvt, targetEvt, removeEvt} from '../../event';
import {root} from '../../root';
import {NONE} from '../../const';
import {
defaultsBool, defaultsStr, defaultsFn,
defaultsNb, defaultsArr
} from '../../settings';
/**
* Columns Visibility extension
@ -33,7 +38,7 @@ export default class ColsVisibility extends Feature {
* Module description
* @type {String}
*/
this.desc = f.description || 'Columns visibility manager';
this.desc = defaultsStr(f.description, 'Columns visibility manager');
/**
* show/hide columns container element
@ -57,13 +62,13 @@ export default class ColsVisibility extends Feature {
* Enable tick to hide a column, defaults to true
* @type {Boolean}
*/
this.tickToHide = f.tick_to_hide === false ? false : true;
this.tickToHide = defaultsBool(f.tick_to_hide, true);
/**
* Enable columns manager UI, defaults to true
* @type {Boolean}
*/
this.manager = f.manager === false ? false : true;
this.manager = defaultsBool(f.manager, true);
/**
* Headers HTML table reference only if headers are external
@ -75,112 +80,115 @@ export default class ColsVisibility extends Feature {
* Headers row index only if headers are external
* @type {Number}
*/
this.headersIndex = f.headers_index || 1;
this.headersIndex = defaultsNb(f.headers_index, 1);
/**
* ID of main container element
* @type {String}
*/
this.contElTgtId = f.container_target_id || null;
this.contElTgtId = defaultsStr(f.container_target_id, null);
/**
* Alternative text for column headers in column manager UI
* @type {Array}
*/
this.headersText = f.headers_text || null;
this.headersText = defaultsArr(f.headers_text, []);
/**
* ID of button's container element
* @type {String}
*/
this.btnTgtId = f.btn_target_id || null;
this.btnTgtId = defaultsStr(f.btn_target_id, null);
/**
* Button's text, defaults to Columns&#9660;
* @type {String}
*/
this.btnText = f.btn_text || 'Columns&#9660;';
this.btnText = defaultsStr(f.btn_text, 'Columns&#9660;');
/**
* Button's inner HTML
* @type {String}
*/
this.btnHtml = f.btn_html || null;
this.btnHtml = defaultsStr(f.btn_html, null);
/**
* Css class for button
* @type {String}
*/
this.btnCssClass = f.btn_css_class || 'colVis';
this.btnCssClass = defaultsStr(f.btn_css_class, 'colVis');
/**
* Columns manager UI close link text, defaults to 'Close'
* @type {String}
*/
this.btnCloseText = f.btn_close_text || 'Close';
this.btnCloseText = defaultsStr(f.btn_close_text, 'Close');
/**
* Columns manager UI close link HTML
* @type {String}
*/
this.btnCloseHtml = f.btn_close_html || null;
this.btnCloseHtml = defaultsStr(f.btn_close_html, null);
/**
* Css for columns manager UI close link
* @type {String}
*/
this.btnCloseCssClass = f.btn_close_css_class || this.btnCssClass;
this.btnCloseCssClass = defaultsStr(f.btn_close_css_class,
this.btnCssClass);
/**
* Extension's stylesheet filename
* @type {String}
*/
this.stylesheet = f.stylesheet || 'colsVisibility.css';
this.stylesheet = defaultsStr(f.stylesheet, 'colsVisibility.css');
/**
* Css for columns manager UI span
* @type {String}
*/
this.spanCssClass = f.span_css_class || 'colVisSpan';
this.spanCssClass = defaultsStr(f.span_css_class, 'colVisSpan');
/**
* Css for columns manager UI main container
* @type {String}
*/
this.contCssClass = f.cont_css_class || 'colVisCont';
this.contCssClass = defaultsStr(f.cont_css_class, 'colVisCont');
/**
* Css for columns manager UI checklist (ul)
* @type {String}
*/
this.listCssClass = cfg.list_css_class || 'cols_checklist';
this.listCssClass = defaultsStr(cfg.list_css_class, 'cols_checklist');
/**
* Css for columns manager UI checklist item (li)
* @type {String}
*/
this.listItemCssClass = cfg.checklist_item_css_class ||
'cols_checklist_item';
this.listItemCssClass = defaultsStr(cfg.checklist_item_css_class,
'cols_checklist_item');
/**
* Css for columns manager UI checklist item selected state (li)
* @type {String}
*/
this.listSlcItemCssClass = cfg.checklist_selected_item_css_class ||
'cols_checklist_slc_item';
this.listSlcItemCssClass = defaultsStr(
cfg.checklist_selected_item_css_class,
'cols_checklist_slc_item'
);
/**
* Text preceding the columns list, defaults to 'Hide' or 'Show'
* depending on tick mode (tick_to_hide option)
* @type {String}
*/
this.text = f.text || (this.tickToHide ? 'Hide: ' : 'Show: ');
this.text = defaultsStr(f.text, this.tickToHide ? 'Hide: ' : 'Show: ');
/**
* List of columns indexes to be hidden at initialization
* @type {Array}
*/
this.atStart = f.at_start || [];
this.atStart = defaultsArr(f.at_start, []);
/**
* Enable hover behaviour on columns manager button/link
@ -198,7 +206,7 @@ export default class ColsVisibility extends Feature {
* Text for select all option, defaults to 'Select all:'
* @type {String}
*/
this.tickAllText = f.tick_all_text || 'Select all:';
this.tickAllText = defaultsStr(f.tick_all_text, 'Select all:');
/**
* List of indexes of hidden columns
@ -216,73 +224,66 @@ export default class ColsVisibility extends Feature {
* Callback fired when the extension is initialized
* @type {Function}
*/
this.onLoaded = isFn(f.on_loaded) ? f.on_loaded : EMPTY_FN;
this.onLoaded = defaultsFn(f.on_loaded, EMPTY_FN);
/**
* Callback fired before the columns manager is opened
* @type {Function}
*/
this.onBeforeOpen = isFn(f.on_before_open) ?
f.on_before_open : EMPTY_FN;
this.onBeforeOpen = defaultsFn(f.on_before_open, EMPTY_FN);
/**
* Callback fired after the columns manager is opened
* @type {Function}
*/
this.onAfterOpen = isFn(f.on_after_open) ? f.on_after_open : EMPTY_FN;
this.onAfterOpen = defaultsFn(f.on_after_open, EMPTY_FN);
/**
* Callback fired before the columns manager is closed
* @type {Function}
*/
this.onBeforeClose = isFn(f.on_before_close) ?
f.on_before_close : EMPTY_FN;
this.onBeforeClose = defaultsFn(f.on_before_close, EMPTY_FN);
/**
* Callback fired after the columns manager is closed
* @type {Function}
*/
this.onAfterClose = isFn(f.on_after_close) ?
f.on_after_close : EMPTY_FN;
this.onAfterClose = defaultsFn(f.on_after_close, EMPTY_FN);
/**
* Callback fired before a column is hidden
* @type {Function}
*/
this.onBeforeColHidden = isFn(f.on_before_col_hidden) ?
f.on_before_col_hidden : EMPTY_FN;
this.onBeforeColHidden = defaultsFn(f.on_before_col_hidden, EMPTY_FN);
/**
* Callback fired after a column is hidden
* @type {Function}
*/
this.onAfterColHidden = isFn(f.on_after_col_hidden) ?
f.on_after_col_hidden : EMPTY_FN;
this.onAfterColHidden = defaultsFn(f.on_after_col_hidden, EMPTY_FN);
/**
* Callback fired before a column is displayed
* @type {Function}
*/
this.onBeforeColDisplayed = isFn(f.on_before_col_displayed) ?
f.on_before_col_displayed : EMPTY_FN;
this.onBeforeColDisplayed = defaultsFn(f.on_before_col_displayed,
EMPTY_FN);
/**
* Callback fired after a column is displayed
* @type {Function}
*/
this.onAfterColDisplayed = isFn(f.on_after_col_displayed) ?
f.on_after_col_displayed : EMPTY_FN;
this.onAfterColDisplayed = defaultsFn(f.on_after_col_displayed,
EMPTY_FN);
//Grid layout support
if (tf.gridLayout) {
this.headersTbl = tf.feature('gridLayout').headTbl; //headers table
this.headersIndex = 0; //headers index
this.onAfterColDisplayed = function () { };
this.onAfterColHidden = function () { };
}
//Loads extension stylesheet
tf.import(f.name + 'Style', tf.stylePath + this.stylesheet, null,
tf.import(f.name + 'Style', tf.getStylePath() + this.stylesheet, null,
'link');
this.enable();
@ -324,7 +325,7 @@ export default class ColsVisibility extends Feature {
}
this.contEl.style.display = contDisplay === 'inline' ?
'none' : 'inline';
NONE : 'inline';
if (contDisplay !== 'inline') {
this.onAfterOpen(this);
@ -459,7 +460,7 @@ export default class ColsVisibility extends Feature {
let ul = createElm('ul');
ul.className = this.listCssClass;
let tbl = this.headersTbl ? this.headersTbl : tf.tbl;
let tbl = this.headersTbl || tf.dom();
let headerIndex = this.headersTbl ?
this.headersIndex : tf.getHeadersRowIndex();
let headerRow = tbl.rows[headerIndex];
@ -485,8 +486,7 @@ export default class ColsVisibility extends Feature {
for (let i = 0; i < headerRow.cells.length; i++) {
let cell = headerRow.cells[i];
let cellText = this.headersText && this.headersText[i] ?
this.headersText[i] : this._getHeaderText(cell);
let cellText = this.headersText[i] || this._getHeaderText(cell);
let liElm = createCheckItem('col_' + i + '_' + tf.id, cellText,
cellText);
addClass(liElm, this.listItemCssClass);
@ -535,7 +535,7 @@ export default class ColsVisibility extends Feature {
*/
setHidden(colIndex, hide) {
let tf = this.tf;
let tbl = tf.tbl;
let tbl = tf.dom();
if (hide) {
this.onBeforeColHidden(this, colIndex);
@ -561,46 +561,13 @@ export default class ColsVisibility extends Feature {
}
}
let gridLayout;
let headTbl;
let gridColElms;
if (hide) {
//This event is fired just after a column is displayed for
//grid_layout support
//TODO: grid layout module should be responsible for those
//calculations
if (tf.gridLayout) {
gridLayout = tf.feature('gridLayout');
headTbl = gridLayout.headTbl;
gridColElms = gridLayout.colElms;
let hiddenWidth = parseInt(
gridColElms[colIndex].style.width, 10);
let headTblW = parseInt(headTbl.style.width, 10);
headTbl.style.width = headTblW - hiddenWidth + 'px';
tbl.style.width = headTbl.style.width;
}
this.onAfterColHidden(this, colIndex);
this.emitter.emit('column-hidden', tf, this, colIndex,
this.hiddenCols);
}
if (!hide) {
//This event is fired just after a column is displayed for
//grid_layout support
//TODO: grid layout module should be responsible for those
//calculations
if (tf.gridLayout) {
gridLayout = tf.feature('gridLayout');
headTbl = gridLayout.headTbl;
gridColElms = gridLayout.colElms;
let width = parseInt(gridColElms[colIndex].style.width, 10);
headTbl.style.width =
(parseInt(headTbl.style.width, 10) + width) + 'px';
tf.tbl.style.width = headTbl.style.width;
}
this.onAfterColDisplayed(this, colIndex);
this.emitter.emit('column-shown', tf, this, colIndex,
this.hiddenCols);
@ -612,7 +579,7 @@ export default class ColsVisibility extends Feature {
* @param {Number} colIndex Column index
*/
showCol(colIndex) {
if (colIndex === undefined || !this.isColHidden(colIndex)) {
if (isUndef(colIndex) || !this.isColHidden(colIndex)) {
return;
}
if (this.manager && this.contEl) {
@ -630,7 +597,7 @@ export default class ColsVisibility extends Feature {
* @param {Number} colIndex Column index
*/
hideCol(colIndex) {
if (colIndex === undefined || this.isColHidden(colIndex)) {
if (isUndef(colIndex) || this.isColHidden(colIndex)) {
return;
}
if (this.manager && this.contEl) {
@ -659,7 +626,7 @@ export default class ColsVisibility extends Feature {
* @param {Number} colIndex Column index
*/
toggleCol(colIndex) {
if (colIndex === undefined || this.isColHidden(colIndex)) {
if (isUndef(colIndex) || this.isColHidden(colIndex)) {
this.showCol(colIndex);
} else {
this.hideCol(colIndex);
@ -726,7 +693,7 @@ export default class ColsVisibility extends Feature {
let row = tbl.rows[i];
let cell = row.cells[colIndex];
if (cell) {
cell.style.display = hide ? 'none' : '';
cell.style.display = hide ? NONE : '';
}
}
}

View file

@ -1,7 +1,10 @@
import {Feature} from '../../feature';
import {createElm, removeElm, elm} from '../../dom';
import {isFn, isUndef, EMPTY_FN} from '../../types';
import {EMPTY_FN} from '../../types';
import {addEvt} from '../../event';
import {
defaultsBool, defaultsStr, defaultsFn, defaultsNb,
} from '../../settings';
/**
* Filters Visibility extension
@ -26,25 +29,26 @@ export default class FiltersVisibility extends Feature {
* Module description
* @type {String}
*/
this.desc = f.description || 'Filters row visibility manager';
this.desc = defaultsStr(f.description,
'Filters row visibility manager');
/**
* Extension's stylesheet filename
* @type {String}
*/
this.stylesheet = f.stylesheet || 'filtersVisibility.css';
this.stylesheet = defaultsStr(f.stylesheet , 'filtersVisibility.css');
/**
* Expand icon filename
* @type {String}
*/
this.icnExpand = f.expand_icon_name || 'icn_exp.png';
this.icnExpand = defaultsStr(f.expand_icon_name, 'icn_exp.png');
/**
* Collapse icon filename
* @type {String}
*/
this.icnCollapse = f.collapse_icon_name || 'icn_clp.png';
this.icnCollapse = defaultsStr(f.collapse_icon_name, 'icn_clp.png');
/**
* Main container element
@ -88,13 +92,13 @@ export default class FiltersVisibility extends Feature {
* Enable expand/collapse icon, defaults to true
* @type {Boolean}
*/
this.enableIcon = f.enable_icon === false ? false : true;
this.enableIcon = defaultsBool(f.enable_icon, true);
/**
* Custom text for button
* @type {String}
*/
this.btnText = f.btn_text || '';
this.btnText = defaultsStr(f.btn_text, '');
/**
* Collapse button HTML
@ -116,62 +120,59 @@ export default class FiltersVisibility extends Feature {
* Button's custom HTML
* @type {String}
*/
this.btnHtml = f.btn_html || null;
this.btnHtml = defaultsStr(f.btn_html, null);
/**
* Css class for expand/collapse filters button
* @type {String}
*/
this.btnCssClass = f.btn_css_class || 'btnExpClpFlt';
this.btnCssClass = defaultsStr(f.btn_css_class, 'btnExpClpFlt');
/**
* Css class for main container
* @type {String}
*/
this.contCssClass = f.cont_css_class || 'expClpFlt';
this.contCssClass = defaultsStr(f.cont_css_class, 'expClpFlt');
/**
* Filters row index
* @type {Number}
*/
this.filtersRowIndex = !isUndef(f.filters_row_index) ?
f.filters_row_index : tf.getFiltersRowIndex();
this.filtersRowIndex = defaultsNb(f.filters_row_index,
tf.getFiltersRowIndex());
/**
* Make filters visible at initialization, defaults to true
* @type {Boolean}
*/
this.visibleAtStart = !isUndef(f.visible_at_start) ?
Boolean(f.visible_at_start) : true;
this.visibleAtStart = defaultsNb(f.visible_at_start, true);
/**
* Callback fired before filters row is shown
* @type {Function}
*/
this.onBeforeShow = isFn(f.on_before_show) ?
f.on_before_show : EMPTY_FN;
this.onBeforeShow = defaultsFn(f.on_before_show, EMPTY_FN);
/**
* Callback fired after filters row is shown
* @type {Function}
*/
this.onAfterShow = isFn(f.on_after_show) ? f.on_after_show : EMPTY_FN;
this.onAfterShow = defaultsFn(f.on_after_show, EMPTY_FN);
/**
* Callback fired before filters row is hidden
* @type {Function}
*/
this.onBeforeHide = isFn(f.on_before_hide) ?
f.on_before_hide : EMPTY_FN;
this.onBeforeHide = defaultsFn(f.on_before_hide, EMPTY_FN);
/**
* Callback fired after filters row is hidden
* @type {Function}
*/
this.onAfterHide = isFn(f.on_after_hide) ? f.on_after_hide : EMPTY_FN;
this.onAfterHide = defaultsFn(f.on_after_hide, EMPTY_FN);
//Import extension's stylesheet
tf.import(f.name + 'Style', tf.stylePath + this.stylesheet, null,
tf.import(f.name + 'Style', tf.getStylePath() + this.stylesheet, null,
'link');
this.enable();
@ -244,7 +245,7 @@ export default class FiltersVisibility extends Feature {
*/
toggle() {
let tf = this.tf;
let tbl = tf.gridLayout ? tf.feature('gridLayout').headTbl : tf.tbl;
let tbl = tf.gridLayout ? tf.feature('gridLayout').headTbl : tf.dom();
let fltRow = tbl.rows[this.filtersRowIndex];
let isDisplayed = fltRow.style.display === '';
@ -258,7 +259,7 @@ export default class FiltersVisibility extends Feature {
*/
show(visible = true) {
let tf = this.tf;
let tbl = tf.gridLayout ? tf.feature('gridLayout').headTbl : tf.tbl;
let tbl = tf.gridLayout ? tf.feature('gridLayout').headTbl : tf.dom();
let fltRow = tbl.rows[this.filtersRowIndex];
if (visible) {

View file

@ -1,5 +1,5 @@
import {Feature} from '../../feature';
import {isArray, isFn, isUndef, isObj, EMPTY_FN} from '../../types';
import {isUndef, isObj, EMPTY_FN} from '../../types';
import {createElm, elm, getText, tag} from '../../dom';
import {addEvt} from '../../event';
import {parse as parseNb} from '../../number';
@ -7,6 +7,7 @@ import {
NONE, CELL_TAG, HEADER_TAG, STRING, NUMBER, DATE, FORMATTED_NUMBER,
IP_ADDRESS
} from '../../const';
import {defaultsStr, defaultsFn, defaultsArr} from '../../settings';
/**
* SortableTable Adapter module
@ -31,7 +32,7 @@ export default class AdapterSortableTable extends Feature {
* Module description
* @type {String}
*/
this.desc = opts.description || 'Sortable table';
this.desc = defaultsStr(opts.description, 'Sortable table');
/**
* Indicate whether table previously sorted
@ -44,15 +45,14 @@ export default class AdapterSortableTable extends Feature {
* List of sort type per column basis
* @type {Array}
*/
this.sortTypes = isArray(opts.types) ? opts.types : tf.colTypes;
this.sortTypes = defaultsArr(opts.types, tf.colTypes);
/**
* Column to be sorted at initialization, ie:
* sort_col_at_start: [1, true]
* @type {Array}
*/
this.sortColAtStart = isArray(opts.sort_col_at_start) ?
opts.sort_col_at_start : null;
this.sortColAtStart = defaultsArr(opts.sort_col_at_start, null);
/**
* Enable asynchronous sort, if triggers are external
@ -64,7 +64,7 @@ export default class AdapterSortableTable extends Feature {
* List of element IDs triggering sort on a per column basis
* @type {Array}
*/
this.triggerIds = isArray(opts.trigger_ids) ? opts.trigger_ids : [];
this.triggerIds = defaultsArr(opts.trigger_ids, []);
// edit .sort-arrow.descending / .sort-arrow.ascending in
// tablefilter.css to reflect any path change
@ -72,58 +72,57 @@ export default class AdapterSortableTable extends Feature {
* Path to images
* @type {String}
*/
this.imgPath = opts.images_path || tf.themesPath;
this.imgPath = defaultsStr(opts.images_path, tf.themesPath);
/**
* Blank image file name
* @type {String}
*/
this.imgBlank = opts.image_blank || 'blank.png';
this.imgBlank = defaultsStr(opts.image_blank, 'blank.png');
/**
* Css class for sort indicator image
* @type {String}
*/
this.imgClassName = opts.image_class_name || 'sort-arrow';
this.imgClassName = defaultsStr(opts.image_class_name, 'sort-arrow');
/**
* Css class for ascending sort indicator image
* @type {String}
*/
this.imgAscClassName = opts.image_asc_class_name || 'ascending';
this.imgAscClassName = defaultsStr(opts.image_asc_class_name,
'ascending');
/**
* Css class for descending sort indicator image
* @type {String}
*/
this.imgDescClassName = opts.image_desc_class_name || 'descending';
this.imgDescClassName = defaultsStr(opts.image_desc_class_name,
'descending');
/**
* Cell attribute key storing custom value used for sorting
* @type {String}
*/
this.customKey = opts.custom_key || 'data-tf-sortKey';
this.customKey = defaultsStr(opts.custom_key, 'data-tf-sortKey');
/**
* Callback fired when sort extension is instanciated
* @type {Function}
*/
this.onSortLoaded = isFn(opts.on_sort_loaded) ?
opts.on_sort_loaded : EMPTY_FN;
this.onSortLoaded = defaultsFn(opts.on_sort_loaded, EMPTY_FN);
/**
* Callback fired before a table column is sorted
* @type {Function}
*/
this.onBeforeSort = isFn(opts.on_before_sort) ?
opts.on_before_sort : EMPTY_FN;
this.onBeforeSort = defaultsFn(opts.on_before_sort, EMPTY_FN);
/**
* Callback fired after a table column is sorted
* @type {Function}
*/
this.onAfterSort = isFn(opts.on_after_sort) ?
opts.on_after_sort : EMPTY_FN;
this.onAfterSort = defaultsFn(opts.on_after_sort, EMPTY_FN);
/**
* SortableTable instance
@ -430,7 +429,7 @@ export default class AdapterSortableTable extends Feature {
this.addSortType(STRING);
this.addSortType(IP_ADDRESS, ipAddress, sortIP);
this.stt = new SortableTable(tf.tbl, _sortTypes);
this.stt = new SortableTable(tf.dom(), _sortTypes);
/*** external table headers adapter ***/
if (this.asyncSort && this.triggerIds.length > 0) {

View file

@ -1,5 +1,5 @@
const NOTIMPLEMENTED = 'Not implemented.';
const NOT_IMPLEMENTED = 'Not implemented.';
/**
* Base class defining the interface of a TableFilter feature
@ -55,7 +55,7 @@ export class Feature {
* Initialize the feature
*/
init() {
throw new Error(NOTIMPLEMENTED);
throw new Error(NOT_IMPLEMENTED);
}
/**
@ -70,7 +70,7 @@ export class Feature {
* Destroy the feature
*/
destroy() {
throw new Error(NOTIMPLEMENTED);
throw new Error(NOT_IMPLEMENTED);
}
/**
@ -92,6 +92,6 @@ export class Feature {
* @returns {Boolean}
*/
isEnabled() {
return this.enabled;
return this.enabled === true;
}
}

View file

@ -1,5 +1,6 @@
import {Feature} from '../feature';
import {addClass, removeClass} from '../dom';
import {defaultsStr} from '../settings';
/**
* Rows with alternating background color for improved readability
@ -19,13 +20,13 @@ export class AlternateRows extends Feature {
* Css class for even rows (default: 'even')
* @type {String}
*/
this.evenCss = config.even_row_css_class || 'even';
this.evenCss = defaultsStr(config.even_row_css_class, 'even');
/**
* Css class for odd rows (default: 'odd')
* @type {String}
*/
this.oddCss = config.odd_row_css_class || 'odd';
this.oddCss = defaultsStr(config.odd_row_css_class, 'odd');
}
/**
@ -42,8 +43,8 @@ export class AlternateRows extends Feature {
this.emitter.on(['row-processed', 'row-paged'],
(tf, rowIndex, arrIndex, isValid) =>
this.processRow(rowIndex, arrIndex, isValid));
this.emitter.on(['column-sorted'], () => this.processAll());
this.emitter.on(['rows-changed'], () => this.processAll());
this.emitter.on(['column-sorted', 'rows-changed'],
() => this.processAll());
/** @inherited */
this.initialized = true;
@ -94,7 +95,7 @@ export class AlternateRows extends Feature {
if (!this.isEnabled() || isNaN(rowIdx)) {
return;
}
let rows = this.tf.tbl.rows;
let rows = this.tf.dom().rows;
let i = isNaN(idx) ? rowIdx : idx;
this.removeRowBg(rowIdx);
@ -110,7 +111,7 @@ export class AlternateRows extends Feature {
if (isNaN(idx)) {
return;
}
let rows = this.tf.tbl.rows;
let rows = this.tf.dom().rows;
removeClass(rows[idx], this.oddCss);
removeClass(rows[idx], this.evenCss);
}
@ -131,8 +132,8 @@ export class AlternateRows extends Feature {
this.emitter.off(['row-processed', 'row-paged'],
(tf, rowIndex, arrIndex, isValid) =>
this.processRow(rowIndex, arrIndex, isValid));
this.emitter.off(['column-sorted'], () => this.processAll());
this.emitter.off(['rows-changed'], () => this.processAll());
this.emitter.off(['column-sorted', 'rows-changed'],
() => this.processAll());
this.initialized = false;
}

121
src/modules/baseDropdown.js Normal file
View file

@ -0,0 +1,121 @@
import {Feature} from '../feature';
import {
ignoreCase, numSortAsc, numSortDesc,
dateSortAsc, sortNumberStr, sortDateStr
} from '../sort';
import {isArray, isObj} from '../types';
import {NUMBER, FORMATTED_NUMBER, DATE} from '../const';
/**
* Base class for Dropdown and CheckList UI components
* @export
* @class BaseDropdown
* @extends {Feature}
*/
export class BaseDropdown extends Feature {
/**
* Creates an instance of BaseDropdown
* @param {TableFilter} tf
*/
constructor(tf) {
super(tf, 'baseDropdown');
let f = this.config;
/**
* Filter options custom sorter on a column basis
* @type {Object}
*/
this.customSorter = isObj(f.filter_options_sorter) &&
isArray(f.filter_options_sorter.col) &&
isArray(f.filter_options_sorter.comparer) ?
f.filter_options_sorter :
null;
// TODO: move here all properties shared by Dropdown CheckList
/**
* Has custom options
* @type {Boolean}
* @private
*/
this.isCustom = false;
/**
* List of options values
* @type {Array}
* @private
*/
this.opts = [];
/**
* List of options texts for custom values
* @type {Array}
* @private
*/
this.optsTxt = [];
/**
* List of options to be excluded from the checklist filter
* @type {Array}
* @private
*/
this.excludedOpts = [];
}
/**
* Sort passed options based on the type of the specified column
* @param {Number} colIndex Column index
* @param {Array} [options=[]] Collection of values
* @return {Array} Sorted values
* @private
*/
sortOptions(colIndex, options = []) {
let tf = this.tf;
if (tf.isCustomOptions(colIndex) || !tf.sortSlc ||
(isArray(tf.sortSlc) && tf.sortSlc.indexOf(colIndex) === -1)) {
return options;
}
let { caseSensitive, sortNumDesc } = tf;
let compareFn;
if (this.customSorter &&
this.customSorter.col.indexOf(colIndex) !== -1) {
var idx = this.customSorter.col.indexOf(colIndex);
compareFn = this.customSorter.comparer[idx];
}
else if (tf.hasType(colIndex, [NUMBER, FORMATTED_NUMBER])) {
let decimal = tf.getDecimal(colIndex);
let comparer = numSortAsc;
if (sortNumDesc === true || sortNumDesc.indexOf(colIndex) !== -1) {
comparer = numSortDesc;
}
compareFn = sortNumberStr(comparer, decimal);
}
else if (tf.hasType(colIndex, [DATE])) {
let locale = tf.feature('dateType').getLocale(colIndex);
let comparer = dateSortAsc;
compareFn = sortDateStr(comparer, locale);
} else { // string
compareFn = caseSensitive ? undefined : ignoreCase;
}
return options.sort(compareFn);
}
/**
* Regenerate filters of specified columns and maintain selection if any
* @param {Array} colIndexes Collection of column indexes
* @private
*/
refreshFilters(colIndexes) {
colIndexes.forEach((colIdx) => {
let values = this.getValues(colIdx);
this.build(colIdx, this.tf.linkedFilters);
this.selectOptions(colIdx, values);
});
}
}

View file

@ -1,22 +1,22 @@
import {Feature} from '../feature';
import {BaseDropdown} from './baseDropdown';
import {
addClass, createCheckItem, createText, createElm, elm, getText,
removeClass, tag
} from '../dom';
import {has} from '../array';
import {matchCase, trim, rgxEsc} from '../string';
import {ignoreCase, numSortAsc, numSortDesc} from '../sort';
import {addEvt, removeEvt, targetEvt} from '../event';
import {isEmpty} from '../types';
import {CHECKLIST, NONE} from '../const';
const SORT_ERROR = 'Filter options for column {0} cannot be sorted in ' +
'{1} manner.';
import {defaultsStr, defaultsBool} from '../settings';
/**
* Checklist filter UI component
* @export
* @class CheckList
* @extends {BaseDropdown}
*/
export class CheckList extends Feature {
export class CheckList extends BaseDropdown {
/**
* Creates an instance of CheckList
@ -37,48 +37,57 @@ export class CheckList extends Feature {
* Css class for the container of the checklist filter (div)
* @type {String}
*/
this.containerCssClass = f.div_checklist_css_class || 'div_checklist';
this.containerCssClass = defaultsStr(f.div_checklist_css_class,
'div_checklist');
/**
* Css class for the checklist filter element (ul)
* @type {String}
*/
this.filterCssClass = f.checklist_css_class || 'flt_checklist';
this.filterCssClass = defaultsStr(f.checklist_css_class,
'flt_checklist');
/**
* Css class for the item of a checklist (li)
* @type {String}
*/
this.itemCssClass = f.checklist_item_css_class || 'flt_checklist_item';
this.itemCssClass = defaultsStr(f.checklist_item_css_class,
'flt_checklist_item');
/**
* Css class for a selected item of a checklist (li)
* @type {String}
*/
this.selectedItemCssClass =
f.checklist_selected_item_css_class || 'flt_checklist_slc_item';
this.selectedItemCssClass = defaultsStr(
f.checklist_selected_item_css_class,
'flt_checklist_slc_item'
);
/**
* Text placed in the filter's container when load filter on demand
* feature is enabled
* @type {String}
*/
this.activateText =
f.activate_checklist_text || 'Click to load filter data';
this.activateText = defaultsStr(
f.activate_checklist_text,
'Click to load filter data'
);
/**
* Css class for a disabled item of a checklist (li)
* @type {String}
*/
this.disabledItemCssClass = f.checklist_item_disabled_css_class ||
'flt_checklist_item_disabled';
this.disabledItemCssClass = defaultsStr(
f.checklist_item_disabled_css_class,
'flt_checklist_item_disabled'
);
/**
* Enable the reset filter option as first item
* @type {Boolean}
*/
this.enableResetOption = f.enable_checklist_reset_filter === false ?
false : true;
this.enableResetOption = defaultsBool(f.enable_checklist_reset_filter,
true);
/**
* Prefix for container element ID
@ -86,34 +95,6 @@ export class CheckList extends Feature {
* @private
*/
this.prfx = 'chkdiv_';
/**
* Has custom options
* @type {Boolean}
* @private
*/
this.isCustom = false;
/**
* List of options values
* @type {Array}
* @private
*/
this.opts = [];
/**
* List of options texts for custom values
* @type {Array}
* @private
*/
this.optsTxt = [];
/**
* List of options to be excluded from the checklist filter
* @type {Array}
* @private
*/
this.excludedOpts = [];
}
/**
@ -149,13 +130,8 @@ export class CheckList extends Feature {
* Refresh all checklist filters
*/
refreshAll() {
let tf = this.tf;
let fltsIdxs = tf.getFiltersByType(CHECKLIST, true);
fltsIdxs.forEach((colIdx) => {
let values = this.getValues(colIdx);
this.build(colIdx, tf.linkedFilters);
this.selectOptions(colIdx, values);
});
let colIdxs = this.tf.getFiltersByType(CHECKLIST, true);
this.refreshFilters(colIdxs);
}
/**
@ -218,7 +194,9 @@ export class CheckList extends Feature {
this.emitter.emit('before-populating-filter', tf, colIndex);
/** @inherited */
this.opts = [];
/** @inherited */
this.optsTxt = [];
let flt = this.containers[colIndex];
@ -227,11 +205,19 @@ export class CheckList extends Feature {
['colIndex', colIndex]);
ul.className = this.filterCssClass;
let rows = tf.tbl.rows;
let rows = tf.dom().rows;
let nbRows = tf.getRowsNb(true);
let caseSensitive = tf.caseSensitive;
/** @inherited */
this.isCustom = tf.isCustomOptions(colIndex);
//Retrieves custom values
if (this.isCustom) {
let customValues = tf.getCustomOptions(colIndex);
this.opts = customValues[0];
this.optsTxt = customValues[1];
}
let activeIdx;
let activeFilterId = tf.getActiveFilterId();
if (isLinked && activeFilterId) {
@ -240,6 +226,7 @@ export class CheckList extends Feature {
let filteredDataCol = [];
if (isLinked && tf.disableExcludedOptions) {
/** @inherited */
this.excludedOpts = [];
}
@ -292,55 +279,10 @@ export class CheckList extends Feature {
}
}
//Retrieves custom values
if (this.isCustom) {
let customValues = tf.getCustomOptions(colIndex);
this.opts = customValues[0];
this.optsTxt = customValues[1];
}
if (tf.sortSlc && !this.isCustom) {
if (!caseSensitive) {
this.opts.sort(ignoreCase);
if (this.excludedOpts) {
this.excludedOpts.sort(ignoreCase);
}
} else {
this.opts.sort();
if (this.excludedOpts) {
this.excludedOpts.sort();
}
}
}
//asc sort
if (tf.sortNumAsc.indexOf(colIndex) !== -1) {
try {
this.opts.sort(numSortAsc);
if (this.excludedOpts) {
this.excludedOpts.sort(numSortAsc);
}
if (this.isCustom) {
this.optsTxt.sort(numSortAsc);
}
} catch (e) {
throw new Error(SORT_ERROR.replace('{0}', colIndex)
.replace('{1}', 'ascending'));
}//in case there are alphanumeric values
}
//desc sort
if (tf.sortNumDesc.indexOf(colIndex) !== -1) {
try {
this.opts.sort(numSortDesc);
if (this.excludedOpts) {
this.excludedOpts.sort(numSortDesc);
}
if (this.isCustom) {
this.optsTxt.sort(numSortDesc);
}
} catch (e) {
throw new Error(SORT_ERROR.replace('{0}', colIndex)
.replace('{1}', 'descending'));
}//in case there are alphanumeric values
//sort options
this.opts = this.sortOptions(colIndex, this.opts);
if (this.excludedOpts) {
this.excludedOpts = this.sortOptions(colIndex, this.excludedOpts);
}
this.addChecks(colIndex, ul);
@ -562,7 +504,6 @@ export class CheckList extends Feature {
let flt = tf.getFilterElement(colIndex);
let fltAttr = flt.getAttribute('value');
let values = isEmpty(fltAttr) ? '' : fltAttr;
//removes last operator ||
values = values.substr(0, values.length - 3);
//turn || separated values into array

View file

@ -1,6 +1,7 @@
import {Feature} from '../feature';
import {createElm, createText, elm, removeElm} from '../dom';
import {addEvt} from '../event';
import {defaultsStr} from '../settings';
/**
* Clear button UI component
@ -20,7 +21,7 @@ export class ClearButton extends Feature {
* Container element ID
* @type {String}
*/
this.targetId = f.btn_reset_target_id || null;
this.targetId = defaultsStr(f.btn_reset_target_id, null);
/**
* Clear button container element
@ -40,13 +41,13 @@ export class ClearButton extends Feature {
* Text for the clear button
* @type {String}
*/
this.text = f.btn_reset_text || 'Reset';
this.text = defaultsStr(f.btn_reset_text, 'Reset');
/**
* Css class for reset button
* @type {String}
*/
this.cssClass = f.btn_reset_css_class || 'reset';
this.cssClass = defaultsStr(f.btn_reset_css_class, 'reset');
/**
* Tooltip text for the clear button
@ -58,10 +59,10 @@ export class ClearButton extends Feature {
* Custom Html string for the clear button
* @type {String}
*/
this.html = f.btn_reset_html ||
this.html = defaultsStr(f.btn_reset_html,
(!tf.enableIcons ? null :
'<input type="button" value="" class="' + this.cssClass +
'" ' + 'title="' + this.tooltip + '" />');
'" ' + 'title="' + this.tooltip + '" />'));
}
/**

View file

@ -94,6 +94,16 @@ export class DateType extends Feature {
return isObj(colType) ? colType : {};
}
/**
* Return the locale code for supplied column index as per configuration
* or global setting
* @param {Number} colIndex Column index
* @returns {String} Locale code (ie: 'en-us')
*/
getLocale(colIndex) {
return this.getOptions(colIndex).locale || this.locale;
}
/**
* Add date time format(s) to a locale as specified by the passed
* collection of column types, ie:

View file

@ -1,18 +1,18 @@
import {Feature} from '../feature';
import {BaseDropdown} from './baseDropdown';
import {createElm, createOpt, elm} from '../dom';
import {has} from '../array';
import {matchCase} from '../string';
import {ignoreCase, numSortAsc, numSortDesc} from '../sort';
import {addEvt, targetEvt} from '../event';
import {SELECT, MULTIPLE, NONE} from '../const';
const SORT_ERROR = 'Filter options for column {0} cannot be sorted in ' +
'{1} manner.';
import {defaultsStr, defaultsBool} from '../settings';
/**
* Dropdown filter UI component
* @export
* @class Dropdown
* @extends {BaseDropdown}
*/
export class Dropdown extends Feature {
export class Dropdown extends BaseDropdown {
/**
* Creates an instance of Dropdown
@ -28,41 +28,21 @@ export class Dropdown extends Feature {
* Enable the reset filter option as first item
* @type {Boolean}
*/
this.enableSlcResetFilter = f.enable_slc_reset_filter === false ?
false : true;
this.enableSlcResetFilter =
defaultsBool(f.enable_slc_reset_filter, true);
/**
* Non empty option text
* @type {String}
*/
this.nonEmptyText = f.non_empty_text || '(Non empty)';
this.nonEmptyText = defaultsStr(f.non_empty_text, '(Non empty)');
/**
* Tooltip text appearing on multiple select
* @type {String}
*/
this.multipleSlcTooltip = f.multiple_slc_tooltip ||
'Use Ctrl/Cmd key for multiple selections';
/**
* Indicates drop-down has custom options
* @private
*/
this.isCustom = null;
/**
* List of options values
* @type {Array}
* @private
*/
this.opts = null;
/**
* List of options texts for custom values
* @type {Array}
* @private
*/
this.optsTxt = null;
this.multipleSlcTooltip = defaultsStr(f.multiple_slc_tooltip,
'Use Ctrl/Cmd key for multiple selections');
}
@ -96,15 +76,10 @@ export class Dropdown extends Feature {
* Refresh all drop-down filters
*/
refreshAll() {
let tf = this.tf;
let selectFlts = tf.getFiltersByType(SELECT, true);
let multipleFlts = tf.getFiltersByType(MULTIPLE, true);
let flts = selectFlts.concat(multipleFlts);
flts.forEach((colIdx) => {
let values = this.getValues(colIdx);
this.build(colIdx, tf.linkedFilters);
this.selectOptions(colIdx, values);
});
let selectFlts = this.tf.getFiltersByType(SELECT, true);
let multipleFlts = this.tf.getFiltersByType(MULTIPLE, true);
let colIdxs = selectFlts.concat(multipleFlts);
this.refreshFilters(colIdxs);
}
/**
@ -177,17 +152,27 @@ export class Dropdown extends Feature {
this.emitter.emit('before-populating-filter', tf, colIndex);
/** @inherited */
this.opts = [];
/** @inherited */
this.optsTxt = [];
let slcId = tf.fltIds[colIndex];
let slc = elm(slcId);
let rows = tf.tbl.rows;
let rows = tf.dom().rows;
let nbRows = tf.getRowsNb(true);
//custom select test
/** @inherited */
this.isCustom = tf.isCustomOptions(colIndex);
//Retrieves custom values
if (this.isCustom) {
let customValues = tf.getCustomOptions(colIndex);
this.opts = customValues[0];
this.optsTxt = customValues[1];
}
//custom selects text
let activeIdx;
let activeFilterId = tf.getActiveFilterId();
@ -250,54 +235,10 @@ export class Dropdown extends Feature {
}//for j
}//for k
//Retrieves custom values
if (this.isCustom) {
let customValues = tf.getCustomOptions(colIndex);
this.opts = customValues[0];
this.optsTxt = customValues[1];
}
if (tf.sortSlc && !this.isCustom) {
if (!tf.caseSensitive) {
this.opts.sort(ignoreCase);
if (excludedOpts) {
excludedOpts.sort(ignoreCase);
}
} else {
this.opts.sort();
if (excludedOpts) { excludedOpts.sort(); }
}
}
//asc sort
if (tf.sortNumAsc.indexOf(colIndex) !== -1) {
try {
this.opts.sort(numSortAsc);
if (excludedOpts) {
excludedOpts.sort(numSortAsc);
}
if (this.isCustom) {
this.optsTxt.sort(numSortAsc);
}
} catch (e) {
throw new Error(SORT_ERROR.replace('{0}', colIndex)
.replace('{1}', 'ascending'));
}//in case there are alphanumeric values
}
//desc sort
if (tf.sortNumDesc.indexOf(colIndex) !== -1) {
try {
this.opts.sort(numSortDesc);
if (excludedOpts) {
excludedOpts.sort(numSortDesc);
}
if (this.isCustom) {
this.optsTxt.sort(numSortDesc);
}
} catch (e) {
throw new Error(SORT_ERROR.replace('{0}', colIndex)
.replace('{1}', 'ascending'));
}//in case there are alphanumeric values
//sort options
this.opts = this.sortOptions(colIndex, this.opts);
if (excludedOpts) {
excludedOpts = this.sortOptions(colIndex, excludedOpts);
}
//populates drop-down

View file

@ -3,6 +3,9 @@ import {createElm, removeElm, elm, tag} from '../dom';
import {addEvt, targetEvt} from '../event';
import {contains} from '../string';
import {NONE} from '../const';
import {
defaultsBool, defaultsStr, defaultsNb, defaultsArr
} from '../settings';
/**
* Grid layout, table with fixed headers
@ -16,75 +19,74 @@ export class GridLayout extends Feature {
constructor(tf) {
super(tf, 'gridLayout');
let f = this.config;
let f = this.config.grid_layout || {};
/**
* Grid-layout container width as CSS string
* @type {String}
*/
this.width = f.grid_width || null;
this.width = defaultsStr(f.width, null);
/**
* Grid-layout container height as CSS string
* @type {String}
*/
this.height = f.grid_height || null;
this.height = defaultsStr(f.height, null);
/**
* Css class for main container element
* @type {String}
*/
this.mainContCssClass = f.grid_cont_css_class || 'grd_Cont';
this.mainContCssClass = defaultsStr(f.cont_css_class, 'grd_Cont');
/**
* Css class for body table container element
* @type {String}
*/
this.contCssClass = f.grid_tbl_cont_css_class || 'grd_tblCont';
this.contCssClass = defaultsStr(f.tbl_cont_css_class, 'grd_tblCont');
/**
* Css class for headers table container element
* @type {String}
*/
this.headContCssClass = f.grid_tblHead_cont_css_class ||
'grd_headTblCont';
this.headContCssClass = defaultsStr(f.tbl_head_css_class,
'grd_headTblCont');
/**
* Css class for toolbar container element (rows counter, paging etc.)
* @type {String}
*/
this.infDivCssClass = f.grid_inf_grid_css_class || 'grd_inf';
this.infDivCssClass = defaultsStr(f.inf_grid_css_class, 'grd_inf');
/**
* Index of the headers row, default: 0
* @type {Number}
*/
this.headRowIndex = f.grid_headers_row_index || 0;
this.headRowIndex = defaultsNb(f.headers_row_index, 0);
/**
* Collection of the header row indexes to be moved into headers table
* @type {Array}
*/
this.headRows = f.grid_headers_rows || [0];
this.headRows = defaultsArr(f.headers_rows, [0]);
/**
* Enable or disable column filters generation, default: true
* @type {Boolean}
*/
this.enableFilters = f.grid_enable_default_filters === false ?
false : true;
this.filters = defaultsBool(f.filters, true);
/**
* Enable or disable column headers, default: false
* @type {Boolean}
*/
this.noHeaders = Boolean(f.grid_no_headers);
this.noHeaders = Boolean(f.no_headers);
/**
* Grid-layout default column widht as CSS string
* @type {String}
*/
this.defaultColWidth = f.grid_default_col_width || '100px';
this.defaultColWidth = defaultsStr(f.default_col_width, '100px');
/**
* List of column elements
@ -112,14 +114,14 @@ export class GridLayout extends Feature {
* @type {String}
* @private
*/
this.sourceTblHtml = tf.tbl.outerHTML;
this.sourceTblHtml = tf.dom().outerHTML;
/**
* Indicates if working table has column elements
* @type {Boolean}
* @private
*/
this.tblHasColTag = tag(tf.tbl, 'col').length > 0 ? true : false;
this.tblHasColTag = tag(tf.dom(), 'col').length > 0 ? true : false;
/**
* Main container element
@ -146,7 +148,7 @@ export class GridLayout extends Feature {
this.headTbl = null;
// filters flag at TF level
tf.fltGrid = this.enableFilters;
tf.fltGrid = this.filters;
}
/**
@ -155,7 +157,7 @@ export class GridLayout extends Feature {
*/
init() {
let tf = this.tf;
let tbl = tf.tbl;
let tbl = tf.dom();
if (this.initialized) {
return;
@ -200,7 +202,6 @@ export class GridLayout extends Feature {
//Headers table container: div wrapping headers table
this.headTblCont = this.createContainer(
'div', this.headContCssClass);
this.setConfigWidth(this.headTblCont);
//Headers table
this.headTbl = createElm('table');
@ -233,22 +234,16 @@ export class GridLayout extends Feature {
tbl.removeChild(thead[0]);
}
//Headers table style
// ensure table layout is always set even if already set in css
// definitions, potentially with custom css class this could be lost
this.headTbl.style.tableLayout = 'fixed';
tbl.style.tableLayout = 'fixed';
this.headTbl.cellPadding = tbl.cellPadding;
this.headTbl.cellSpacing = tbl.cellSpacing;
// this.headTbl.style.width = tbl.style.width;
//content table without headers needs col widths to be reset
tf.setColWidths(this.headTbl);
//Headers container width
// this.headTblCont.style.width = this.tblCont.clientWidth+'px';
tbl.style.width = '';
//
this.headTbl.style.width = tbl.clientWidth + 'px';
this.headTbl.style.width = tbl.style.width;
//
//scroll synchronisation
@ -288,10 +283,6 @@ export class GridLayout extends Feature {
filtersRow.style.display = NONE;
}
if (tbl.clientWidth !== this.headTbl.clientWidth) {
tbl.style.width = this.headTbl.clientWidth + 'px';
}
/** @inherited */
this.initialized = true;
}
@ -305,7 +296,6 @@ export class GridLayout extends Feature {
tf.refRow = 0;
tf.headersRow = 0;
tf.filtersRowIndex = 1;
tf.isExternalFlt = true;
}
/**
@ -314,12 +304,12 @@ export class GridLayout extends Feature {
*/
setDefaultColWidths() {
let tf = this.tf;
if (tf.hasColWidths) {
if (tf.colWidths.length > 0) {
return;
}
for (let k = 0, len = tf.getCellsNb(); k < len; k++) {
let colW;
let cell = tf.tbl.rows[tf.getHeadersRowIndex()].cells[k];
let cell = tf.dom().rows[tf.getHeadersRowIndex()].cells[k];
if (cell.width !== '') {
colW = cell.width;
} else if (cell.style.width !== '') {
@ -329,7 +319,6 @@ export class GridLayout extends Feature {
}
tf.colWidths[k] = colW;
}
tf.hasColWidths = true;
tf.setColWidths();
}
@ -339,7 +328,7 @@ export class GridLayout extends Feature {
* @private
*/
initialTableWidth() {
let tbl = this.tf.tbl;
let tbl = this.tf.dom();
let width; //initial table width
if (tbl.width !== '') {
@ -374,7 +363,7 @@ export class GridLayout extends Feature {
createFiltersRow() {
let tf = this.tf;
let filtersRow = createElm('tr');
if (this.enableFilters && tf.fltGrid) {
if (this.filters && tf.fltGrid) {
tf.externalFltTgtIds = [];
for (let j = 0; j < tf.getCellsNb(); j++) {
let fltTdId = `${tf.prfxFlt + j + this.prfxGridFltTd + tf.id}`;
@ -392,7 +381,7 @@ export class GridLayout extends Feature {
*/
setColumnElements() {
let tf = this.tf;
let cols = tag(tf.tbl, 'col');
let cols = tag(tf.dom(), 'col');
this.tblHasColTag = cols.length > 0;
for (let k = (tf.nbCells - 1); k >= 0; k--) {
@ -400,7 +389,7 @@ export class GridLayout extends Feature {
if (!this.tblHasColTag) {
col = createElm('col');
tf.tbl.insertBefore(col, tf.tbl.firstChild);
tf.dom().insertBefore(col, tf.dom().firstChild);
} else {
col = cols[k];
}
@ -423,7 +412,7 @@ export class GridLayout extends Feature {
} else {
// Headers row are moved from content table to headers table
for (let i = 0; i < this.headRows.length; i++) {
let row = this.tf.tbl.rows[this.headRows[i]];
let row = this.tf.dom().rows[this.headRows[i]];
tableHead.appendChild(row);
}
}
@ -471,7 +460,7 @@ export class GridLayout extends Feature {
*/
destroy() {
let tf = this.tf;
let tbl = tf.tbl;
let tbl = tf.dom();
if (!this.initialized) {
return;

View file

@ -3,6 +3,8 @@ import {createElm, createText, elm, removeElm} from '../dom';
import {addEvt, targetEvt, removeEvt} from '../event';
import {NONE} from '../const';
import {root} from '../root';
import {isEmpty} from '../types';
import {defaultsStr} from '../settings';
const WIKI_URL = 'https://github.com/koalyptus/TableFilter/wiki/' +
'4.-Filter-operators';
@ -20,27 +22,25 @@ export class Help extends Feature {
constructor(tf) {
super(tf, 'help');
let f = this.config;
let f = this.config.help_instructions || {};
/**
* ID of main custom container element
* @type {String}
*/
this.tgtId = f.help_instructions_target_id || null;
this.tgtId = defaultsStr(f.target_id, null);
/**
* ID of custom container element for instructions
* @type {String}
*/
this.contTgtId = f.help_instructions_container_target_id ||
null;
this.contTgtId = defaultsStr(f.container_target_id, null);
/**
* Instructions text (accepts HTML)
* @type {String}
*/
this.instrText = f.help_instructions_text ?
f.help_instructions_text :
this.instrText = !isEmpty(f.text) ? f.text :
'Use the filters above each column to filter and limit table ' +
'data. Advanced searches can be performed by using the following ' +
'operators: <br /><b>&lt;</b>, <b>&lt;=</b>, <b>&gt;</b>, ' +
@ -53,32 +53,31 @@ export class Help extends Feature {
* Instructions HTML
* @type {String}
*/
this.instrHtml = f.help_instructions_html || null;
this.instrHtml = defaultsStr(f.html, null);
/**
* Help button text ('?')
* @type {String}
*/
this.btnText = f.help_instructions_btn_text || '?';
this.btnText = defaultsStr(f.btn_text, '?');
/**
* Custom help button HTML
* @type {String}
*/
this.btnHtml = f.help_instructions_btn_html || null;
this.btnHtml = defaultsStr(f.btn_html, null);
/**
* Css class for help button
* @type {String}
*/
this.btnCssClass = f.help_instructions_btn_css_class || 'helpBtn';
this.btnCssClass = defaultsStr(f.btn_css_class, 'helpBtn');
/**
* Css class for help container element
* @type {String}
*/
this.contCssClass = f.help_instructions_container_css_class ||
'helpCont';
this.contCssClass = defaultsStr(f.container_css_class, 'helpCont');
/**
* Button DOM element
@ -193,9 +192,9 @@ export class Help extends Feature {
* Toggle help pop-up
*/
toggle() {
// check only if explicitily set to false as in this case undefined
// check only if explicitily disabled as in this case undefined
// signifies the help feature is enabled by default
if (this.enabled === false) {
if (!this.isEnabled()) {
return;
}
@ -225,7 +224,6 @@ export class Help extends Feature {
this.cont = null;
this.boundMouseup = null;
this.initialized = false;
}

View file

@ -1,6 +1,7 @@
import {createText, createElm, getText} from '../dom';
import {isArray} from '../types';
import {rgxEsc} from '../string';
import {defaultsStr} from '../settings';
/**
* Highlight matched keywords upon filtering
@ -21,7 +22,7 @@ export class HighlightKeyword {
* Css class for highlighted term
* @type {String}
*/
this.highlightCssClass = f.highlight_css_class || 'keyword';
this.highlightCssClass = defaultsStr(f.highlight_css_class, 'keyword');
/**
* TableFilter instance
@ -99,7 +100,7 @@ export class HighlightKeyword {
* @param {String} cssClass Css class to remove
*/
unhighlight(term, cssClass) {
let highlightedNodes = this.tf.tbl.querySelectorAll(`.${cssClass}`);
let highlightedNodes = this.tf.dom().querySelectorAll(`.${cssClass}`);
for (let i = 0; i < highlightedNodes.length; i++) {
let n = highlightedNodes[i];
let nodeVal = getText(n);

View file

@ -1,8 +1,9 @@
import {Feature} from '../feature';
import {createElm, createText, elm, removeElm} from '../dom';
import {isFn, EMPTY_FN} from '../types';
import {EMPTY_FN} from '../types';
import {root} from '../root';
import {NONE} from '../const';
import {defaultsStr, defaultsFn} from '../settings';
const EVENTS = [
'before-filtering',
@ -33,13 +34,13 @@ export class Loader extends Feature {
constructor(tf) {
super(tf, 'loader');
let f = this.config;
let f = this.config.loader || {};
/**
* ID of custom container element
* @type {String}
*/
this.targetId = f.loader_target_id || null;
this.targetId = defaultsStr(f.target_id, null);
/**
* Loader container DOM element
@ -51,19 +52,19 @@ export class Loader extends Feature {
* Text displayed when indicator is visible
* @type {String}
*/
this.text = f.loader_text || 'Loading...';
this.text = defaultsStr(f.text, 'Loading...');
/**
* Custom HTML injected in Loader's container element
* @type {String}
*/
this.html = f.loader_html || null;
this.html = defaultsStr(f.html, null);
/**
* Css class for Loader's container element
* @type {String}
*/
this.cssClass = f.loader_css_class || 'loader';
this.cssClass = defaultsStr(f.css_class, 'loader');
/**
* Close delay in milliseconds
@ -75,14 +76,13 @@ export class Loader extends Feature {
* Callback fired when loader is displayed
* @type {Function}
*/
this.onShow = isFn(f.on_show_loader) ?
f.on_show_loader : EMPTY_FN;
this.onShow = defaultsFn(f.on_show_loader, EMPTY_FN);
/**
* Callback fired when loader is closed
* @type {Function}
*/
this.onHide = isFn(f.on_hide_loader) ? f.on_hide_loader : EMPTY_FN;
this.onHide = defaultsFn(f.on_hide_loader, EMPTY_FN);
}
/**
@ -100,9 +100,9 @@ export class Loader extends Feature {
containerDiv.className = this.cssClass;
let targetEl = !this.targetId ?
tf.tbl.parentNode : elm(this.targetId);
tf.dom().parentNode : elm(this.targetId);
if (!this.targetId) {
targetEl.insertBefore(containerDiv, tf.tbl);
targetEl.insertBefore(containerDiv, tf.dom());
} else {
targetEl.appendChild(containerDiv);
}
@ -119,9 +119,7 @@ export class Loader extends Feature {
emitter.on(EVENTS, () => this.show(''));
emitter.on(EVENTS, () => this.show(NONE));
/**
* @inherited
*/
/** @inherited */
this.initialized = true;
}

View file

@ -0,0 +1,108 @@
import {Feature} from '../feature';
import {addClass, removeClass, hasClass} from '../dom';
import {EMPTY_FN} from '../types';
import {defaultsStr, defaultsFn} from '../settings';
/**
* Visual indicator for filtered columns
* @export
* @class MarkActiveColumns
* @extends {Feature}
*/
export class MarkActiveColumns extends Feature {
/**
* Create an instance of MarkActiveColumns
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'markActiveColumns');
let config = this.config.mark_active_columns || {};
/**
* Css class for filtered (active) columns
* @type {String}
*/
this.headerCssClass = defaultsStr(config.header_css_class,
'activeHeader');
/**
* Callback fired before a column is marked as filtered
* @type {Function}
*/
this.onBeforeActiveColumn = defaultsFn(config.on_before_active_column,
EMPTY_FN);
/**
* Callback fired after a column is marked as filtered
* @type {Function}
*/
this.onAfterActiveColumn = defaultsFn(config.on_after_active_column,
EMPTY_FN);
}
/**
* Initialise MarkActiveColumns instance
*/
init() {
if (this.initialized) {
return;
}
this.emitter.on(['before-filtering'], () => this.clearActiveColumns());
this.emitter.on(
['cell-processed'],
(tf, colIndex) => this.markActiveColumn(colIndex)
);
/** @inherited */
this.initialized = true;
}
/**
* Clear filtered columns visual indicator (background color)
*/
clearActiveColumns() {
let tf = this.tf;
let len = tf.getCellsNb();
for (let i = 0; i < len; i++) {
removeClass(tf.getHeaderElement(i), this.headerCssClass);
}
}
/**
* Mark currently filtered column
* @param {Number} colIndex Column index
*/
markActiveColumn(colIndex) {
let header = this.tf.getHeaderElement(colIndex);
if (hasClass(header, this.headerCssClass)) {
return;
}
this.onBeforeActiveColumn(this, colIndex);
addClass(header, this.headerCssClass);
this.onAfterActiveColumn(this, colIndex);
}
/**
* Remove feature
*/
destroy() {
if (!this.initialized) {
return;
}
this.clearActiveColumns();
this.emitter.off(['before-filtering'], () => this.clearActiveColumns());
this.emitter.off(
['cell-processed'],
(tf, colIndex) => this.markActiveColumn(colIndex)
);
/** @inherited */
this.initialized = false;
}
}

View file

@ -1,7 +1,8 @@
import {Feature} from '../feature';
import {createElm, elm, removeElm} from '../dom';
import {isEmpty, isFn, EMPTY_FN} from '../types';
import {isEmpty, EMPTY_FN} from '../types';
import {NONE} from '../const';
import {defaultsStr, defaultsFn} from '../settings';
/**
* UI when filtering yields no matches
@ -19,25 +20,25 @@ export class NoResults extends Feature {
super(tf, 'noResults');
//configuration object
let f = this.config.no_results_message;
let f = this.config.no_results_message || {};
/**
* Text (accepts HTML)
* @type {String}
*/
this.content = f.content || 'No results';
this.content = defaultsStr(f.content, 'No results');
/**
* Custom container DOM element
* @type {DOMElement}
*/
this.customContainer = f.custom_container || null;
this.customContainer = defaultsStr(f.custom_container, null);
/**
* ID of custom container element
* @type {String}
*/
this.customContainerId = f.custom_container_id || null;
this.customContainerId = defaultsStr(f.custom_container_id, null);
/**
* Indicates if UI is contained in a external element
@ -51,7 +52,7 @@ export class NoResults extends Feature {
* Css class assigned to container element
* @type {String}
*/
this.cssClass = f.css_class || 'no-results';
this.cssClass = defaultsStr(f.css_class, 'no-results');
/**
* Stores container DOM element
@ -63,29 +64,25 @@ export class NoResults extends Feature {
* Callback fired before the message is displayed
* @type {Function}
*/
this.onBeforeShow = isFn(f.on_before_show_msg) ?
f.on_before_show_msg : EMPTY_FN;
this.onBeforeShow = defaultsFn(f.on_before_show_msg, EMPTY_FN);
/**
* Callback fired after the message is displayed
* @type {Function}
*/
this.onAfterShow = isFn(f.on_after_show_msg) ?
f.on_after_show_msg : EMPTY_FN;
this.onAfterShow = defaultsFn(f.on_after_show_msg, EMPTY_FN);
/**
* Callback fired before the message is hidden
* @type {Function}
*/
this.onBeforeHide = isFn(f.on_before_hide_msg) ?
f.on_before_hide_msg : EMPTY_FN;
this.onBeforeHide = defaultsFn(f.on_before_hide_msg, EMPTY_FN);
/**
* Callback fired after the message is hidden
* @type {Function}
*/
this.onAfterHide = isFn(f.on_after_hide_msg) ?
f.on_after_hide_msg : EMPTY_FN;
this.onAfterHide = defaultsFn(f.on_after_hide_msg, EMPTY_FN);
}
/**
@ -97,7 +94,7 @@ export class NoResults extends Feature {
}
let tf = this.tf;
let target = this.customContainer || elm(this.customContainerId) ||
tf.tbl;
tf.dom();
//container
let cont = createElm('div');
@ -115,9 +112,7 @@ export class NoResults extends Feature {
// subscribe to after-filtering event
this.emitter.on(['after-filtering'], () => this.toggle());
/**
* @inherited
*/
/** @inherited */
this.initialized = true;
this.hide();
@ -174,10 +169,11 @@ export class NoResults extends Feature {
let tf = this.tf;
if (tf.gridLayout) {
let gridLayout = tf.feature('gridLayout');
this.cont.style.width = gridLayout.tblCont.clientWidth + 'px';
this.cont.style.width = gridLayout.headTbl.clientWidth + 'px';
} else {
this.cont.style.width = (tf.tbl.tHead ? tf.tbl.tHead.clientWidth :
tf.tbl.tBodies[0].clientWidth) + 'px';
this.cont.style.width = (tf.dom().tHead ?
tf.dom().tHead.clientWidth :
tf.dom().tBodies[0].clientWidth) + 'px';
}
}

View file

@ -1,8 +1,11 @@
import {Feature} from '../feature';
import {createElm, createOpt, createText, elm, removeElm} from '../dom';
import {isArray, isFn, isNull, EMPTY_FN} from '../types';
import {isArray, isNull, EMPTY_FN} from '../types';
import {addEvt, keyCode, removeEvt} from '../event';
import {INPUT, SELECT, NONE, ENTER_KEY} from '../const';
import {
defaultsStr, defaultsNb, defaultsBool, defaultsArr, defaultsFn
} from '../settings';
/**
* Paging UI component
@ -20,62 +23,62 @@ export class Paging extends Feature {
super(tf, 'paging');
// Configuration object
var f = this.config;
let f = this.config.paging || {};
/**
* Css class for the paging buttons (previous, next, etc.)
* @type {String}
*/
this.btnPageCssClass = f.paging_btn_css_class || 'pgInp';
this.btnCssClass = defaultsStr(f.btn_css_class, 'pgInp');
/**
/**
* Main select DOM element
* @type {DOMElement}
*/
this.pagingSlc = null;
this.pageSlc = null;
/**
* Results per page select DOM element
* @type {DOMElement}
*/
this.resultsPerPageSlc = null;
this.pageLengthSlc = null;
/**
* ID of custom container element
* @type {String}
*/
this.pagingTgtId = f.paging_target_id || null;
this.tgtId = defaultsStr(f.target_id, null);
/**
* Number of rows contained in a page
* @type {Number}
*/
this.pagingLength = !isNaN(f.paging_length) ? f.paging_length : 10;
this.pageLength = defaultsNb(f.length, 10);
/**
* ID of custom container element for the results per page selector
* @type {String}
*/
this.resultsPerPageTgtId = f.results_per_page_target_id || null;
this.pageLengthTgtId = defaultsStr(f.results_per_page_target_id, null);
/**
* Css class for the paging select element
* @type {String}
*/
this.pgSlcCssClass = f.paging_slc_css_class || 'pgSlc';
this.pgSlcCssClass = defaultsStr(f.slc_css_class, 'pgSlc');
/**
* Css class for the paging input element
* @type {String}
*/
this.pgInpCssClass = f.paging_inp_css_class || 'pgNbInp';
this.pgInpCssClass = defaultsStr(f.inp_css_class, 'pgNbInp');
/**
* Label and values for the results per page select, example of usage:
* ['Records: ', [10,25,50,100]]
* @type {Array}
*/
this.resultsPerPage = f.results_per_page || null;
this.resultsPerPage = defaultsArr(f.results_per_page, null);
/**
* Determines if results per page is configured
@ -87,13 +90,14 @@ export class Paging extends Feature {
* Css class for the results per page select
* @type {String}
*/
this.resultsSlcCssClass = f.results_slc_css_class || 'rspg';
this.resultsSlcCssClass = defaultsStr(f.results_slc_css_class, 'rspg');
/**
* Css class for the label preceding results per page select
* @type {String}
*/
this.resultsSpanCssClass = f.results_span_css_class || 'rspgSpan';
this.resultsSpanCssClass = defaultsStr(f.results_span_css_class,
'rspgSpan');
/**
* Index of the first row of current page
@ -120,105 +124,103 @@ export class Paging extends Feature {
* Next page button text
* @type {String}
*/
this.btnNextPageText = f.btn_next_page_text || '>';
this.btnNextPageText = defaultsStr(f.btn_next_page_text, '>');
/**
* Previous page button text
* @type {String}
*/
this.btnPrevPageText = f.btn_prev_page_text || '<';
this.btnPrevPageText = defaultsStr(f.btn_prev_page_text, '<');
/**
* Last page button text
* @type {String}
*/
this.btnLastPageText = f.btn_last_page_text || '>|';
this.btnLastPageText = defaultsStr(f.btn_last_page_text, '>|');
/**
* First page button text
* @type {String}
*/
this.btnFirstPageText = f.btn_first_page_text || '|<';
this.btnFirstPageText = defaultsStr(f.btn_first_page_text, '|<');
/**
* Next page button HTML
* @type {String}
*/
this.btnNextPageHtml = f.btn_next_page_html ||
this.btnNextPageHtml = defaultsStr(f.btn_next_page_html,
(!tf.enableIcons ? null :
'<input type="button" value="" class="' + this.btnPageCssClass +
' nextPage" title="Next page" />');
'<input type="button" value="" class="' + this.btnCssClass +
' nextPage" title="Next page" />'));
/**
* Previous page button HTML
* @type {String}
*/
this.btnPrevPageHtml = f.btn_prev_page_html ||
this.btnPrevPageHtml = defaultsStr(f.btn_prev_page_html,
(!tf.enableIcons ? null :
'<input type="button" value="" class="' + this.btnPageCssClass +
' previousPage" title="Previous page" />');
'<input type="button" value="" class="' + this.btnCssClass +
' previousPage" title="Previous page" />'));
/**
* First page button HTML
* @type {String}
*/
this.btnFirstPageHtml = f.btn_first_page_html ||
this.btnFirstPageHtml = defaultsStr(f.btn_first_page_html,
(!tf.enableIcons ? null :
'<input type="button" value="" class="' + this.btnPageCssClass +
' firstPage" title="First page" />');
'<input type="button" value="" class="' + this.btnCssClass +
' firstPage" title="First page" />'));
/**
* Last page button HTML
* @type {String}
*/
this.btnLastPageHtml = f.btn_last_page_html ||
this.btnLastPageHtml = defaultsStr(f.btn_last_page_html,
(!tf.enableIcons ? null :
'<input type="button" value="" class="' + this.btnPageCssClass +
' lastPage" title="Last page" />');
'<input type="button" value="" class="' + this.btnCssClass +
' lastPage" title="Last page" />'));
/**
* Text preceeding page selector drop-down
* @type {String}
*/
this.pageText = f.page_text || ' Page ';
this.pageText = defaultsStr(f.page_text, ' Page ');
/**
* Text after page selector drop-down
* @type {String}
*/
this.ofText = f.of_text || ' of ';
this.ofText = defaultsStr(f.of_text, ' of ');
/**
* Css class for the span containing total number of pages
* @type {String}
*/
this.nbPgSpanCssClass = f.nb_pages_css_class || 'nbpg';
this.nbPgSpanCssClass = defaultsStr(f.nb_pages_css_class, 'nbpg');
/**
* Determines if paging buttons are enabled (default: true)
* @type {Boolean}
*/
this.hasPagingBtns = f.paging_btns === false ? false : true;
this.hasBtns = defaultsBool(f.btns, true);
/**
* Defines page selector type, two possible values: 'select', 'input'
* @type {String}
*/
this.pageSelectorType = f.page_selector_type || SELECT;
this.pageSelectorType = defaultsStr(f.page_selector_type, SELECT);
/**
* Callback fired before the page is changed
* @type {Function}
*/
this.onBeforeChangePage = isFn(f.on_before_change_page) ?
f.on_before_change_page : EMPTY_FN;
this.onBeforeChangePage = defaultsFn(f.on_before_change_page, EMPTY_FN);
/**
* Callback fired after the page is changed
* @type {Function}
*/
this.onAfterChangePage = isFn(f.on_after_change_page) ?
f.on_after_change_page : EMPTY_FN;
this.onAfterChangePage = defaultsFn(f.on_after_change_page, EMPTY_FN);
/**
* Label preciding results per page select
@ -269,12 +271,12 @@ export class Paging extends Feature {
*/
this.pgAfter = null;
var start_row = tf.refRow;
var nrows = tf.getRowsNb(true);
let startRow = tf.refRow;
let nrows = tf.getRowsNb(true);
//calculates page nb
this.nbPages = Math.ceil((nrows - start_row) / this.pagingLength);
this.nbPages = Math.ceil((nrows - startRow) / this.pageLength);
var o = this;
let o = this;
/**
* Paging DOM events handlers
* @type {String}
@ -283,21 +285,21 @@ export class Paging extends Feature {
this.evt = {
slcIndex() {
return (o.pageSelectorType === SELECT) ?
o.pagingSlc.options.selectedIndex :
parseInt(o.pagingSlc.value, 10) - 1;
o.pageSlc.options.selectedIndex :
parseInt(o.pageSlc.value, 10) - 1;
},
nbOpts() {
return (o.pageSelectorType === SELECT) ?
parseInt(o.pagingSlc.options.length, 10) - 1 :
parseInt(o.pageSlc.options.length, 10) - 1 :
(o.nbPages - 1);
},
next() {
var nextIndex = o.evt.slcIndex() < o.evt.nbOpts() ?
let nextIndex = o.evt.slcIndex() < o.evt.nbOpts() ?
o.evt.slcIndex() + 1 : 0;
o.changePage(nextIndex);
},
prev() {
var prevIndex = o.evt.slcIndex() > 0 ?
let prevIndex = o.evt.slcIndex() > 0 ?
o.evt.slcIndex() - 1 : o.evt.nbOpts();
o.changePage(prevIndex);
},
@ -308,7 +310,7 @@ export class Paging extends Feature {
o.changePage(0);
},
_detectKey(e) {
var key = keyCode(e);
let key = keyCode(e);
if (key === ENTER_KEY) {
if (tf.sorted) {
tf.filter();
@ -331,9 +333,9 @@ export class Paging extends Feature {
* Initialize DOM elements
*/
init() {
var slcPages;
var tf = this.tf;
var evt = this.evt;
let slcPages;
let tf = this.tf;
let evt = this.evt;
if (this.initialized) {
return;
@ -345,13 +347,13 @@ export class Paging extends Feature {
if (this.resultsPerPage.length < 2) {
this.hasResultsPerPage = false;
} else {
this.pagingLength = this.resultsPerPage[1][0];
this.pageLength = this.resultsPerPage[1][0];
this.setResultsPerPage();
}
}
evt.slcPagesChange = (event) => {
var slc = event.target;
let slc = event.target;
this.changePage(slc.selectedIndex);
};
@ -370,20 +372,20 @@ export class Paging extends Feature {
}
// btns containers
var btnNextSpan = createElm('span');
var btnPrevSpan = createElm('span');
var btnLastSpan = createElm('span');
var btnFirstSpan = createElm('span');
let btnNextSpan = createElm('span');
let btnPrevSpan = createElm('span');
let btnLastSpan = createElm('span');
let btnFirstSpan = createElm('span');
if (this.hasPagingBtns) {
if (this.hasBtns) {
// Next button
if (!this.btnNextPageHtml) {
var btnNext = createElm(INPUT,
let btnNext = createElm(INPUT,
['type', 'button'],
['value', this.btnNextPageText],
['title', 'Next']
);
btnNext.className = this.btnPageCssClass;
btnNext.className = this.btnCssClass;
addEvt(btnNext, 'click', evt.next);
btnNextSpan.appendChild(btnNext);
} else {
@ -392,12 +394,12 @@ export class Paging extends Feature {
}
// Previous button
if (!this.btnPrevPageHtml) {
var btnPrev = createElm(INPUT,
let btnPrev = createElm(INPUT,
['type', 'button'],
['value', this.btnPrevPageText],
['title', 'Previous']
);
btnPrev.className = this.btnPageCssClass;
btnPrev.className = this.btnCssClass;
addEvt(btnPrev, 'click', evt.prev);
btnPrevSpan.appendChild(btnPrev);
} else {
@ -406,12 +408,12 @@ export class Paging extends Feature {
}
// Last button
if (!this.btnLastPageHtml) {
var btnLast = createElm(INPUT,
let btnLast = createElm(INPUT,
['type', 'button'],
['value', this.btnLastPageText],
['title', 'Last']
);
btnLast.className = this.btnPageCssClass;
btnLast.className = this.btnCssClass;
addEvt(btnLast, 'click', evt.last);
btnLastSpan.appendChild(btnLast);
} else {
@ -420,12 +422,12 @@ export class Paging extends Feature {
}
// First button
if (!this.btnFirstPageHtml) {
var btnFirst = createElm(INPUT,
let btnFirst = createElm(INPUT,
['type', 'button'],
['value', this.btnFirstPageText],
['title', 'First']
);
btnFirst.className = this.btnPageCssClass;
btnFirst.className = this.btnCssClass;
addEvt(btnFirst, 'click', evt.first);
btnFirstSpan.appendChild(btnFirst);
} else {
@ -435,23 +437,23 @@ export class Paging extends Feature {
}
// paging elements (buttons+drop-down list) are added to defined element
if (!this.pagingTgtId) {
if (!this.tgtId) {
tf.setToolbar();
}
var targetEl = !this.pagingTgtId ? tf.mDiv : elm(this.pagingTgtId);
let targetEl = !this.tgtId ? tf.mDiv : elm(this.tgtId);
targetEl.appendChild(btnFirstSpan);
targetEl.appendChild(btnPrevSpan);
var pgBeforeSpan = createElm('span');
let pgBeforeSpan = createElm('span');
pgBeforeSpan.appendChild(createText(this.pageText));
pgBeforeSpan.className = this.nbPgSpanCssClass;
targetEl.appendChild(pgBeforeSpan);
targetEl.appendChild(slcPages);
var pgAfterSpan = createElm('span');
let pgAfterSpan = createElm('span');
pgAfterSpan.appendChild(createText(this.ofText));
pgAfterSpan.className = this.nbPgSpanCssClass;
targetEl.appendChild(pgAfterSpan);
var pgSpan = createElm('span');
let pgSpan = createElm('span');
pgSpan.className = this.nbPgSpanCssClass;
pgSpan.appendChild(createText(' ' + this.nbPages + ' '));
targetEl.appendChild(pgSpan);
@ -465,7 +467,7 @@ export class Paging extends Feature {
this.pgCont = pgSpan;
this.pgBefore = pgBeforeSpan;
this.pgAfter = pgAfterSpan;
this.pagingSlc = slcPages;
this.pageSlc = slcPages;
this.setPagingInfo();
@ -489,15 +491,11 @@ export class Paging extends Feature {
* @param {Boolean} filterTable Execute filtering once paging instanciated
*/
reset(filterTable = false) {
var tf = this.tf;
if (this.isEnabled()) {
return;
}
this.enable();
this.init();
if (filterTable) {
tf.filter();
this.tf.filter();
}
}
@ -516,31 +514,31 @@ export class Paging extends Feature {
* @param {Array} validRows Collection of valid rows
*/
setPagingInfo(validRows) {
var tf = this.tf;
var mdiv = !this.pagingTgtId ? tf.mDiv : elm(this.pagingTgtId);
let tf = this.tf;
let mdiv = !this.tgtId ? tf.mDiv : elm(this.tgtId);
//store valid rows indexes
tf.validRowsIndex = validRows || tf.getValidRows(true);
//calculate nb of pages
this.nbPages = Math.ceil(tf.validRowsIndex.length / this.pagingLength);
this.nbPages = Math.ceil(tf.validRowsIndex.length / this.pageLength);
//refresh page nb span
this.pgCont.innerHTML = this.nbPages;
//select clearing shortcut
if (this.pageSelectorType === SELECT) {
this.pagingSlc.innerHTML = '';
this.pageSlc.innerHTML = '';
}
if (this.nbPages > 0) {
mdiv.style.visibility = 'visible';
if (this.pageSelectorType === SELECT) {
for (var z = 0; z < this.nbPages; z++) {
var opt = createOpt(z + 1, z * this.pagingLength, false);
this.pagingSlc.options[z] = opt;
for (let z = 0; z < this.nbPages; z++) {
let opt = createOpt(z + 1, z * this.pageLength, false);
this.pageSlc.options[z] = opt;
}
} else {
//input type
this.pagingSlc.value = this.currentPageNb;
this.pageSlc.value = this.currentPageNb;
}
} else {
@ -555,10 +553,10 @@ export class Paging extends Feature {
* @param {Array} validRows Collection of valid rows
*/
groupByPage(validRows) {
var tf = this.tf;
var rows = tf.tbl.rows;
var startPagingRow = parseInt(this.startPagingRow, 10);
var endPagingRow = startPagingRow + parseInt(this.pagingLength, 10);
let tf = this.tf;
let rows = tf.dom().rows;
let startPagingRow = parseInt(this.startPagingRow, 10);
let endPagingRow = startPagingRow + parseInt(this.pageLength, 10);
//store valid rows indexes
if (validRows) {
@ -566,11 +564,11 @@ export class Paging extends Feature {
}
//this loop shows valid rows of current page
for (var h = 0, len = tf.getValidRowsNb(true); h < len; h++) {
var validRowIdx = tf.validRowsIndex[h];
var r = rows[validRowIdx];
var isRowValid = r.getAttribute('validRow');
var rowDisplayed = false;
for (let h = 0, len = tf.getValidRowsNb(true); h < len; h++) {
let validRowIdx = tf.validRowsIndex[h];
let r = rows[validRowIdx];
let isRowValid = r.getAttribute('validRow');
let rowDisplayed = false;
if (h >= startPagingRow && h < endPagingRow) {
if (isNull(isRowValid) || Boolean(isRowValid === 'true')) {
@ -601,11 +599,11 @@ export class Paging extends Feature {
* 'previous', 'last', 'first' or page number as per param
*/
setPage(cmd) {
var tf = this.tf;
let tf = this.tf;
if (!tf.isInitialized() || !this.isEnabled()) {
return;
}
var btnEvt = this.evt,
let btnEvt = this.evt,
cmdtype = typeof cmd;
if (cmdtype === 'string') {
switch (cmd.toLowerCase()) {
@ -635,10 +633,10 @@ export class Paging extends Feature {
* Generates UI elements for the number of results per page drop-down
*/
setResultsPerPage() {
var tf = this.tf;
var evt = this.evt;
let tf = this.tf;
let evt = this.evt;
if (this.resultsPerPageSlc || !this.resultsPerPage) {
if (this.pageLengthSlc || !this.resultsPerPage) {
return;
}
@ -647,22 +645,22 @@ export class Paging extends Feature {
ev.target.blur();
};
var slcR = createElm(SELECT);
let slcR = createElm(SELECT);
slcR.className = this.resultsSlcCssClass;
var slcRText = this.resultsPerPage[0],
let slcRText = this.resultsPerPage[0],
slcROpts = this.resultsPerPage[1];
var slcRSpan = createElm('span');
let slcRSpan = createElm('span');
slcRSpan.className = this.resultsSpanCssClass;
// results per page select is added to external element
if (!this.resultsPerPageTgtId) {
if (!this.pageLengthTgtId) {
tf.setToolbar();
}
var targetEl = !this.resultsPerPageTgtId ?
tf.rDiv : elm(this.resultsPerPageTgtId);
let targetEl = !this.pageLengthTgtId ?
tf.rDiv : elm(this.pageLengthTgtId);
slcRSpan.appendChild(createText(slcRText));
var help = tf.feature('help');
let help = tf.feature('help');
if (help && help.btn) {
help.btn.parentNode.insertBefore(slcRSpan, help.btn);
help.btn.parentNode.insertBefore(slcR, help.btn);
@ -671,31 +669,31 @@ export class Paging extends Feature {
targetEl.appendChild(slcR);
}
for (var r = 0; r < slcROpts.length; r++) {
var currOpt = new Option(slcROpts[r], slcROpts[r], false, false);
for (let r = 0; r < slcROpts.length; r++) {
let currOpt = new Option(slcROpts[r], slcROpts[r], false, false);
slcR.options[r] = currOpt;
}
addEvt(slcR, 'change', evt.slcResultsChange);
this.slcResultsTxt = slcRSpan;
this.resultsPerPageSlc = slcR;
this.pageLengthSlc = slcR;
}
/**
* Remove number of results per page UI elements
*/
removeResultsPerPage() {
var tf = this.tf;
if (!tf.isInitialized() || !this.resultsPerPageSlc ||
let tf = this.tf;
if (!tf.isInitialized() || !this.pageLengthSlc ||
!this.resultsPerPage) {
return;
}
if (this.resultsPerPageSlc) {
removeElm(this.resultsPerPageSlc);
if (this.pageLengthSlc) {
removeElm(this.pageLengthSlc);
}
if (this.slcResultsTxt) {
removeElm(this.slcResultsTxt);
}
this.resultsPerPageSlc = null;
this.pageLengthSlc = null;
this.slcResultsTxt = null;
}
@ -704,7 +702,7 @@ export class Paging extends Feature {
* @param {Number} index Index of the page (0-n)
*/
changePage(index) {
var tf = this.tf;
let tf = this.tf;
if (!this.isEnabled()) {
return;
@ -714,20 +712,20 @@ export class Paging extends Feature {
if (index === null) {
index = this.pageSelectorType === SELECT ?
this.pagingSlc.options.selectedIndex : this.pagingSlc.value - 1;
this.pageSlc.options.selectedIndex : this.pageSlc.value - 1;
}
if (index >= 0 && index <= (this.nbPages - 1)) {
this.onBeforeChangePage(this, (index + 1));
this.currentPageNb = parseInt(index, 10) + 1;
if (this.pageSelectorType === SELECT) {
this.pagingSlc.options[index].selected = true;
this.pageSlc.options[index].selected = true;
} else {
this.pagingSlc.value = this.currentPageNb;
this.pageSlc.value = this.currentPageNb;
}
this.startPagingRow = (this.pageSelectorType === SELECT) ?
this.pagingSlc.value : (index * this.pagingLength);
this.pageSlc.value : (index * this.pageLength);
this.groupByPage();
@ -746,7 +744,7 @@ export class Paging extends Feature {
return;
}
this.resultsPerPageSlc.value = val;
this.pageLengthSlc.value = val;
this.onChangeResultsPerPage();
}
@ -761,44 +759,44 @@ export class Paging extends Feature {
}
let {
resultsPerPageSlc: slcR, pageSelectorType, pagingSlc, emitter
pageLengthSlc: slcR, pageSelectorType, pageSlc, emitter
} = this;
emitter.emit('before-page-length-change', tf);
let slcIndex = slcR.selectedIndex;
let slcPagesSelIndex = (pageSelectorType === SELECT) ?
pagingSlc.selectedIndex : parseInt(pagingSlc.value - 1, 10);
this.pagingLength = parseInt(slcR.options[slcIndex].value, 10);
this.startPagingRow = this.pagingLength * slcPagesSelIndex;
pageSlc.selectedIndex : parseInt(pageSlc.value - 1, 10);
this.pageLength = parseInt(slcR.options[slcIndex].value, 10);
this.startPagingRow = this.pageLength * slcPagesSelIndex;
if (!isNaN(this.pagingLength)) {
if (!isNaN(this.pageLength)) {
if (this.startPagingRow >= tf.nbFilterableRows) {
this.startPagingRow = (tf.nbFilterableRows - this.pagingLength);
this.startPagingRow = (tf.nbFilterableRows - this.pageLength);
}
this.setPagingInfo();
if (pageSelectorType === SELECT) {
let slcIdx =
(pagingSlc.options.length - 1 <= slcPagesSelIndex) ?
(pagingSlc.options.length - 1) : slcPagesSelIndex;
pagingSlc.options[slcIdx].selected = true;
let slcIdx = (pageSlc.options.length - 1 <= slcPagesSelIndex) ?
(pageSlc.options.length - 1) :
slcPagesSelIndex;
pageSlc.options[slcIdx].selected = true;
}
}
emitter.emit('after-page-length-change', tf, this.pagingLength);
emitter.emit('after-page-length-change', tf, this.pageLength);
}
/**
* Re-set page nb at page re-load
*/
resetPage() {
var tf = this.tf;
let tf = this.tf;
if (!this.isEnabled()) {
return;
}
this.emitter.emit('before-reset-page', tf);
var pgNb = tf.feature('store').getPageNb();
let pgNb = tf.feature('store').getPageNb();
if (pgNb !== '') {
this.changePage((pgNb - 1));
}
@ -809,15 +807,15 @@ export class Paging extends Feature {
* Re-set page length value at page re-load
*/
resetPageLength() {
var tf = this.tf;
let tf = this.tf;
if (!this.isEnabled()) {
return;
}
this.emitter.emit('before-reset-page-length', tf);
var pglenIndex = tf.feature('store').getPageLength();
let pglenIndex = tf.feature('store').getPageLength();
if (pglenIndex !== '') {
this.resultsPerPageSlc.options[pglenIndex].selected = true;
this.pageLengthSlc.options[pglenIndex].selected = true;
this.changeResultsPerPage();
}
this.emitter.emit('after-reset-page-length', tf, pglenIndex);
@ -831,16 +829,16 @@ export class Paging extends Feature {
return;
}
var evt = this.evt;
let evt = this.evt;
if (this.pagingSlc) {
if (this.pageSlc) {
if (this.pageSelectorType === SELECT) {
removeEvt(this.pagingSlc, 'change', evt.slcPagesChange);
removeEvt(this.pageSlc, 'change', evt.slcPagesChange);
}
else if (this.pageSelectorType === INPUT) {
removeEvt(this.pagingSlc, 'keypress', evt._detectKey);
removeEvt(this.pageSlc, 'keypress', evt._detectKey);
}
removeElm(this.pagingSlc);
removeElm(this.pageSlc);
}
if (this.btnNextCont) {
@ -892,9 +890,9 @@ export class Paging extends Feature {
this.emitter.off(['change-page-results'],
(tf, pageLength) => this.changeResultsPerPage(pageLength));
this.pagingSlc = null;
this.pageSlc = null;
this.nbPages = 0;
this.disable();
this.initialized = false;
}
}

View file

@ -1,9 +1,10 @@
import {Feature} from '../feature';
import {isFn, isUndef, EMPTY_FN} from '../types';
import {isUndef, EMPTY_FN} from '../types';
import {createElm, removeElm} from '../dom';
import {addEvt, cancelEvt, stopEvt, targetEvt, removeEvt} from '../event';
import {INPUT, NONE, CHECKLIST, MULTIPLE} from '../const';
import {root} from '../root';
import {defaultsStr, defaultsBool, defaultsArr, defaultsFn} from '../settings';
/**
* Pop-up filter component
@ -21,81 +22,78 @@ export class PopupFilter extends Feature {
super(tf, 'popupFilters');
// Configuration object
let f = this.config;
// Enable external filters
tf.isExternalFlt = true;
tf.externalFltTgtIds = [];
let f = this.config.popup_filters || {};
/**
* Close active popup filter upon filtering, enabled by default
* @type {Boolean}
*/
this.closeOnFiltering = f.popup_filters_close_on_filtering === false ?
false : true;
this.closeOnFiltering = defaultsBool(f.close_on_filtering, true);
/**
* Filter icon path
* @type {String}
*/
this.iconPath = f.popup_filters_image ||
tf.themesPath + 'icn_filter.gif';
this.iconPath = defaultsStr(f.image, tf.themesPath + 'icn_filter.gif');
/**
* Active filter icon path
* @type {string}
*/
this.activeIconPath = f.popup_filters_image_active ||
tf.themesPath + 'icn_filterActive.gif';
this.activeIconPath = defaultsStr(f.image_active,
tf.themesPath + 'icn_filterActive.gif');
/**
* HTML for the filter icon
* @type {string}
*/
this.iconHtml = f.popup_filters_image_html ||
'<img src="' + this.iconPath + '" alt="Column filter" />';
this.iconHtml = defaultsStr(f.image_html,
'<img src="' + this.iconPath + '" alt="Column filter" />');
/**
* Css class assigned to the popup container element
* @type {String}
*/
this.placeholderCssClass = defaultsStr(f.placeholder_css_class,
'popUpPlaceholder');
/**
* Css class assigned to filter container element
* @type {String}
*/
this.containerCssClass = f.popup_div_css_class || 'popUpFilter';
this.containerCssClass = defaultsStr(f.div_css_class, 'popUpFilter');
/**
* Ensure filter's container element width matches column width, enabled
* by default
* @type {Boolean}
*/
this.adjustToContainer =
f.popup_filters_adjust_to_container === false ? false : true;
this.adjustToContainer = defaultsBool(f.adjust_to_container, true);
/**
* Callback fired before a popup filter is opened
* @type {Function}
*/
this.onBeforeOpen = isFn(f.on_before_popup_filter_open) ?
f.on_before_popup_filter_open : EMPTY_FN;
this.onBeforeOpen = defaultsFn(f.on_before_popup_filter_open, EMPTY_FN);
/**
* Callback fired after a popup filter is opened
* @type {Function}
*/
this.onAfterOpen = isFn(f.on_after_popup_filter_open) ?
f.on_after_popup_filter_open : EMPTY_FN;
this.onAfterOpen = defaultsFn(f.on_after_popup_filter_open, EMPTY_FN);
/**
* Callback fired before a popup filter is closed
* @type {Function}
*/
this.onBeforeClose = isFn(f.on_before_popup_filter_close) ?
f.on_before_popup_filter_close : EMPTY_FN;
this.onBeforeClose = defaultsFn(f.on_before_popup_filter_close,
EMPTY_FN);
/**
* Callback fired after a popup filter is closed
* @type {Function}
*/
this.onAfterClose = isFn(f.on_after_popup_filter_close) ?
f.on_after_popup_filter_close : EMPTY_FN;
this.onAfterClose = defaultsFn(f.on_after_popup_filter_close, EMPTY_FN);
/**
* Collection of filters spans
@ -123,7 +121,7 @@ export class PopupFilter extends Feature {
* @type {Array}
* @private
*/
this.fltElms = this.filtersCache || [];
this.fltElms = defaultsArr(this.filtersCache, []);
/**
* Prefix for pop-up filter container ID
@ -198,6 +196,12 @@ export class PopupFilter extends Feature {
let tf = this.tf;
// Enable external filters
tf.externalFltTgtIds = [''];
// Override filters row index supplied by configuration
tf.filtersRowIndex = 0;
// Override headers row index if no grouped headers
// TODO: Because of the filters row generation, headers row index needs
// adjusting: prevent useless row generation
@ -277,12 +281,14 @@ export class PopupFilter extends Feature {
build(colIndex, div) {
let tf = this.tf;
let contId = `${this.prfxDiv}${tf.id}_${colIndex}`;
let cont = div || createElm('div', ['id', contId]);
cont.className = this.containerCssClass;
tf.externalFltTgtIds.push(cont.id);
let placeholder = createElm('div', ['class', this.placeholderCssClass]);
let cont = div ||
createElm('div', ['id', contId], ['class', this.containerCssClass]);
tf.externalFltTgtIds[colIndex] = cont.id;
placeholder.appendChild(cont);
let header = tf.getHeaderElement(colIndex);
header.insertBefore(cont, header.firstChild);
header.insertBefore(placeholder, header.firstChild);
addEvt(cont, 'click', (evt) => stopEvt(evt));
this.fltElms[colIndex] = cont;
}
@ -364,7 +370,7 @@ export class PopupFilter extends Feature {
if (i === exceptIdx) {
continue;
}
let fltType = tf.getFilterType(i);
let fltType = this.tf.getFilterType(i);
let isMultipleFilter =
(fltType === CHECKLIST || fltType === MULTIPLE);
@ -408,6 +414,7 @@ export class PopupFilter extends Feature {
this.filtersCache = [];
for (let i = 0; i < this.fltElms.length; i++) {
let container = this.fltElms[i],
placeholder = container.parentNode,
icon = this.fltSpans[i],
iconImg = this.fltIcons[i];
if (container) {
@ -415,6 +422,10 @@ export class PopupFilter extends Feature {
this.filtersCache[i] = container;
}
container = null;
if (placeholder) {
removeElm(placeholder);
}
placeholder = null;
if (icon) {
removeElm(icon);
}
@ -429,7 +440,7 @@ export class PopupFilter extends Feature {
this.fltIcons = [];
// TODO: expose an API to handle external filter IDs
tf.externalFltTgtIds = [];
this.tf.externalFltTgtIds = [];
// unsubscribe to events
this.emitter.off(['before-filtering'], () => this.setIconsState());

View file

@ -1,6 +1,7 @@
import {Feature} from '../feature';
import {createElm, createText, elm, removeElm} from '../dom';
import {isFn, EMPTY_FN} from '../types';
import {EMPTY_FN} from '../types';
import {defaultsStr, defaultsFn} from '../settings';
/**
* Rows counter UI component
@ -18,13 +19,13 @@ export class RowsCounter extends Feature {
super(tf, 'rowsCounter');
// TableFilter configuration
let f = this.config;
let f = this.config.rows_counter || {};
/**
* ID of custom container element
* @type {String}
*/
this.targetId = f.rows_counter_target_id || null;
this.targetId = defaultsStr(f.target_id, null);
/**
* Container DOM element
@ -44,14 +45,14 @@ export class RowsCounter extends Feature {
* Text preceding the total number of rows
* @type {String}
*/
this.text = f.rows_counter_text || 'Rows: ';
this.text = defaultsStr(f.text, 'Rows: ');
/**
* Separator symbol appearing between the first and last visible rows of
* current page when paging is enabled. ie: Rows: 31-40 / 70
* @type {String}
*/
this.fromToTextSeparator = f.from_to_text_separator || '-';
this.fromToTextSeparator = defaultsStr(f.separator, '-');
/**
* Separator symbol appearing between the first and last visible rows of
@ -59,27 +60,27 @@ export class RowsCounter extends Feature {
* enabled. ie: Rows: 31-40 / 70
* @type {String}
*/
this.overText = f.over_text || ' / ';
this.overText = defaultsStr(f.over_text, ' / ');
/**
* Css class for container element
* @type {String}
*/
this.cssClass = f.tot_rows_css_class || 'tot';
this.cssClass = defaultsStr(f.css_class, 'tot');
/**
* Callback fired before the counter is refreshed
* @type {Function}
*/
this.onBeforeRefreshCounter = isFn(f.on_before_refresh_counter) ?
f.on_before_refresh_counter : EMPTY_FN;
this.onBeforeRefreshCounter = defaultsFn(f.on_before_refresh_counter,
EMPTY_FN);
/**
* Callback fired after the counter is refreshed
* @type {Function}
*/
this.onAfterRefreshCounter = isFn(f.on_after_refresh_counter) ?
f.on_after_refresh_counter : EMPTY_FN;
this.onAfterRefreshCounter = defaultsFn(f.on_after_refresh_counter,
EMPTY_FN);
}
/**
@ -111,8 +112,7 @@ export class RowsCounter extends Feature {
countDiv.appendChild(countText);
countDiv.appendChild(countSpan);
targetEl.appendChild(countDiv);
}
else {
} else {
//custom container, no need to append statusDiv
targetEl.appendChild(countText);
targetEl.appendChild(countSpan);
@ -133,7 +133,6 @@ export class RowsCounter extends Feature {
/**
* Refreshes the rows counter
* @param {Number} p Optional parameter the total number of rows to display
* @returns
*/
refresh(p) {
if (!this.initialized || !this.isEnabled()) {
@ -154,16 +153,17 @@ export class RowsCounter extends Feature {
} else {
let paging = tf.feature('paging');
if (paging) {
let nbValidRows = tf.getValidRowsNb();
//paging start row
let pagingStartRow = parseInt(paging.startPagingRow, 10) +
((tf.getValidRowsNb() > 0) ? 1 : 0);
((nbValidRows > 0) ? 1 : 0);
let pagingEndRow =
(pagingStartRow + paging.pagingLength) - 1 <=
tf.getValidRowsNb() ?
pagingStartRow + paging.pagingLength - 1 :
tf.getValidRowsNb();
(pagingStartRow + paging.pageLength) - 1 <=
nbValidRows ?
pagingStartRow + paging.pageLength - 1 :
nbValidRows;
totTxt = pagingStartRow + this.fromToTextSeparator +
pagingEndRow + this.overText + tf.getValidRowsNb();
pagingEndRow + this.overText + nbValidRows;
}
}

View file

@ -3,6 +3,7 @@ import {Hash} from './hash';
import {Storage} from './storage';
import {isEmpty} from '../string';
import {isArray, isNull, isString, isUndef} from '../types';
import {defaultsBool, defaultsNb} from '../settings';
/**
* Features state object persistable with localStorage, cookie or URL hash
@ -20,7 +21,7 @@ export class State extends Feature {
constructor(tf) {
super(tf, 'state');
let cfg = this.config.state;
let cfg = this.config.state || {};
/**
* Determines whether state is persisted with URL hash
@ -47,7 +48,7 @@ export class State extends Feature {
* Persist filters values, enabled by default
* @type {Boolean}
*/
this.persistFilters = cfg.filters === false ? false : true;
this.persistFilters = defaultsBool(cfg.filters, true);
/**
* Persist current page number when paging is enabled
@ -83,8 +84,8 @@ export class State extends Feature {
* Cookie duration in hours
* @type {Boolean}
*/
this.cookieDuration = !isNaN(cfg.cookie_duration) ?
parseInt(cfg.cookie_duration, 10) : 87600;
this.cookieDuration = defaultsNb(parseInt(cfg.cookie_duration, 10),
87600);
/**
* Enable Storage if localStorage or cookie is required

View file

@ -1,7 +1,8 @@
import {Feature} from '../feature';
import {root} from '../root';
import {createElm, createText, elm, removeElm} from '../dom';
import {isFn, EMPTY_FN} from '../types';
import {EMPTY_FN} from '../types';
import {defaultsStr, defaultsFn} from '../settings';
const EVENTS = [
'after-filtering',
@ -31,13 +32,13 @@ export class StatusBar extends Feature {
super(tf, 'statusBar');
// Configuration object
let f = this.config;
let f = this.config.status_bar || {};
/**
* ID of custom container element
* @type {String}
*/
this.targetId = f.status_bar_target_id || null;
this.targetId = defaultsStr(f.target_id, null);
/**
* Container DOM element
@ -64,13 +65,13 @@ export class StatusBar extends Feature {
* Text preceding status message
* @type {String}
*/
this.text = f.status_bar_text || '';
this.text = defaultsStr(f.text, '');
/**
* Css class for container element
* @type {String}
*/
this.cssClass = f.status_bar_css_class || 'status';
this.cssClass = defaultsStr(f.css_class, 'status');
/**
* Message visibility duration in milliseconds
@ -83,85 +84,85 @@ export class StatusBar extends Feature {
* Callback fired before the message is displayed
* @type {Function}
*/
this.onBeforeShowMsg = isFn(f.on_before_show_msg) ?
f.on_before_show_msg : EMPTY_FN;
this.onBeforeShowMsg = defaultsFn(f.on_before_show_msg, EMPTY_FN);
/**
* Callback fired after the message is displayed
* @type {Function}
*/
this.onAfterShowMsg = isFn(f.on_after_show_msg) ?
f.on_after_show_msg : EMPTY_FN;
this.onAfterShowMsg = defaultsFn(f.on_after_show_msg, EMPTY_FN);
/**
* Message appearing upon filtering
* @type {String}
*/
this.msgFilter = f.msg_filter || 'Filtering data...';
this.msgFilter = defaultsStr(f.msg_filter, 'Filtering data...');
/**
* Message appearing when a drop-down filter is populated
* @type {String}
*/
this.msgPopulate = f.msg_populate || 'Populating filter...';
this.msgPopulate = defaultsStr(f.msg_populate, 'Populating filter...');
/**
* Message appearing when a checklist filter is populated
* @type {String}
*/
this.msgPopulateCheckList = f.msg_populate_checklist ||
'Populating list...';
this.msgPopulateCheckList = defaultsStr(f.msg_populate_checklist,
'Populating list...');
/**
* Message appearing when a pagination page is changed
* @type {String}
*/
this.msgChangePage = f.msg_change_page || 'Collecting paging data...';
this.msgChangePage = defaultsStr(f.msg_change_page,
'Collecting paging data...');
/**
* Message appearing when filters are cleared
* @type {String}
*/
this.msgClear = f.msg_clear || 'Clearing filters...';
this.msgClear = defaultsStr(f.msg_clear, 'Clearing filters...');
/**
* Message appearing when the page length is changed
* @type {String}
*/
this.msgChangeResults = f.msg_change_results ||
'Changing results per page...';
this.msgChangeResults = defaultsStr(f.msg_change_results,
'Changing results per page...');
/**
* Message appearing when the page is re-set
* @type {String}
*/
this.msgResetPage = f.msg_reset_page || 'Re-setting page...';
this.msgResetPage = defaultsStr(f.msg_reset_page, 'Re-setting page...');
/**
* Message appearing when the page length is re-set
* @type {String}
*/
this.msgResetPageLength = f.msg_reset_page_length ||
'Re-setting page length...';
this.msgResetPageLength = defaultsStr(f.msg_reset_page_length,
'Re-setting page length...');
/**
* Message appearing upon column sorting
* @type {String}
*/
this.msgSort = f.msg_sort || 'Sorting data...';
this.msgSort = defaultsStr(f.msg_sort, 'Sorting data...');
/**
* Message appearing when extensions are loading
* @type {String}
*/
this.msgLoadExtensions = f.msg_load_extensions ||
'Loading extensions...';
this.msgLoadExtensions = defaultsStr(f.msg_load_extensions,
'Loading extensions...');
/**
* Message appearing when themes are loading
* @type {String}
*/
this.msgLoadThemes = f.msg_load_themes || 'Loading theme(s)...';
this.msgLoadThemes = defaultsStr(f.msg_load_themes,
'Loading theme(s)...');
}
/**

View file

@ -1,4 +1,3 @@
import Cookie from '../cookie';
import {root} from '../root';

View file

@ -19,11 +19,14 @@ export const parse = (value, decimal = '.') => {
let regex = new RegExp('[^0-9-' + decimal + ']', ['g']);
let unformatted = parseFloat(
('' + value)
.replace(/\((.*)\)/, '-$1') // replace bracketed values with negatives
.replace(regex, '') // strip out any cruft
.replace(decimal, '.') // make sure decimal point is standard
// replace bracketed values with negatives
.replace(/\((.*)\)/, '-$1')
// strip out any cruft
.replace(regex, '')
// make sure decimal point is standard
.replace(decimal, '.')
);
// This will fail silently
return !isNaN(unformatted) ? unformatted : 0;
}
};

53
src/settings.js Normal file
View file

@ -0,0 +1,53 @@
import {isBoolean, isString, isFn, isArray} from './types';
/** Configuration settings helpers */
/**
* If passed value is not of boolean type return the default value
* otherwise return the value itself
* @param {Boolean|Any} value
* @param {Boolean} default value
* @return {Boolean|Any}
*/
export const defaultsBool =
(val, defaultVal) => isBoolean(val) ? val : defaultVal;
/**
* If passed value is not of string type return the default value
* otherwise return the value itself
* @param {String|Any} value
* @param {String} default value
* @return {String|Any}
*/
export const defaultsStr =
(val, defaultVal) => isString(val) ? val : defaultVal;
/**
* If passed value is not of number type return the default value
* otherwise return the value itself
* @param {Number|Any} value
* @param {Number} default value
* @return {Number|Any}
*/
export const defaultsNb =
(val, defaultVal) => isNaN(val) ? defaultVal : val;
/**
* If passed value is not of array type return the default value
* otherwise return the value itself
* @param {Array|Any} value
* @param {Array} default value
* @return {Array|Any}
*/
export const defaultsArr =
(val, defaultVal) => isArray(val) ? val : defaultVal;
/**
* If passed value is not of function type return the default value
* otherwise return the value itself
* @param {Function|Any} value
* @param {Function} default value
* @return {Function|Any}
*/
export const defaultsFn =
(val, defaultVal) => isFn(val) ? val : defaultVal;

View file

@ -1,6 +1,7 @@
/**
* Sorting utilities
*/
import {parse as parseNb} from './number';
import {Date as SugarDate} from 'sugar-date';
/** Sorting utilities */
/**
* Case insensitive compare function for passed strings
@ -13,21 +14,69 @@
export const ignoreCase = (a, b) => {
let x = a.toLowerCase();
let y = b.toLowerCase();
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
return x < y ? -1 : (x > y ? 1 : 0);
};
/**
* Sorts passed numbers in a ascending manner
* Compare function for sorting passed numbers in ascending manner
* @param {Number} First number
* @param {Number} Second number
* @param {Number} Negative, zero or positive number
* @return {Number} Negative, zero or positive number
*/
export const numSortAsc = (a, b) => (a - b);
/**
* Sorts passed numbers in a descending manner
* Compare function for sorting passed numbers in descending manner
* @param {Number} First number
* @param {Number} Second number
* @param {Number} Negative, zero or positive number
* @return {Number} Negative, zero or positive number
*/
export const numSortDesc = (a, b) => (b - a);
/**
* Compare function for sorting passed dates in ascending manner according to
* the corresponding UTC numeric value (returned by getTime)
* @param {Date} First date object
* @param {Date} Second date object
* @return {Number} Negative, zero or positive number
*/
export const dateSortAsc = (date1, date2) => date1.getTime() - date2.getTime();
/**
* Compare function for sorting passed dates in descending manner according to
* the corresponding UTC numeric value (returned by getTime)
* @param {Date} First date object
* @param {Date} Second date object
* @return {Number} Negative, zero or positive number
*/
export const dateSortDesc = (date1, date2) => date2.getTime() - date1.getTime();
/**
* Curried compare function for sorting passed formatted numbers in desired
* fashion according to supplied compare function and decimal separator
* @param {Function} Compare function
* @param {String} [decimal=','] Decimal separator
* @return {Function} Compare function receiving parsed numeric arguments
*/
export const sortNumberStr = (compareFn, decimal = ',') => {
return (numStr1, numStr2) => {
let num1 = parseNb(numStr1, decimal);
let num2 = parseNb(numStr2, decimal);
return compareFn(num1, num2);
};
};
/**
* Curried compare function for sorting passed formatted dates in desired
* fashion according to supplied compare function and locale
* @param {Function} Compare function
* @param {String} [locale='en-us'] Locale code
* @return {Function} Compare function receiving parsed date arguments
*/
export const sortDateStr = (compareFn, locale = 'en-us') => {
return (dateStr1, dateStr2) => {
let date1 = SugarDate.create(dateStr1, locale);
let date2 = SugarDate.create(dateStr2, locale);
return compareFn(date1, date2);
};
};

View file

@ -14,7 +14,7 @@ export const trim = (text) => {
return text.trim();
}
return text.replace(/^\s*|\s*$/g, '');
}
};
/**
* Checks if passed string is empty
@ -32,7 +32,7 @@ export const rgxEsc = (text) => {
let chars = /[-\/\\^$*+?.()|[\]{}]/g;
let escMatch = '\\$&';
return String(text).replace(chars, escMatch);
}
};
/**
* Returns passed string as lowercase if caseSensitive flag set false. By
@ -45,7 +45,7 @@ export const matchCase = (text, caseSensitive = false) => {
return text.toLowerCase();
}
return text;
}
};
/**
* Checks if passed data contains the searched term
@ -73,4 +73,4 @@ export const contains = (term, data, exactMatch = false, caseSensitive = false,
regexp = new RegExp(rgxEsc(term), modifier);
}
return regexp.test(data);
}
};

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,7 @@ export const isArray =
/**
* Check passed argument is a string
* @param {String} obj objue
* @param {String} obj obj
* @returns {Boolean}
*/
export const isString =
@ -51,6 +51,14 @@ export const isString =
export const isNumber =
(obj) => Object.prototype.toString.call(obj) === '[object Number]';
/**
* Check passed argument is a boolean
* @param {Boolean} obj
* @returns {Boolean}
*/
export const isBoolean =
(obj) => Object.prototype.toString.call(obj) === '[object Boolean]';
/**
* Check passed argument is undefined
* @param {Any} obj

File diff suppressed because it is too large Load diff

View file

@ -92,7 +92,7 @@ select.flt_multi
box-sizing initial
display initial
// Pop-up filters elements
// pop-up filters elements
div.popUpFilter
arrow(top, 10px white, 2px $th-bg-color)
box-shadow(3px 3px 2px #888)
@ -103,3 +103,7 @@ div.popUpFilter
background-color $th-bg-color
border 1px solid $filter-row-bg-color
padding 0
// pop-up container
.popUpPlaceholder
position relative

View file

@ -11,7 +11,6 @@ div.grd_Cont
width 800px
height auto
overflow hidden
padding 3px 3px 3px 3px
background-color $grid-layout-bg-color
border 1px solid $grid-layout-border-color
@ -50,8 +49,9 @@ div.grd_tblCont
// headers' table container
div.grd_headTblCont
display block
margin-right 20px
height auto
width 800px
overflow hidden
border-bottom 1px solid $grid-layout-border-color
background-color $grid-layout-bg-color
@ -63,10 +63,6 @@ div.grd_headTblCont table
table-layout fixed
box-sizing initial
div.grd_tblCont table
border-right 1px solid $grid-layout-border-color
box-sizing initial
// headers
div.grd_tblCont table th
div.grd_headTblCont table th

View file

@ -49,8 +49,9 @@
<script data-config>
var filtersConfig = {
base_path: '../dist/tablefilter/',
grid_layout: true,
grid_width: '900px',
grid_layout: {
width: '900px'
},
alternate_rows: true,
btn_reset: true,
rows_counter: true,

View file

@ -24,8 +24,9 @@
filters_row_index: 1,
state: true,
alternate_rows: true,
rows_counter: true,
rows_counter_text: 'Rows: ',
rows_counter: {
text: 'Rows: '
},
btn_reset: true,
status_bar: true,
msg_filter: 'Filtering...'

View file

@ -82,8 +82,9 @@
var tfConfig = {
base_path: '../dist/tablefilter/',
alternate_rows: true,
rows_counter: true,
rows_counter_text: "Displayed rows: ",
rows_counter: {
text: 'Displayed rows: '
},
loader: true,
status: true,
status_bar: true,
@ -105,7 +106,7 @@ var tfConfig = {
col_8: "none",
/* external filters */
external_flt_grid: true,
// external_flt_grid: true,
external_flt_grid_ids: [
'slcCountry',
'slcCode',

View file

@ -26,8 +26,9 @@ var tfConfig = {
'string', 'string', 'string',
'number', 'string', 'string', 'date'
],
rows_counter: true,
rows_counter_text: 'Books: ',
rows_counter: {
text: 'Books: '
},
alternate_rows: true,
btn_reset: true,

View file

@ -58,8 +58,9 @@ var tfConfig = {
rows_counter: true,
btn_reset: true,
status_bar: true,
paging: true,
paging_length: 15,
paging: {
length: 15
},
enable_empty_option: true,
enable_non_empty_option: true,
enable_default_theme: true,

View file

@ -30,8 +30,9 @@
<script data-config>
var filtersConfig = {
base_path: '../dist/tablefilter/',
paging: true,
results_per_page: ['Records: ', [10,25,50,100]],
paging: {
results_per_page: ['Records: ', [10, 25, 50, 100]]
},
state: {
types: ['local_storage'],
filters: true,
@ -42,12 +43,14 @@
alternate_rows: true,
btn_reset: true,
rows_counter: true,
loader: true,
loader_html: '<div id="lblMsg"></div>',
loader_css_class: 'myLoader',
status_bar: true,
status_bar_target_id: 'lblMsg',
status_bar_css_class: 'myStatus',
loader: {
html: '<div id="lblMsg"></div>',
css_class: 'myLoader'
},
status_bar: {
target_id: 'lblMsg',
css_class: 'myStatus'
},
no_results_message: true,
col_0: 'select',
col_1: 'select',

View file

@ -35,8 +35,9 @@ var tfConfig = {
'string', 'string', 'number',
'string', 'string', 'date'
],
rows_counter: true,
rows_counter_text: 'Books: ',
rows_counter: {
text: 'Books: '
},
alternate_rows: true,
btn_reset: true,
mark_active_columns: true,

View file

@ -6,12 +6,68 @@
mark_active_columns: true
});
tf.init();
var markActiveColumns = tf.feature('markActiveColumns');
module('Sanity checks');
test('Active columns', function() {
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
notEqual(markActiveColumns, null, 'markActiveColumns instanciated');
deepEqual(tf.markActiveColumns, true, 'markActiveColumns property');
});
module('Feature interface');
test('Properties', function() {
deepEqual(markActiveColumns.tf instanceof TableFilter, true,
'TableFilter instance');
deepEqual(markActiveColumns.feature, 'markActiveColumns',
'Feature name');
deepEqual(markActiveColumns.enabled, true, 'Feature enabled');
deepEqual(markActiveColumns.initialized, true, 'Feature initialized');
deepEqual(typeof markActiveColumns.emitter, 'object',
'Feature has emitter instance');
deepEqual(typeof markActiveColumns.config, 'object',
'TF configuration object');
deepEqual(typeof markActiveColumns.init, 'function',
'Feature init method');
deepEqual(typeof markActiveColumns.destroy, 'function',
'Feature destroy method');
deepEqual(typeof markActiveColumns.reset, 'function',
'Feature reset method');
deepEqual(typeof markActiveColumns.enable, 'function',
'Feature enable method');
deepEqual(typeof markActiveColumns.disable, 'function',
'Feature enable method');
deepEqual(typeof markActiveColumns.isEnabled, 'function',
'Feature enable method');
});
test('Can destroy', function() {
markActiveColumns.destroy();
deepEqual(markActiveColumns.initialized, false, 'not initialised');
});
test('Can reset', function() {
markActiveColumns.reset();
deepEqual(markActiveColumns.enabled, true, 'enabled');
});
test('Can disable', function() {
markActiveColumns.disable();
deepEqual(markActiveColumns.enabled, false, 'disabled');
});
test('Can enable', function() {
markActiveColumns.enable();
deepEqual(markActiveColumns.enabled, true, 'enabled');
});
test('Can init', function() {
markActiveColumns.destroy();
markActiveColumns.enable();
markActiveColumns.init();
deepEqual(markActiveColumns.enabled, true, 'enabled');
});
test('Can check is enabled', function() {
markActiveColumns.isEnabled();
deepEqual(markActiveColumns.enabled, true, 'enabled');
});
module('Behaviour');
test('Active columns', function() {
tf.setFilterValue(1, 'Bri');
tf.setFilterValue(3, '>2');
@ -76,8 +132,130 @@
header3.className.indexOf('activeHeader') !== -1,
true,
'Active filter indicator');
});
test('Cannot destroy if not initialised', function() {
// setup
var clearActiveColumns = markActiveColumns.clearActiveColumns;
var hit = 0;
markActiveColumns.clearActiveColumns = function() { hit++; };
markActiveColumns.initialized = false;
// act
markActiveColumns.destroy();
// assert
deepEqual(hit, 0, 'clearActiveColumns not called');
markActiveColumns.clearActiveColumns = clearActiveColumns;
});
module('Callbacks');
test('Can trigger onBeforeActiveColumn callback', function() {
// setup
var colIndex;
markActiveColumns.onBeforeActiveColumn = function(feature, colIdx) {
colIndex = colIdx;
};
// act
markActiveColumns.markActiveColumn(2);
// assert
deepEqual(colIndex, 2,
'expected column index passed to onBeforeActiveColumn');
});
test('Can trigger onAfterActiveColumn callback', function() {
// setup
var colIndex;
markActiveColumns.onAfterActiveColumn = function(feature, colIdx) {
colIndex = colIdx;
};
// act
markActiveColumns.markActiveColumn(3);
// assert
deepEqual(colIndex, 3,
'expected column index passed to onAfterActiveColumn');
});
module('mark_active_columns as configuration object');
test('Sanity checks', function() {
tf.destroy();
var hit = 0;
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
mark_active_columns: {
header_css_class: 'myCssClass',
on_before_active_column: function(feature, colIndex) {
hit = colIndex;
},
on_after_active_column: function(feature, colIndex) {
hit = colIndex;
}
}
});
tf.init();
var markActiveColumns = tf.feature('markActiveColumns');
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
notEqual(markActiveColumns, null, 'markActiveColumns instanciated');
deepEqual(tf.markActiveColumns, true, 'markActiveColumns property');
test('Custom header CSS class', function() {
// setup
tf.setFilterValue(1, 'Bri');
tf.setFilterValue(3, '>2');
var header1 = tf.getHeaderElement(1);
var header3 = tf.getHeaderElement(3);
// act
tf.filter();
// assert
deepEqual(
header1.className.indexOf('myCssClass') !== -1,
true,
'Active filter indicator');
deepEqual(
header3.className.indexOf('myCssClass') !== -1,
true,
'Active filter indicator');
});
test('on_before_active_column callback', function() {
// setup
tf.clearFilters();
tf.setFilterValue(1, 'Bri');
// act
tf.filter();
// assert
deepEqual(hit, 1,
'expected column index passed to on_before_active_column');
});
test('on_after_active_column callback', function() {
// setup
tf.clearFilters();
tf.setFilterValue(3, '>2');
// act
tf.filter();
// assert
deepEqual(hit, 3,
'expected column index passed to on_after_active_column');
});
module('Tear-down');
test('can destroy', function() {
tf.destroy();
deepEqual(tf.isInitialized(), false, 'Filters removed');
});
});
})(window, TableFilter);

View file

@ -4,7 +4,7 @@ var tf = new TableFilter('demo', {
alternate_rows: true
});
tf.init();
var tbl = tf.tbl;
var tbl = tf.dom();
var altRows = tf.feature('alternateRows');
module('Sanity checks');
@ -110,7 +110,7 @@ test('Cannot init if initialised', function() {
// setup
var processAll = altRows.processAll;
var hit = 0;
altRows.processAll = function() { hit++ };
altRows.processAll = function() { hit++; };
altRows.initialized = true;
// act
@ -126,7 +126,7 @@ test('Cannot processAll if not enabled', function() {
// setup
var setRowBg = altRows.setRowBg;
var hit = 0;
altRows.setRowBg = function() { hit++ };
altRows.setRowBg = function() { hit++; };
altRows.enabled = false;
// act
@ -142,7 +142,7 @@ test('Cannot setRowBg if not enabled', function() {
// setup
var removeRowBg = altRows.removeRowBg;
var hit = 0;
altRows.removeRowBg = function() { hit++ };
altRows.removeRowBg = function() { hit++; };
altRows.enabled = false;
// act
@ -171,7 +171,7 @@ test('Cannot destroy if not initialised', function() {
// setup
var getRowsNb = altRows.tf.getRowsNb;
var hit = 0;
altRows.tf.getRowsNb = function() { hit++ };
altRows.tf.getRowsNb = function() { hit++; };
altRows.initialized = false;
// act
@ -288,13 +288,13 @@ test('Grid layout: initialising alternating rows', function() {
alternate_rows: true
});
tf.init();
tbl = tf.tbl;
tbl = tf.dom();
altRows = tf.feature('alternateRows');
deepEqual(
tbl.querySelectorAll('tr.odd').length, 4, 'Expected bg for odd rows');
tbl.querySelectorAll('tr.odd').length, 4, 'Expected bg for odd rows');
deepEqual(
tbl.querySelectorAll('tr.even').length, 3, 'Expected bg for even rows');
tbl.querySelectorAll('tr.even').length, 3, 'Expected bg for even rows');
});
test('Grid layout: filter column', function() {
@ -352,7 +352,7 @@ test('Sort: alternating rows with column sorted at start', function() {
deepEqual(altRows.oddCss, 'odd', 'Expected odd css class');
function checkAlternateRows(tf) {
tbl = tf.tbl;
tbl = tf.dom();
altRows = tf.feature('alternateRows');
test('Alternate rows with sort column at start option', function() {

View file

@ -15,8 +15,8 @@
test('for filtered table', function() {
tf.setFilterValue(0, 'Hello');
tf.filter();
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
var alwaysVisibleRow1 = tf.dom().rows[4];
var alwaysVisibleRow2 = tf.dom().rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'',
@ -31,8 +31,8 @@
test('after filters are cleared', function() {
tf.clearFilters();
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
var alwaysVisibleRow1 = tf.dom().rows[4];
var alwaysVisibleRow2 = tf.dom().rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'',
@ -52,8 +52,9 @@
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
rows_always_visible: [4, 9],
paging: true,
paging_length: 2
paging: {
length: 2
}
});
tf.init();
var paging = tf.feature('paging');
@ -62,8 +63,8 @@
test('for filtered table', function() {
tf.setFilterValue(0, 'Hello');
tf.filter();
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
var alwaysVisibleRow1 = tf.dom().rows[4];
var alwaysVisibleRow2 = tf.dom().rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'',
@ -78,8 +79,8 @@
test('after filters are cleared', function() {
tf.clearFilters();
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
var alwaysVisibleRow1 = tf.dom().rows[4];
var alwaysVisibleRow2 = tf.dom().rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'none',
@ -92,11 +93,10 @@
);
});
test('after changing pagination page', function() {
paging.setPage(2);
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
var alwaysVisibleRow1 = tf.dom().rows[4];
var alwaysVisibleRow2 = tf.dom().rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'',

View file

@ -14,6 +14,14 @@ var tf1 = new TableFilter('demo1', {
on_loaded: colsVisibilityTests
}]
});
tf1.registerExtension(
{
init: function() {},
destroy: function() {}
},
'myExtension'
);
tf1.init();
module('Sanity checks');
@ -28,6 +36,7 @@ test('TableFilter object', function() {
deepEqual(tf.getFilterId(0), 'flt0_demo', 'Filter DOM element id');
deepEqual(tf.getStartRowIndex(), 2, 'Start of filterable rows');
deepEqual(tf.getLastRowIndex(), 8, 'Last row index');
deepEqual(tf.dom().nodeName, 'TABLE', 'Working DOM element type');
deepEqual(
tf.getHeadersText(),
[
@ -42,7 +51,7 @@ test('TableFilter object', function() {
);
deepEqual(tf.getValidRowsNb(), 0, 'Number of valid rows before filtering');
deepEqual(
tf.getCellData(tf.tbl.rows[3].cells[2]),
tf.getCellData(tf.dom().rows[3].cells[2]),
982,
'getCellData returns typed value'
);
@ -274,7 +283,7 @@ test('Get table data', function() {
);
deepEqual(
tf.getFilteredColumnValues(2, true),
['Road Distance (km)','2781','1533','2045'],
['Road Distance (km)','2781','1533','2045'],
'Get filtered column data with headers'
);
deepEqual(
@ -379,10 +388,20 @@ test('Can select checklist options with array', function() {
tf.setFilterValue(2, '');
tf.setFilterValue(2, ['1412', '982']);
deepEqual(tf.getFilterValue(2), ['1412', '982'],
deepEqual(tf.getFilterValue(2), ['982', '1412'],
'Column 2 filter values');
});
test('get and set filter value can handle out of range column index',
function() {
// act
tf.setFilterValue(11, '');
// assert
deepEqual(tf.getFilterValue(11), '',
'return empty string for inexistent filter');
});
module('TableFilter with pop-up filters');
test('Sanity checks', function() {
tf.destroy();
@ -621,7 +640,7 @@ test('Get table data', function() {
);
deepEqual(
tf.getFilteredColumnValues(2, true),
['Road Distance (km)','2781','1533','2045'],
['Road Distance (km)','2781','1533','2045'],
'Get filtered column data with headers'
);
deepEqual(
@ -718,6 +737,20 @@ function colsVisibilityTests() { // issue 94
});
test('Extension Sanity checks', function() {
deepEqual(
tf1.hasExtension('colsVisibility'),
true,
'ColsVisibility in extensions registry'
);
deepEqual(
tf1.hasExtension('myExtension'),
true,
'myExtension in extensions registry'
);
});
test('Destroy', function() {
tf1.destroy();
deepEqual(tf1.isInitialized(), false, 'Filters removed');

View file

@ -21,7 +21,7 @@
test('Sanity checks', function() {
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
deepEqual(tf.cellParser.cols.length, 1,
'Columns implementing cell parser')
'Columns implementing cell parser');
deepEqual(typeof tf.cellParser.parse, 'function', 'Parse function');
deepEqual(
tf.getFilterElement(0).nodeName, 'SELECT', 'Expected filter type');
@ -41,7 +41,7 @@
test('Can parse with custom function', function() {
// setup
var cell = tf.tbl.rows[3].cells[0];
var cell = tf.dom().rows[3].cells[0];
// act
var value = tf.getCellValue(cell);
@ -55,12 +55,12 @@
// setup
var initialCellParser = tf.cellParser;
var hit = 0;
var cell = tf.tbl.rows[3].cells[0];
var cell = tf.dom().rows[3].cells[0];
tf.cellParser.cols = [];
tf.cellParser.parse = function() {
hit++;
}
};
// act
tf.getCellValue(cell);

View file

@ -41,7 +41,7 @@ test('Can refresh all drop-down filters', function() {
tf.clearFilters();
var build = checkList.build;
var hit = 0;
checkList.build = function() { hit++ };
checkList.build = function() { hit++; };
//act
checkList.refreshAll();
@ -103,6 +103,7 @@ test('Can sort options', function() {
col_2: 'checklist',
col_3: 'checklist',
col_4: 'checklist',
col_types: ['string', 'string', 'number', 'number', 'number'],
sort_num_asc: [2, 3],
sort_num_desc: [4]
});

View file

@ -6,8 +6,9 @@ var totRowIndex = table.getElementsByTagName('tr').length;
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
col_types: ['string', 'string', 'number', 'number', 'number'],
paging: true,
paging_length: 4,
paging: {
length: 4
},
rows_always_visible: [
totRowIndex-6,
totRowIndex-5,

View file

@ -9,7 +9,7 @@
module('Sanity checks');
test('Column widths', function() {
var cols = tf.tbl.getElementsByTagName('col');
var cols = tf.dom().getElementsByTagName('col');
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
deepEqual(cols[1].style.width, '100px', 'Expected column width');
deepEqual(cols[4].style.width, '', 'Expected column width');
@ -21,8 +21,7 @@
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
col_widths: ['150px', '100px', '175px', '120px', '200px'],
grid_layout: true,
sort: false
grid_layout: true
});
tf.init();
var cols = tf.feature('gridLayout').headTbl.getElementsByTagName('col');

View file

@ -70,7 +70,7 @@ test('Popup container auto-closes when user clicks away', function() {
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent('mouseup', true, true);
// mouseup fired from a table cell
tf.tbl.rows[3].cells[2].dispatchEvent(evObj);
tf.dom().rows[3].cells[2].dispatchEvent(evObj);
// assert
deepEqual(ext.contEl.style.display, 'none',

View file

@ -69,7 +69,7 @@ test('Popup container auto-closes when user clicks away', function() {
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent('mouseup', true, true);
// mouseup fired from a table cell
tf.tbl.rows[3].cells[2].dispatchEvent(evObj);
tf.dom().rows[3].cells[2].dispatchEvent(evObj);
// assert
deepEqual(ext.contEl.style.display, 'none',

View file

@ -282,6 +282,24 @@
deepEqual(tf.getValidRows().length, 8, 'Expected rows');
});
module('Locale helpers');
test('Can get decimal separator for given column from config', function() {
// act
var result = tf.getDecimal(3);
// assert
deepEqual(result, ',', 'Decimal separator for given column');
});
test('Can get decimal separator for given column from global setting',
function() {
// act
var result = tf.getDecimal(1);
// assert
deepEqual(result, '.', 'Decimal separator for given column');
});
module('Tear-down');
test('can destroy TableFilter DOM elements', function() {
tf.destroy();

View file

@ -136,6 +136,22 @@ test('Can add date formats from config', function() {
);
});
test('Can get locale for a column index retrieved from config', function() {
// act
var result = dateType.getLocale(6);
// assert
deepEqual(result, 'fr', 'Locale for given column');
});
test('Can get locale for a column index from global setting', function() {
// act
var result = dateType.getLocale(1);
// assert
deepEqual(result, 'en', 'Locale for given column');
});
module('Tear-down');
test('can destroy TableFilter DOM elements', function() {
tf.destroy();

View file

@ -5,13 +5,14 @@ var tf = new TableFilter('demo', {
});
tf.init();
var rowsCounter = tf.feature('rowsCounter');
var rowToAdd = tf.tbl.rows[8];
var rowToAdd = tf.dom().rows[8];
var tf1 = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
rows_counter: true,
paging: true,
paging_length: 3
paging: {
length: 3
}
});
module('Sanity checks');
@ -27,7 +28,7 @@ module('DOM changes');
test('Can filter after row is removed', function() {
// setup
tf.clearFilters();
tf.tbl.deleteRow(-1);
tf.dom().deleteRow(-1);
// act
tf.filter();
@ -44,7 +45,7 @@ test('Can filter after row is removed', function() {
test('Can filter after row is added', function() {
// setup
tf.clearFilters();
tf.tbl.tBodies[0].appendChild(rowToAdd);
tf.dom().tBodies[0].appendChild(rowToAdd);
// act
tf.filter();
@ -104,7 +105,7 @@ test('Can filter and change a page after row is removed', function() {
var paging = tf1.feature('paging');
var rowsCounter = tf1.feature('rowsCounter');
tf1.clearFilters();
tf1.tbl.deleteRow(-1);
tf1.dom().deleteRow(-1);
// act
tf1.filter();
@ -124,7 +125,7 @@ test('Can filter and change page after row is added', function() {
var paging = tf1.feature('paging');
var rowsCounter = tf1.feature('rowsCounter');
tf1.clearFilters();
tf1.tbl.tBodies[0].appendChild(rowToAdd);
tf1.dom().tBodies[0].appendChild(rowToAdd);
// act
tf1.filter();

View file

@ -41,7 +41,7 @@ test('Can refresh all drop-down filters', function() {
tf.clearFilters();
var build = dropdown.build;
var hit = 0;
dropdown.build = function() { hit++ };
dropdown.build = function() { hit++; };
//act
dropdown.refreshAll();
@ -95,6 +95,7 @@ test('Can sort options', function() {
col_2: 'multiple',
col_3: 'select',
col_4: 'multiple',
col_types: ['string', 'string', 'number', 'number', 'number'],
sort_num_asc: [2, 3],
sort_num_desc: [4]
});

View file

@ -7,7 +7,6 @@ var tf = new TableFilter('demo', {
col_3: 'multiple',
col_4: 'checklist',
/* external filters */
external_flt_grid: true,
external_flt_grid_ids: [
'extFrom',
'extDestination',
@ -21,7 +20,7 @@ tf.init();
module('Sanity checks');
test('External filters', function() {
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
deepEqual(tf.isExternalFlt, true, 'Has external filters');
deepEqual(tf.isExternalFlt(), true, 'Has external filters');
deepEqual(tf.externalFltTgtIds.length, 5,
'External filters ids length');
deepEqual(tf.getFiltersRowIndex(), 0, 'Filters row index');
@ -82,7 +81,6 @@ test('Sanity checks', function() {
col_3: 'multiple',
col_4: 'checklist',
/* external filters */
external_flt_grid: true,
external_flt_grid_ids: [
'extFrom',
'extDestination',
@ -95,7 +93,7 @@ test('Sanity checks', function() {
tf.init();
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
deepEqual(tf.isExternalFlt, true, 'Has external filters');
deepEqual(tf.isExternalFlt(), true, 'Has external filters');
deepEqual(tf.externalFltTgtIds.length, 5,
'External filters ids length');
deepEqual(tf.getFiltersRowIndex(), 1, 'Filters row index');
@ -154,7 +152,6 @@ test('Sanity checks', function() {
col_3: 'multiple',
col_4: 'checklist',
/* external filters */
external_flt_grid: true,
external_flt_grid_ids: [
'extFrom',
'extDestination',
@ -167,7 +164,7 @@ test('Sanity checks', function() {
tf.init();
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
deepEqual(tf.isExternalFlt, true, 'Has external filters');
deepEqual(tf.isExternalFlt(), true, 'Has external filters');
deepEqual(tf.externalFltTgtIds.length, 5,
'External filters ids length');
deepEqual(tf.getFiltersRowIndex(), 0, 'Filters row index');

View file

@ -236,9 +236,9 @@ test('can filter date with different date format', function(){
test('can filter empty value with [empty] operator', function(){
// setup
var cellValue = tf.getCellValue(tf.tbl.rows[2].cells[2]);
var cellValue = tf.getCellValue(tf.dom().rows[2].cells[2]);
tf.clearFilters();
tf.tbl.rows[2].cells[2].innerHTML = '';
tf.dom().rows[2].cells[2].innerHTML = '';
// act
tf.setFilterValue(2, '[empty]');
@ -251,7 +251,7 @@ test('can filter empty value with [empty] operator', function(){
'Expected match'
);
tf.tbl.rows[2].cells[2].innerHTML = cellValue;
tf.dom().rows[2].cells[2].innerHTML = cellValue;
});
test('can filter empty value with [nonempty] operator', function(){

View file

@ -11,7 +11,7 @@ tf.init();
var extTargetElement = document.createElement('div');
extTargetElement.setAttribute('id', 'test');
document.body.insertBefore(extTargetElement, tf.tbl);
document.body.insertBefore(extTargetElement, tf.dom());
module('Sanity checks');
test('Filters visibility extension', function() {

View file

@ -7,7 +7,7 @@ tf.init();
var extTargetElement = document.createElement('div');
extTargetElement.setAttribute('id', 'test');
document.body.insertBefore(extTargetElement, tf.tbl);
document.body.insertBefore(extTargetElement, tf.dom());
module('Sanity checks');
test('Filters visibility extension', function() {
@ -33,7 +33,7 @@ module('Check behaviours');
test('Toggle filters', function() {
var ext = tf.extension('filtersVisibility');
ext.toggle();
var filtersRow = tf.tbl.rows[tf.getFiltersRowIndex()];
var filtersRow = tf.dom().rows[tf.getFiltersRowIndex()];
deepEqual(filtersRow.style.display, 'none', 'Filters hidden');
ext.toggle();
deepEqual(filtersRow.style.display, '', 'Filters displayed');

View file

@ -28,8 +28,9 @@ test('Sanity checks', function() {
base_path: '../dist/tablefilter/',
filters_row_index: 3,
headers_row_index: 2,
paging: true,
paging_length: 3
paging: {
length: 3
}
});
tf.init();

View file

@ -7,8 +7,9 @@ var tf = new TableFilter('demo', {
page_number: true,
page_length: true
},
paging: true,
results_per_page: ['Records: ', [2, 4, 6]],
paging: {
results_per_page: ['Records: ', [2, 4, 6]]
}
});
tf.init();
var state = tf.feature('state');
@ -46,7 +47,7 @@ test('Can parse a URL hash', function() {
// URL-encoded version of:
// #{"page":2,"page_length":4,"col_2":{"flt":">500"}}
var hashStr = '#%7B%22page%22%3A2%2C%22page_length%22%3A4'+
'%2C%22col_2%22%3A%7B%22flt%22%3A%22%3E500%22%7D%7D'
'%2C%22col_2%22%3A%7B%22flt%22%3A%22%3E500%22%7D%7D';
// act
var result = hash.parse(hashStr);

View file

@ -70,7 +70,7 @@ test('Help container auto-closes when user clicks away', function() {
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent('mouseup', true, true);
// mouseup fired from a table cell
tf.tbl.rows[3].cells[2].dispatchEvent(evObj);
tf.dom().rows[3].cells[2].dispatchEvent(evObj);
// assert
deepEqual(help.cont.style.display, 'none',
@ -135,20 +135,62 @@ test('Re-set UI', function() {
});
module('Destroy and re-init with help property undefined');
module('Destroy and re-init');
test('Can init help when property is undefined and toolbar is set',
function() {
tf.destroy();
tf.help = undefined;
tf.rowsCounter = true;
var help = tf.feature('help');
help.btnText = '?';
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
help_instructions: undefined,
// creates toolbar
rows_counter: true
});
tf.init();
var help = tf.feature('help');
notEqual(help.btn, null, 'btn property');
deepEqual(help.btn.childNodes[1].innerHTML, '?', 'Button text');
}
);
test('Does not init help when property is undefined and toolbar is not set ' +
'by other feature(s)',
function() {
tf.destroy();
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/'
});
tf.init();
var help = tf.feature('help');
deepEqual(help.initialized, false, 'feature not initialized');
deepEqual(help.btn, null, 'btn property not set');
deepEqual(help.cont, null, 'cont property not set');
});
test('Can init help when property is defined with a literal object ' +
'and toolbar is set',
function() {
tf.destroy();
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
help_instructions: {
btn_text: '??',
text: 'hello world'
},
// creates toolbar
rows_counter: true
});
tf.init();
var help = tf.feature('help');
notEqual(help.btn, null, 'btn property');
deepEqual(help.btn.childNodes[1].innerHTML, '??', 'Button text');
deepEqual(help.instrText, 'hello world', 'Text property');
deepEqual(help.cont.innerHTML.indexOf('hello world') !== -1, true,
'Text in DOM element');
});
test('Can toggle help when property is undefined and toolbar is set',
function() {
tf.destroy();
@ -166,8 +208,7 @@ test('Can toggle help when property is undefined and toolbar is set',
notEqual(help, null, 'help instantiated');
deepEqual(help.enabled, true, 'help enabled');
deepEqual(help.cont.style.display, 'inline', 'Container is open');
}
);
});
module('Tear-down');
test('can destroy TableFilter DOM elements', function() {

View file

@ -17,12 +17,12 @@ test('Highlighted keywords', function() {
tf.setFilterValue(1, 'Perth');
tf.setFilterValue(3, '3.1');
tf.filter();
deepEqual(tf.tbl.querySelectorAll('.keyword').length, 2,
deepEqual(tf.dom().querySelectorAll('.keyword').length, 2,
'Number of applied CSS classes');
tf.clearFilters();
// issue 155
deepEqual(tf.tbl.querySelectorAll('.keyword').length, 0,
deepEqual(tf.dom().querySelectorAll('.keyword').length, 0,
'Number of applied CSS classes');
});
@ -30,17 +30,17 @@ test('Highlighted keywords', function() {
test('Match same term with increasing number of chars', function() {
tf.setFilterValue(1, 'Pe');
tf.filter();
deepEqual(tf.tbl.querySelectorAll('.keyword').length, 1,
deepEqual(tf.dom().querySelectorAll('.keyword').length, 1,
'Search term matched');
tf.setFilterValue(1, 'Per');
tf.filter();
deepEqual(tf.tbl.querySelectorAll('.keyword').length, 1,
deepEqual(tf.dom().querySelectorAll('.keyword').length, 1,
'Search term matched');
tf.setFilterValue(1, 'Pert');
tf.filter();
deepEqual(tf.tbl.querySelectorAll('.keyword').length, 1,
deepEqual(tf.dom().querySelectorAll('.keyword').length, 1,
'Search term matched');
});
@ -59,7 +59,7 @@ test('can destroy TableFilter DOM elements and clean highlighted words',
tf.filter();
tf.destroy();
deepEqual(tf.isInitialized(), false, 'Filters removed');
deepEqual(tf.tbl.querySelectorAll('.keyword').length, 0,
deepEqual(tf.dom().querySelectorAll('.keyword').length, 0,
'Number of applied CSS classes');
}
);

View file

@ -1,7 +1,8 @@
var tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
paging: true,
paging_length: 2,
paging: {
length: 2
},
results_per_page: ['Results per page ', [2,4,6]],
extensions: [{
name: 'sort',
@ -15,7 +16,7 @@ var paging = tf.feature('paging');
module('Sanity checks');
test('Paging component', function() {
notEqual(paging, null, 'Paging instanciated');
deepEqual(paging.pagingLength, 2, 'Paging length');
deepEqual(paging.pageLength, 2, 'Paging length');
deepEqual(paging.nbPages, 4, 'Number of pages');
});
test('Sort extension', function() {
@ -31,14 +32,14 @@ test('It contains options', function() {
var sort = tf.extension('sort');
sort.sortByColumnIndex(0);
deepEqual(paging.pagingSlc.options.length, 4, 'Expected options number');
deepEqual(paging.pageSlc.options.length, 4, 'Expected options number');
});
test('Can select a page', function() {
var sort = tf.extension('sort');
sort.sortByColumnIndex(1);
paging.setPage(3);
deepEqual(paging.pagingSlc.selectedIndex, 2, 'Expected selected option');
deepEqual(paging.pageSlc.selectedIndex, 2, 'Expected selected option');
});
module('Changing pages when column is sorted (issue #70)');

View file

@ -12,6 +12,22 @@ test('Loader component', function() {
notEqual(loader, null, 'Loader instanciated');
equal(loader.cont.nodeName, 'DIV', 'Loader DOM container');
});
test('Does not init if initialised', function() {
// setup
var show = loader.show;
var hit = 0;
loader.show = function() {
hit++;
};
// act
loader.init();
// assert
deepEqual(hit, 0, 'does not initialise');
loader.show = show;
});
module('Feature interface');
test('Properties', function() {

80
test/test-no-config.html Normal file
View file

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TableFilter no configuration tests</title>
<link rel="stylesheet" href="libs/qunit/qunit.css">
<script src="libs/qunit/qunit.js"></script>
<script src="libs/polyfill.js"></script>
</head>
<body>
<table id="demo">
<thead>
<tr>
<th>From</th>
<th>Destination</th>
<th>Road Distance (km)</th>
<th>By Air (hrs)</th>
<th>By Rail (hrs)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Sydney</strong></td>
<td>Adelaide</td>
<td>1412</td>
<td>1.4</td>
<td>25.3</td>
</tr>
<tr>
<td><strong>Sydney</strong></td>
<td>Brisbane</td>
<td>982</td>
<td>1.5</td>
<td>16</td>
</tr>
<tr>
<td><strong>Sydney</strong></td>
<td>Canberra</td>
<td>286</td>
<td>.6</td>
<td>4.3</td>
</tr>
<tr>
<td><strong>Sydney</strong></td>
<td>Melbourne</td>
<td>872</td>
<td>1.1</td>
<td>10.5</td>
</tr>
<tr>
<td><strong>Adelaide</strong></td>
<td>Perth</td>
<td>2781</td>
<td>3.1</td>
<td>38</td>
</tr>
<tr>
<td><strong>Adelaide</strong></td>
<td>Alice Springs</td>
<td>1533</td>
<td>2</td>
<td>20.25</td>
</tr>
<tr>
<td><strong>Adelaide</strong></td>
<td>Brisbane</td>
<td>2045</td>
<td>2.15</td>
<td>40</td>
</tr>
</tbody>
</table>
<script src="../dist/tablefilter/tablefilter.js"></script>
<script src="test-no-config.js"></script>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
</body>
</html>

63
test/test-no-config.js Normal file
View file

@ -0,0 +1,63 @@
(function(win, TableFilter){
var tf = new TableFilter('demo');
tf.basePath = '../dist/tablefilter/';
tf.init();
module('Sanity checks');
test('Features', function() {
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
deepEqual(tf.fltGrid, true, 'fltGrid property');
notEqual(tf.getFilterElement(0), null,
'Filter element for column 0');
deepEqual(tf.refRow, 2, 'Reference row index');
deepEqual(Object.keys(tf.Mod).length, 14, 'Features instantiated');
notEqual(tf.feature('rowsCounter'), null, 'RowsCounter instantiated');
deepEqual(tf.rowsCounter, false, 'RowsCounter not enabled');
});
module('Feature life cycle');
test('Can init', function() {
// setup
var rowsCounter = tf.feature('rowsCounter');
tf.rowsCounter = true;
rowsCounter.enable();
// act
rowsCounter.init();
// assert
deepEqual(rowsCounter.enabled, true, 'rowsCounter enabled');
deepEqual(rowsCounter.initialized, true, 'rowsCounter initialized');
});
test('Can destroy', function() {
// setup
var rowsCounter = tf.feature('rowsCounter');
// act
rowsCounter.destroy();
// assert
deepEqual(rowsCounter.initialized, false, 'rowsCounter initialized');
});
test('Can reset', function() {
// setup
var rowsCounter = tf.feature('rowsCounter');
// act
rowsCounter.reset();
// assert
deepEqual(rowsCounter.enabled, true, 'rowsCounter enabled');
deepEqual(rowsCounter.initialized, true, 'rowsCounter initialized');
});
module('Tear-down');
test('TableFilter removed', function() {
tf.destroy();
deepEqual(tf.isInitialized(), false, 'Filters removed');
});
})(window, TableFilter);

View file

@ -137,9 +137,10 @@
tf = null;
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
grid_enable_default_filters: false,
col_width: ['100px','100px','100px','100px','100px'],
grid_layout: true
grid_layout: {
filters: false
}
});
// act

View file

@ -49,8 +49,9 @@ test('Grid layout with no header', function() {
tf.destroy();
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
grid_layout: true,
grid_no_headers: true
grid_layout: {
no_headers: true
}
});
tf.init();

View file

@ -143,7 +143,7 @@ test('Sanity checks', function() {
deepEqual(tfGl.noResults, true, 'noResults property');
deepEqual(noResultsGl.cont.nodeName, 'DIV', 'Container element');
deepEqual(noResultsGl.cont.className, 'no-results',
'Container element default CSS class');
'Container element default CSS class');
test('Can display no results message in grid layout', function() {
tfGl.setFilterValue(0, 'sadasd');
@ -154,7 +154,7 @@ test('Sanity checks', function() {
'No results message displayed');
deepEqual(
parseInt(noResultsGl.cont.style.width, 10),
gridLayout.tblCont.clientWidth,
gridLayout.headTbl.clientWidth,
'Container element width'
);
});

View file

@ -3,7 +3,7 @@
module('TableFilter with no rows');
test('throws when no rows', function() {
throws(
function() { new TableFilter('demo') },
function() { new TableFilter('demo'); },
Error,
'Throws Error when DOM table does not contain rows'
);

View file

@ -1,9 +1,10 @@
var tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
paging: true,
paging_length: 2,
results_per_page: ['Results per page ', [2, 4, 6]]
paging: {
length: 2,
results_per_page: ['Results per page ', [2, 4, 6]]
}
});
tf.init();
@ -11,7 +12,7 @@ var paging = tf.feature('paging');
module('Sanity checks');
test('Paging component', function() {
notEqual(paging, null, 'Paging instanciated');
deepEqual(paging.pagingLength, 2, 'Paging length');
deepEqual(paging.pageLength, 2, 'Paging length');
deepEqual(paging.nbPages, 4, 'Number of pages');
});
module('Feature interface');
@ -33,7 +34,7 @@ test('Properties', function() {
});
test('Can destroy', function() {
paging.destroy();
deepEqual(paging.enabled, false, 'disabled');
deepEqual(paging.initialized, false, 'not initialized');
});
test('Can reset', function() {
paging.reset();
@ -60,8 +61,8 @@ test('Can check is enabled', function() {
module('UI elements');
test('Paging UI elements', function() {
notEqual(paging.pagingSlc, null, 'Paging drop-down element');
notEqual(paging.resultsPerPageSlc, null,
notEqual(paging.pageSlc, null, 'Paging drop-down element');
notEqual(paging.pageLengthSlc, null,
'Number of results per page drop-down element');
notEqual(paging.btnNextCont, null, 'Next button container element');
notEqual(paging.btnPrevCont, null, 'Previous button container element');
@ -71,8 +72,8 @@ test('Paging UI elements', function() {
test('Destroy Paging component', function() {
paging.destroy();
deepEqual(paging.pagingSlc, null, 'Paging drop-down element');
deepEqual(paging.resultsPerPageSlc, null, 'Paging drop-down element');
deepEqual(paging.pageSlc, null, 'Paging drop-down element');
deepEqual(paging.pageLengthSlc, null, 'Paging drop-down element');
deepEqual(paging.btnNextCont, null, 'Next button container element');
deepEqual(paging.btnPrevCont, null, 'Previous button container element');
deepEqual(paging.btnLastCont, null, 'Last button container element');
@ -83,7 +84,7 @@ test('Destroy Paging component', function() {
test('Reset Paging component', function() {
paging.reset();
paging.setPage(2);
notEqual(paging.pagingSlc, null, 'Paging drop-down element');
notEqual(paging.pageSlc, null, 'Paging drop-down element');
});
module('Behaviour');
@ -92,7 +93,7 @@ test('Set page', function() {
deepEqual(paging.getPage(), 1, 'Expected page number');
paging.setPage(3);
deepEqual(paging.getPage(), 3, 'Expected page number');
deepEqual(paging.pagingSlc.selectedIndex, 2,
deepEqual(paging.pageSlc.selectedIndex, 2,
'Expected page number in paging drop-down selector');
});
@ -121,8 +122,8 @@ test('Can set page with command', function() {
});
test('Set page via drop-down page selector', function() {
paging.pagingSlc.selectedIndex = 3;
paging.changePage(paging.pagingSlc.selectedIndex);
paging.pageSlc.selectedIndex = 3;
paging.changePage(paging.pageSlc.selectedIndex);
deepEqual(paging.getPage(), 4, 'Expected page number');
});
@ -145,10 +146,10 @@ test('Filter with dummy value', function() {
test('Set results per page', function() {
tf.clearFilters();
paging.changeResultsPerPage('4');
deepEqual(paging.pagingLength, 4, 'Expected page length');
deepEqual(paging.pageLength, 4, 'Expected page length');
deepEqual(paging.nbPages, 2, 'Expected number of pages');
paging.changeResultsPerPage('6');
deepEqual(paging.pagingLength, 6, 'Expected page length');
deepEqual(paging.pageLength, 6, 'Expected page length');
deepEqual(paging.nbPages, 2, 'Expected number of pages');
});
@ -159,16 +160,17 @@ test('Grid layout with paging', function() {
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
grid_layout: true,
paging: true,
paging_length: 2,
results_per_page: ['Results per page ', [2,4,6]]
paging: {
length: 2,
results_per_page: ['Results per page ', [2, 4, 6]]
}
});
tf.init();
paging = tf.feature('paging');
notEqual(paging.pagingSlc, null, 'Paging drop-down element');
notEqual(paging.resultsPerPageSlc, null,
notEqual(paging.pageSlc, null, 'Paging drop-down element');
notEqual(paging.pageLengthSlc, null,
'Number of results per page drop-down element');
notEqual(paging.btnNextCont, null, 'Next button container element');
notEqual(paging.btnPrevCont, null, 'Previous button container element');
@ -209,8 +211,8 @@ test('Can set page with command', function() {
});
test('Set page via drop-down page selector', function() {
paging.pagingSlc.selectedIndex = 3;
paging.changePage(paging.pagingSlc.selectedIndex);
paging.pageSlc.selectedIndex = 3;
paging.changePage(paging.pageSlc.selectedIndex);
deepEqual(paging.getPage(), 4, 'Expected page number');
});
@ -233,10 +235,10 @@ test('Filter with dummy value', function() {
test('Set results per page', function() {
tf.clearFilters();
paging.changeResultsPerPage('4');
deepEqual(paging.pagingLength, 4, 'Expected page length');
deepEqual(paging.pageLength, 4, 'Expected page length');
deepEqual(paging.nbPages, 2, 'Expected number of pages');
paging.changeResultsPerPage('6');
deepEqual(paging.pagingLength, 6, 'Expected page length');
deepEqual(paging.pageLength, 6, 'Expected page length');
deepEqual(paging.nbPages, 2, 'Expected number of pages');
});
@ -251,7 +253,7 @@ test('Set results per page when no valid rows', function() {
paging.changeResultsPerPage('4');
// assert
deepEqual(paging.resultsPerPageSlc.value, '4', 'Select page length option');
deepEqual(paging.pageLengthSlc.value, '4', 'Select page length option');
deepEqual(paging.getPage(), 1, 'Expected page number');
});
@ -260,7 +262,7 @@ test('can destroy and init TableFilter', function() {
tf.destroy();
tf.init();
notEqual(paging, null, 'Paging instanciated');
deepEqual(paging.pagingLength, 2, 'Paging length');
deepEqual(paging.pageLength, 2, 'Paging length');
deepEqual(paging.nbPages, 4, 'Number of pages');
});

View file

@ -33,6 +33,8 @@ test('Pop-up filter component', function() {
'By Air (hrs)',
'Expected header text for multiple filter type'
);
deepEqual(tf.dom().rows[tf.headersRow-1].style.display, 'none',
'Extra row hidden');
});
module('UI elements');
@ -156,7 +158,7 @@ test('Pop-up filter auto-closes when user clicks away', function() {
// act
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent('mouseup', true, true);
tf.tbl.rows[4].cells[2].dispatchEvent(evObj);
tf.dom().rows[4].cells[2].dispatchEvent(evObj);
// assert
deepEqual(popupFilter.isOpen(0), false,
@ -164,6 +166,19 @@ test('Pop-up filter auto-closes when user clicks away', function() {
);
});
test('Can close all popup filters', function() {
// setup
popupFilter.open(0);
// act
popupFilter.closeAll();
// assert
deepEqual(popupFilter.isOpen(0), false,
'Pop-up filter closed after closeAll'
);
});
test('Can destroy and reset', function(){
// setup
popupFilter.destroy();
@ -191,6 +206,38 @@ test('TableFilter re-initialised', function() {
deepEqual(id(tf.fltIds[3]).nodeName, 'SELECT', 'Filter exists');
});
module('Properties');
test('Can set icon HTML', function() {
// setup
tf.destroy();
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
col_2: 'multiple',
col_3: 'select',
col_4: 'none',
popup_filters: {
image_html: '<span>hello world</span>'
}
});
tf.init();
var feature = tf.feature('popupFilter');
feature.filtersCache = [];
feature.fltElms = [];
// act
tf.init();
var headersRow = tf.dom().rows[tf.getHeadersRowIndex()];
// assert
deepEqual(
headersRow.cells[1].innerHTML
.indexOf('<span>hello world</span>') !== -1,
true,
'Custom HTML element present'
);
});
module('Grid-layout');
test('Re-instantiated with grid-layout', function() {
tf.destroy();
@ -287,6 +334,46 @@ test('Properties', function() {
'function', 'Feature enable method');
});
module('Overrides');
test('Configuration settings overrides', function() {
// setup
tf.destroy();
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
popup_filters: true,
filters_row_index: 1
});
// assert
deepEqual(tf.filtersRowIndex, 1, 'Filters row index config setting value');
deepEqual(
tf.externalFltTgtIds,
[],
'External filters container ids config setting value'
);
deepEqual(tf.headersRow, 0, 'Headers row index config setting value');
test('Overrides after init', function() {
// act
tf.init();
// assert
deepEqual(tf.filtersRowIndex, 0, 'Filters row index override');
deepEqual(
tf.externalFltTgtIds,
[
'popup_demo_0',
'popup_demo_1',
'popup_demo_2',
'popup_demo_3',
'popup_demo_4'
],
'External filters container ids config setting value'
);
deepEqual(tf.headersRow, 1, 'Headers row index override');
});
});
module('Tear-down');
test('TableFilter removed', function() {
tf.destroy();

View file

@ -0,0 +1,104 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TableFilter pop-up filters with grouped headers</title>
<link rel="stylesheet" href="libs/qunit/qunit.css">
<script src="libs/qunit/qunit.js"></script>
<script src="libs/polyfill.js"></script>
</head>
<body>
<p>
Tests for <a href="https://jsfiddle.net/wLexc6pt/6/">
https://jsfiddle.net/wLexc6pt/6/</a> fiddle
</p>
<table id="demo">
<thead>
<tr>
<th colspan="3">Colspan Header</th>
<th colspan="4">Colspan Header</th>
</tr>
<tr>
<th>SubHeader</th>
<th>SubHeader</th>
<th>SubHeader</th>
<th>SubHeader</th>
<th>SubHeader</th>
<th>SubHeader</th>
<th>SubHeader</th>
</tr>
</thead>
<tbody>
<tr>
<td>Value</td>
<td>Value</td>
<td>Value</td>
<td>Filter Value 1</td>
<td>Filter Value 1</td>
<td>Filter Value 1</td>
<td>Filter Value 1</td>
</tr>
<tr>
<td>Value</td>
<td>Value</td>
<td>Value</td>
<td>Filter Value 1</td>
<td>Filter Value 1</td>
<td>Filter Value 1</td>
<td>Filter Value 1</td>
</tr>
<tr>
<td>Value</td>
<td>Value</td>
<td>Value</td>
<td>Filter Value 2</td>
<td>Filter Value 2</td>
<td>Filter Value 2</td>
<td>Filter Value 2</td>
</tr>
<tr>
<td>Value</td>
<td>Value</td>
<td>Value</td>
<td>Filter Value 3</td>
<td>Filter Value 3</td>
<td>Filter Value 3</td>
<td>Filter Value 3</td>
</tr>
<tr>
<td>Value</td>
<td>Value</td>
<td>Value</td>
<td>Filter Value 3</td>
<td>Filter Value 3</td>
<td>Filter Value 3</td>
<td>Filter Value 3</td>
</tr>
<tr>
<td>Value</td>
<td>Value</td>
<td>Value</td>
<td>Filter Value 4</td>
<td>Filter Value 4</td>
<td>Filter Value 4</td>
<td>Filter Value 4</td>
</tr>
<tr>
<td>Value</td>
<td>Value</td>
<td>Value</td>
<td>Filter Value 5</td>
<td>Filter Value 5</td>
<td>Filter Value 5</td>
<td>Filter Value 5</td>
</tr>
</tbody>
</table>
<script src="../dist/tablefilter/tablefilter.js"></script>
<script src="test-popup-filters-grouped-headers.js"></script>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
</body>
</html>

View file

@ -0,0 +1,206 @@
var id = function (id){ return document.getElementById(id); };
var _tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
col_0: 'none',
col_1: 'none',
col_2: 'none',
col_3: 'checklist',
col_4: 'checklist',
col_5: 'checklist',
col_6: 'checklist',
headers_row_index: 1,
popup_filters: true,
mark_active_columns: true
}, 2);
_tf.init();
var popupFilter = _tf.feature('popupFilter');
module('Sanity checks');
test('Pop-up filter component', function() {
notEqual(popupFilter, null, 'PopupFilter instanciated');
deepEqual(popupFilter.fltElms instanceof Array,
true, 'Type of fltElms property');
deepEqual(
popupFilter.adjustToContainer,
true,
'Popup filter width adjusts to container'
);
deepEqual(_tf.headersRow, 2, 'Headers row index');
});
module('UI elements');
test('Pop-up filter UI elements', function() {
var flt3 = popupFilter.fltElms[3];
var flt4 = popupFilter.fltElms[4];
var fltIcn3 = popupFilter.fltIcons[3];
var fltIcn4 = popupFilter.fltIcons[4];
var fltIcn0 = popupFilter.fltIcons[0];
var fltIcn1 = popupFilter.fltIcons[0];
notEqual(flt3, null, 'Filter element exists');
notEqual(flt4, null, 'Filter element exists');
deepEqual(fltIcn3.nodeName, 'IMG', 'Filter icon exists');
deepEqual(fltIcn4.nodeName, 'IMG', 'Filter icon exists');
deepEqual(fltIcn0, undefined, 'Filter icon does not exist for column 0');
deepEqual(fltIcn1, undefined, 'Filter icon does not exist for column 1');
});
test('Pop-up filter state after filtering', function(){
var fltIcn4 = popupFilter.fltIcons[4];
_tf.setFilterValue(4, 'Filter Value 4');
_tf.filter();
deepEqual(fltIcn4.src.indexOf('icn_filterActive') !== -1,
true, 'Icon state');
});
test('Pop-up filter state after clearing', function(){
var fltIcn3 = popupFilter.fltIcons[3];
var fltIcn4 = popupFilter.fltIcons[4];
var fltIcn5 = popupFilter.fltIcons[5];
var fltIcn6 = popupFilter.fltIcons[6];
_tf.clearFilters();
deepEqual(fltIcn3.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
deepEqual(fltIcn4.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
deepEqual(fltIcn5.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
deepEqual(fltIcn6.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
});
test('Can open pop-up filter', function(){
// act
popupFilter.open(5);
// assert
deepEqual(popupFilter.isOpen(5), true,
'Popup filter is open');
});
test('Can close pop-up filter', function(){
// act
popupFilter.close(5);
// assert
deepEqual(popupFilter.isOpen(5), false,
'Popup filter is open');
});
test('Can toggle pop-up filter (initially closed)', function(){
// setup
popupFilter.close(6);
// act
popupFilter.toggle(6);
// assert
deepEqual(popupFilter.isOpen(6), true,
'Popup filter is toggled');
});
test('Can toggle pop-up filter (initially opened)', function(){
// setup
popupFilter.open(6);
// act
popupFilter.toggle(6);
// assert
deepEqual(popupFilter.isOpen(6), false,
'Popup filter is toggled');
});
test('Checklist pop-up filter remains open upon filtering', function(){
// setup
popupFilter.open(4);
// act
_tf.setFilterValue(4, ['Filter Value 4']);
_tf.filter();
// assert
deepEqual(
popupFilter.isOpen(4),
true,
'Checklist pop-up filter still open after filtering'
);
});
test('Pop-up filter auto-closes when user clicks away', function() {
// setup
popupFilter.open(5);
// act
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent('mouseup', true, true);
_tf.dom().rows[4].cells[2].dispatchEvent(evObj);
// assert
deepEqual(popupFilter.isOpen(5), false,
'Pop-up filter closed after user clicks away'
);
});
test('Can close all popup filters', function() {
// setup
popupFilter.open(3);
// act
popupFilter.closeAll(4);
// assert
deepEqual(popupFilter.isOpen(3), false,
'Pop-up filter closed after closeAll'
);
});
test('Does not close popup filter if closeOnFiltering false', function() {
// setup
popupFilter.closeOnFiltering = false;
popupFilter.open(4);
// act
popupFilter.close(4);
// assert
deepEqual(popupFilter.isOpen(4), false,
'Pop-up filter closed after closeAll'
);
});
// TODO: fix reset popupFilter component with grouped headers
// test('Can destroy and reset', function(){
// // setup
// _tf.clearFilters();
// _tf.filter();
// popupFilter.destroy();
// // act
// popupFilter.reset();
// // assert
// deepEqual(popupFilter.fltElms.length, 7, 'Filters are generated');
// deepEqual(popupFilter.fltIcons.length, 4, 'Icons are generated');
// deepEqual(popupFilter.fltSpans.length, 4,
// 'Icon containers are generated');
// });
test('TableFilter removed', function() {
_tf.destroy();
var fltIcn1 = popupFilter.fltIcons[3];
deepEqual(fltIcn1, undefined, 'Filter icon is removed');
deepEqual(id(_tf.fltIds[3]), null, 'Filter is removed');
});
// test('TableFilter re-initialised', function() {
// _tf.init();
// var fltIcn1 = popupFilter.fltIcons[3];
// deepEqual(fltIcn1.nodeName, 'IMG', 'Filter icon exists');
// deepEqual(_tf.getFilterType(3), 'checklist', 'Filter type');
// });

View file

@ -80,13 +80,18 @@ test('RowsCounter component with paging', function() {
tf = null;
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
rows_counter: true,
paging: true,
paging_length: 3
rows_counter: {
text: 'Records: ',
separator: '~',
over_text: ' \\ '
},
paging: {
length: 3
}
});
tf.init();
equal(tf.feature('rowsCounter').label.innerHTML,
'1-3 / 7', 'Counter value with paging');
'1~3 \\ 7', 'Counter value with paging');
});
test('Can calculate page on page change', function() {
//setup
@ -97,7 +102,7 @@ test('Can calculate page on page change', function() {
//assert
equal(tf.feature('rowsCounter').label.innerHTML,
'4-6 / 7', 'Counter value with paging');
'4~6 \\ 7', 'Counter value with paging');
});
module('Tear-down');

View file

@ -27,7 +27,6 @@ test('Sanity checks', function() {
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
single_filter: true,
external_flt_grid: true,
external_flt_grid_ids: ['single-search']
});
tf.init();

View file

@ -47,7 +47,7 @@ function startTest(tf, sort){
deepEqual(indicator.length, 1, 'Sort indicator in header element');
deepEqual(
(tf.tbl.rows[validRows[0]].cells[1]).innerHTML,
(tf.dom().rows[validRows[0]].cells[1]).innerHTML,
'AUY78',
'First custom key cell text before sorting');
});
@ -58,7 +58,7 @@ function startTest(tf, sort){
deepEqual(sort.sorted, true, 'Table column sorted');
deepEqual(
(tf.tbl.rows[validRows[0]].cells[1]).innerHTML,
(tf.dom().rows[validRows[0]].cells[1]).innerHTML,
'QT1',
'First custom key cell text after sorting');
});

View file

@ -39,7 +39,7 @@ function start(tf, sort){
deepEqual(indicator.length, 1, 'Sort indicator in header element');
deepEqual(
(tf.tbl.rows[validRows[0]].cells[1]).innerHTML,
(tf.dom().rows[validRows[0]].cells[1]).innerHTML,
'AUY78',
'First custom key cell text before sorting');
});
@ -50,7 +50,7 @@ function start(tf, sort){
deepEqual(sort.sorted, true, 'Table column sorted');
deepEqual(
(tf.tbl.rows[validRows[0]].cells[1]).innerHTML,
(tf.dom().rows[validRows[0]].cells[1]).innerHTML,
'QT1',
'First custom key cell text after sorting');
});

View file

@ -7,8 +7,9 @@ var tf = new TableFilter('demo', {
page_number: true,
page_length: true
},
paging: true,
results_per_page: ['Records: ', [2, 4, 6]],
paging: {
results_per_page: ['Records: ', [2, 4, 6]]
}
});
tf.init();
var state = tf.feature('state');

Some files were not shown because too many files have changed in this diff Show more