1
0
Fork 0
mirror of https://github.com/koalyptus/TableFilter.git synced 2024-04-30 13:52:53 +02:00

Merge pull request #108 from koalyptus/pub-sub-refactoring

Pub sub refactoring
This commit is contained in:
koalyptus 2016-01-27 22:10:20 +11:00
commit 8335d35c39
59 changed files with 2136 additions and 1352 deletions

View file

@ -11,7 +11,7 @@
"trailing": true,
"quotmark": "single",
"immed": true,
"maxstatements": 198,
"maxstatements": 172,
"maxdepth": 7,
"maxcomplexity": 104
"maxcomplexity": 85
}

View file

@ -34,6 +34,10 @@ git clone --bare https://github.com/koalyptus/TableFilter.git
```shell
npm install tablefilter --save
```
* or get the future features from the ``next`` release channel:
```shell
npm install tablefilter@next --save
```
## Setup
Copy the ``tablefilter`` directory under ``dist`` and place it at desired location in your project. Then include the main js file in your page:

4
dist/starter.html vendored
View file

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

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.0.23 by Max Guglielmi
* build date: 2016-01-15T07:08:13.103Z
* tablefilter v0.1.9 by Max Guglielmi
* build date: 2016-01-27T10:49:29.388Z
* 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.0.23 by Max Guglielmi
* build date: 2016-01-15T07:08:13.103Z
* tablefilter v0.1.9 by Max Guglielmi
* build date: 2016-01-27T10:49:29.388Z
* 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.0.23 by Max Guglielmi
* build date: 2016-01-15T07:08:13.103Z
* tablefilter v0.1.9 by Max Guglielmi
* build date: 2016-01-27T10:49:29.388Z
* MIT License
*/
.activeHeader{background-color:#66afe9 !important;color:#fff !important}

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.0.23 by Max Guglielmi
* build date: 2016-01-15T07:08:13.103Z
* tablefilter v0.1.9 by Max Guglielmi
* build date: 2016-01-27T10:49:29.388Z
* MIT License
*/
table.TF{border-left:1px solid #ccc !important;border-top:none !important;border-right:none !important;border-bottom:none !important;}table.TF th{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;color:#333 !important}table.TF td{border-bottom:1px dotted #999 !important;padding:5px !important}.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}

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.0.23 by Max Guglielmi
* build date: 2016-01-15T07:08:13.103Z
* tablefilter v0.1.9 by Max Guglielmi
* build date: 2016-01-27T10:49:29.388Z
* MIT License
*/
table.TF{border-left:1px dotted #81963b !important;border-top:none !important;border-right:0 !important;border-bottom:none !important;}table.TF th{background:#39424b url("images/bg_headers.jpg") left top repeat-x !important;border-bottom:0 !important;border-right:1px dotted #d0d0d0 !important;border-left:0 !important;border-top:0 !important;color:#fff !important}table.TF td{border-bottom:1px dotted #81963b;border-right:1px dotted #81963b;padding:5px !important}.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}

View file

@ -1,6 +1,6 @@
/**
* tablefilter v0.0.23 by Max Guglielmi
* build date: 2016-01-15T07:08:13.103Z
* tablefilter v0.1.9 by Max Guglielmi
* build date: 2016-01-27T10:49:29.388Z
* 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}

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.0.23",
"version": "0.1.9",
"description": "A Javascript library making HTML tables filterable and a bit more",
"license": "MIT",
"author": {
@ -24,6 +24,9 @@
"scripts": {
"test": "grunt test"
},
"publishConfig": {
"tag": "next"
},
"devDependencies": {
"babel-core": "^6.1.2",
"babel-loader": "^6.0.1",

50
src/emitter.js Normal file
View file

@ -0,0 +1,50 @@
/**
* Event emitter class
*/
export class Emitter {
constructor() {
/**
* Events object
* @type {Object}
*/
this.events = {};
}
/**
* Subscribe to an event
* @param {Array} evts Collection of event names
* @param {Function} fn Function invoked when event is emitted
*/
on(evts, fn) {
evts.forEach((evt)=> {
this.events[evt] = this.events[evt] || [];
this.events[evt].push(fn);
});
}
/**
* Unsubscribe to an event
* @param {Array} evts Collection of event names
* @param {Function} fn Function invoked when event is emitted
*/
off(evts, fn) {
evts.forEach((evt)=> {
if(evt in this.events) {
this.events[evt].splice(this.events[evt].indexOf(fn), 1);
}
});
}
/**
* Emit an event
* @param {String} evt Event name followed by any other argument passed to
* the invoked function
*/
emit(evt /*, args...*/) {
if(evt in this.events) {
for(let i = 0; i < this.events[evt].length; i++) {
this.events[evt][i].apply(this, [].slice.call(arguments, 1));
}
}
}
}

View file

@ -26,6 +26,7 @@ export default class AdapterEzEditTable {
this._ezEditTable = null;
this.cfg = cfg;
this.tf = tf;
this.emitter = tf.emitter;
}
/**
@ -43,6 +44,11 @@ export default class AdapterEzEditTable {
if(this.loadStylesheet && !tf.isImported(this.stylesheet, 'link')){
tf.import(this.stylesheetName, this.stylesheet, null, 'link');
}
// TODO: hack to prevent ezEditTable enter key event hijaking.
// Needs to be fixed in the vendor's library
this.emitter.on(['filter-focus', 'filter-blur'],
()=> this._toggleForInputFilter());
}
/**
@ -293,7 +299,8 @@ export default class AdapterEzEditTable {
cfg.on_added_dom_row = function(){
tf.nbFilterableRows++;
if(!tf.paging){
tf.feature('rowsCounter').refresh();
tf.emitter.emit('rows-changed', tf, this);
//tf.feature('rowsCounter').refresh();
} else {
tf.nbRows++;
tf.nbVisibleRows++;
@ -314,7 +321,8 @@ export default class AdapterEzEditTable {
cfg.actions['delete'].on_after_submit = function(){
tf.nbFilterableRows--;
if(!tf.paging){
tf.feature('rowsCounter').refresh();
// tf.feature('rowsCounter').refresh();
tf.emitter.emit('rows-changed', tf, this);
} else {
tf.nbRows--;
tf.nbVisibleRows--;
@ -356,6 +364,35 @@ export default class AdapterEzEditTable {
}
}
/**
* Toggle behaviour
*/
toggle(){
var ezEditTable = this._ezEditTable;
if(ezEditTable.editable){
ezEditTable.Editable.Remove();
} else {
ezEditTable.Editable.Set();
}
if(ezEditTable.selection){
ezEditTable.Selection.Remove();
} else {
ezEditTable.Selection.Set();
}
}
_toggleForInputFilter(){
var tf = this.tf;
if(!tf.activeFlt){
return;
}
var colIndex = tf.activeFlt.getAttribute('ct');
var filterType = tf.getFilterType(colIndex);
if(filterType === tf.fltTypeInp){
this.toggle();
}
}
/**
* Remove advanced grid
*/
@ -370,6 +407,9 @@ export default class AdapterEzEditTable {
ezEditTable.Editable.Remove();
}
}
this.emitter.off(['filter-focus', 'filter-blur'],
()=> this._toggleForInputFilter());
this.initialized = false;
}
}

View file

@ -22,6 +22,9 @@ export default class ColOps{
}
init(){
// subscribe to events
this.tf.emitter.on(['after-filtering'], ()=> this.calc());
this.calc();
}
@ -43,7 +46,7 @@ export default class ColOps{
*/
calc() {
var tf = this.tf;
if(!tf.isFirstLoad && !tf.hasGrid()){
if(!tf.hasGrid()){
return;
}
@ -310,6 +313,9 @@ export default class ColOps{
}
}
destroy(){}
destroy(){
// unsubscribe to events
this.tf.emitter.off(['after-filtering'], ()=> this.calc());
}
}

View file

@ -46,6 +46,7 @@ export default class AdapterSortableTable{
opts.on_after_sort : null;
this.tf = tf;
this.emitter = tf.emitter;
}
init(){
@ -85,42 +86,6 @@ export default class AdapterSortableTable{
this.stt.onsort = function(){
adpt.sorted = true;
//rows alternating bg issue
// TODO: move into AlternateRows component
if(tf.alternateRows){
let rows = tf.tbl.rows, c = 0;
let setClass = function(row, i, removeOnly){
if(Types.isUndef(removeOnly)){
removeOnly = false;
}
let altRows = tf.feature('alternateRows'),
oddCls = altRows.oddCss,
evenCls = altRows.evenCss;
Dom.removeClass(row, oddCls);
Dom.removeClass(row, evenCls);
if(!removeOnly){
Dom.addClass(row, i % 2 ? oddCls : evenCls);
}
};
for (let i = tf.refRow; i < tf.nbRows; i++){
let isRowValid = rows[i].getAttribute('validRow');
if(tf.paging && rows[i].style.display === ''){
setClass(rows[i], c);
c++;
} else {
if((isRowValid==='true' || isRowValid===null) &&
rows[i].style.display === ''){
setClass(rows[i], c);
c++;
} else {
setClass(rows[i], c, true);
}
}
}
}
//sort behaviour for paging
if(tf.paging){
let paginator = tf.feature('paging');
@ -133,6 +98,8 @@ export default class AdapterSortableTable{
if(adpt.onAfterSort){
adpt.onAfterSort.call(null, tf, adpt.stt.sortColumn);
}
adpt.emitter.emit('column-sorted', tf, adpt.stt.sortColumn);
};
this.initialized = true;

View file

@ -25,9 +25,24 @@ export class AlternateRows extends Feature {
return;
}
this.processAll();
// Subscribe to events
this.emitter.on(['row-processed', 'row-paged'],
(tf, rowIndex, arrIndex, isValid)=>
this.processRow(rowIndex, arrIndex, isValid));
this.emitter.on(['column-sorted'], ()=> this.processAll());
this.initialized = true;
}
processAll() {
if(!this.isEnabled()){
return;
}
var tf = this.tf;
var validRowsIndex = tf.validRowsIndex;
var noValidRowsIndex = validRowsIndex===null;
var validRowsIndex = tf.getValidRows(true);
var noValidRowsIndex = validRowsIndex.length === 0;
//1st index
var beginIndex = noValidRowsIndex ? tf.refRow : 0;
// nb indexes
@ -42,7 +57,19 @@ export class AlternateRows extends Feature {
this.setRowBg(rowIdx, idx);
idx++;
}
this.initialized = true;
}
/**
* Set/remove row background based on row validation
* @param {Number} rowIdx Row index
* @param {Boolean} isValid Valid row flag
*/
processRow(rowIdx, arrIdx, isValid) {
if(isValid){
this.setRowBg(rowIdx, arrIdx);
} else {
this.removeRowBg(rowIdx);
}
}
/**
@ -85,9 +112,16 @@ export class AlternateRows extends Feature {
if(!this.initialized){
return;
}
for(var i=this.tf.refRow; i<this.tf.nbRows; i++){
for(var i=0; i<this.tf.nbRows; i++){
this.removeRowBg(i);
}
// Unsubscribe to events
this.emitter.off(['row-processed', 'row-paged'],
(tf, rowIndex, arrIndex, isValid)=>
this.processRow(rowIndex, arrIndex, isValid));
this.emitter.off(['column-sorted'], ()=> this.processAll());
this.initialized = false;
}

View file

@ -1,18 +1,21 @@
import {Feature} from './feature';
import Dom from '../dom';
import Arr from '../array';
import Str from '../string';
import Sort from '../sort';
import Event from '../event';
export class CheckList{
export class CheckList extends Feature{
/**
* Checklist UI component
* @param {Object} tf TableFilter instance
*/
constructor(tf){
super(tf, 'checkList');
// Configuration object
var f = tf.config();
let f = tf.config();
this.checkListDiv = []; //checklist container div
//defines css class for div containing checklist filter
@ -42,16 +45,14 @@ export class CheckList{
this.opts = null;
this.optsTxt = null;
this.excludedOpts = null;
this.tf = tf;
}
// TODO: move event here
onChange(evt){
let elm = evt.target;
this.tf.activeFilterId = elm.getAttribute('id');
this.tf.activeFlt = Dom.id(this.tf.activeFilterId);
this.tf.Evt.onSlcChange.call(this.tf, evt);
let tf = this.tf;
tf.activeFilterId = elm.getAttribute('id');
tf.activeFlt = Dom.id(tf.activeFilterId);
tf.filter();
}
optionClick(evt){
@ -59,18 +60,61 @@ export class CheckList{
this.onChange(evt);
}
onCheckListClick(evt){
let elm = Event.target(evt);
if(this.tf.loadFltOnDemand && elm.getAttribute('filled') === '0'){
let ct = elm.getAttribute('ct');
let div = this.checkListDiv[ct];
this.build(ct);
Event.remove(div, 'click', (evt)=> this.onCheckListClick(evt));
}
}
/**
* Build checklist UI asynchronously
* @param {Number} colIndex Column index
* @param {Boolean} isExternal Render in external container
* @param {String} extFltId External container id
* Initialize checklist filter
* @param {Number} colIndex Column index
* @param {Boolean} isExternal External filter flag
* @param {DOMElement} container Dom element containing the filter
*/
build(colIndex, isExternal, extFltId){
var tf = this.tf;
tf.EvtManager(
tf.Evt.name.checklist,
{ slcIndex:colIndex, slcExternal:isExternal, slcId:extFltId }
init(colIndex, isExternal, container){
let tf = this.tf;
let externalFltTgtId = isExternal ?
tf.externalFltTgtIds[colIndex] : null;
let divCont = Dom.create('div',
['id', this.prfxCheckListDiv+colIndex+'_'+tf.id],
['ct', colIndex], ['filled', '0']);
divCont.className = this.checkListDivCssClass;
//filter is appended in desired element
if(externalFltTgtId){
Dom.id(externalFltTgtId).appendChild(divCont);
tf.externalFltEls.push(divCont);
} else {
container.appendChild(divCont);
}
this.checkListDiv[colIndex] = divCont;
tf.fltIds.push(tf.prfxFlt+colIndex+'_'+tf.id);
if(!tf.loadFltOnDemand){
this.build(colIndex);
} else {
Event.add(divCont, 'click', (evt)=> this.onCheckListClick(evt));
divCont.appendChild(Dom.text(this.activateCheckListTxt));
}
this.emitter.on(
['build-checklist-filter'],
(tf, colIndex, isExternal)=> this.build(colIndex, isExternal)
);
this.emitter.on(
['select-checklist-options'],
(tf, colIndex, values)=> this.selectOptions(colIndex, values)
);
this.initialized = true;
}
/**
@ -79,48 +123,50 @@ export class CheckList{
* @param {Boolean} isExternal Render in external container
* @param {String} extFltId External container id
*/
_build(colIndex, isExternal=false, extFltId=null){
var tf = this.tf;
build(colIndex, isExternal=false, extFltId=null){
let tf = this.tf;
colIndex = parseInt(colIndex, 10);
this.emitter.emit('before-populating-filter', tf, colIndex);
this.opts = [];
this.optsTxt = [];
var divFltId = this.prfxCheckListDiv+colIndex+'_'+tf.id;
let divFltId = this.prfxCheckListDiv+colIndex+'_'+tf.id;
if((!Dom.id(divFltId) && !isExternal) ||
(!Dom.id(extFltId) && isExternal)){
return;
}
var flt = !isExternal ? this.checkListDiv[colIndex] : Dom.id(extFltId);
var ul = Dom.create(
let flt = !isExternal ? this.checkListDiv[colIndex] : Dom.id(extFltId);
let ul = Dom.create(
'ul', ['id', tf.fltIds[colIndex]], ['colIndex', colIndex]);
ul.className = this.checkListCssClass;
Event.add(ul, 'change', (evt) => { this.onChange(evt); });
Event.add(ul, 'change', (evt)=> this.onChange(evt));
var rows = tf.tbl.rows;
let rows = tf.tbl.rows;
this.isCustom = tf.isCustomOptions(colIndex);
var activeFlt;
let activeFlt;
if(tf.linkedFilters && tf.activeFilterId){
activeFlt = tf.activeFilterId.split('_')[0];
activeFlt = activeFlt.split(tf.prfxFlt)[1];
}
var filteredDataCol = [];
let filteredDataCol = [];
if(tf.linkedFilters && tf.disableExcludedOptions){
this.excludedOpts = [];
}
for(var k=tf.refRow; k<tf.nbRows; k++){
for(let k=tf.refRow; k<tf.nbRows; k++){
// always visible rows don't need to appear on selects as always
// valid
if(tf.hasVisibleRows && tf.visibleRows.indexOf(k) !== -1){
continue;
}
var cells = rows[k].cells;
var ncells = cells.length;
let cells = rows[k].cells;
let ncells = cells.length;
// checks if row has exact cell #
if(ncells !== tf.nbCells || this.isCustom){
@ -128,7 +174,7 @@ export class CheckList{
}
// this loop retrieves cell data
for(var j=0; j<ncells; j++){
for(let j=0; j<ncells; j++){
// WTF: cyclomatic complexity hell :)
if((colIndex===j && (!tf.linkedFilters ||
(tf.linkedFilters && tf.disableExcludedOptions)))||
@ -137,22 +183,21 @@ export class CheckList{
(tf.paging && ((!activeFlt || activeFlt===colIndex )||
(activeFlt!=colIndex &&
tf.validRowsIndex.indexOf(k) != -1)) )))){
var cell_data = tf.getCellData(cells[j]);
let cell_data = tf.getCellData(cells[j]);
//Vary Peter's patch
var cell_string = Str.matchCase(cell_data, tf.matchCase);
let cell_string = Str.matchCase(cell_data, tf.matchCase);
// checks if celldata is already in array
if(!Arr.has(this.opts, cell_string, tf.matchCase)){
this.opts.push(cell_data);
}
var filteredCol = filteredDataCol[j];
let filteredCol = filteredDataCol[j];
if(tf.linkedFilters && tf.disableExcludedOptions){
if(!filteredCol){
filteredCol = tf.getFilteredDataCol(j);
}
if(!Arr.has(filteredCol, cell_string, tf.matchCase) &&
!Arr.has(this.excludedOpts,
cell_string, tf.matchCase) &&
!tf.isFirstLoad){
cell_string, tf.matchCase)){
this.excludedOpts.push(cell_data);
}
}
@ -162,7 +207,7 @@ export class CheckList{
//Retrieves custom values
if(this.isCustom){
var customValues = tf.getCustomOptions(colIndex);
let customValues = tf.getCustomOptions(colIndex);
this.opts = customValues[0];
this.optsTxt = customValues[1];
}
@ -220,13 +265,15 @@ export class CheckList{
}//in case there are alphanumeric values
}
this.addChecks(colIndex, ul, tf.separator);
this.addChecks(colIndex, ul);
if(tf.loadFltOnDemand){
flt.innerHTML = '';
}
flt.appendChild(ul);
flt.setAttribute('filled', '1');
this.emitter.emit('after-populating-filter', tf, colIndex, flt);
}
/**
@ -235,55 +282,30 @@ export class CheckList{
* @param {Object} ul Ul element
*/
addChecks(colIndex, ul){
var tf = this.tf;
var chkCt = this.addTChecks(colIndex, ul);
var fltArr = []; //remember grid values
var store = tf.feature('store');
var tmpVal = store ?
store.getFilterValues(tf.fltsValuesCookie)[colIndex] : null;
if(tmpVal && Str.trim(tmpVal).length > 0){
if(tf.hasCustomSlcOptions &&
tf.customSlcOptions.cols.indexOf(colIndex) != -1){
fltArr.push(tmpVal);
} else {
fltArr = tmpVal.split(' '+tf.orOperator+' ');
}
}
let tf = this.tf;
let chkCt = this.addTChecks(colIndex, ul);
for(var y=0; y<this.opts.length; y++){
var val = this.opts[y]; //item value
var lbl = this.isCustom ? this.optsTxt[y] : val; //item text
var li = Dom.createCheckItem(
for(let y=0; y<this.opts.length; y++){
let val = this.opts[y]; //item value
let lbl = this.isCustom ? this.optsTxt[y] : val; //item text
let li = Dom.createCheckItem(
tf.fltIds[colIndex]+'_'+(y+chkCt), val, lbl);
li.className = this.checkListItemCssClass;
if(tf.linkedFilters && tf.disableExcludedOptions &&
Arr.has(this.excludedOpts,
Str.matchCase(val, tf.matchCase), tf.matchCase)){
Dom.addClass(li, this.checkListItemDisabledCssClass);
li.check.disabled = true;
li.disabled = true;
Str.matchCase(val, tf.matchCase), tf.matchCase)){
Dom.addClass(li, this.checkListItemDisabledCssClass);
li.check.disabled = true;
li.disabled = true;
} else {
Event.add(li.check, 'click',
(evt) => { this.optionClick(evt); });
Event.add(li.check, 'click', (evt)=> this.optionClick(evt));
}
ul.appendChild(li);
if(val===''){
if(val === ''){
//item is hidden
li.style.display = 'none';
}
/*** remember grid values ***/
if(tf.rememberGridValues){
if((tf.hasCustomSlcOptions &&
tf.customSlcOptions.cols.indexOf(colIndex) != -1 &&
fltArr.toString().indexOf(val) != -1) ||
Arr.has(fltArr,
Str.matchCase(val, tf.matchCase), tf.matchCase)){
li.check.checked = true;
this.setCheckListValues(li.check);
}
}
}
}
@ -293,43 +315,37 @@ export class CheckList{
* @param {Object} ul Ul element
*/
addTChecks(colIndex, ul){
var tf = this.tf;
var chkCt = 1;
var li0 = Dom.createCheckItem(
let tf = this.tf;
let chkCt = 1;
let li0 = Dom.createCheckItem(
tf.fltIds[colIndex]+'_0', '', tf.displayAllText);
li0.className = this.checkListItemCssClass;
ul.appendChild(li0);
Event.add(li0.check, 'click', (evt) => {
this.optionClick(evt);
});
Event.add(li0.check, 'click', (evt)=> this.optionClick(evt));
if(!this.enableCheckListResetFilter){
li0.style.display = 'none';
}
if(tf.enableEmptyOption){
var li1 = Dom.createCheckItem(
let li1 = Dom.createCheckItem(
tf.fltIds[colIndex]+'_1', tf.emOperator, tf.emptyText);
li1.className = this.checkListItemCssClass;
ul.appendChild(li1);
Event.add(li1.check, 'click', (evt) => {
this.optionClick(evt);
});
Event.add(li1.check, 'click', (evt)=> this.optionClick(evt));
chkCt++;
}
if(tf.enableNonEmptyOption){
var li2 = Dom.createCheckItem(
let li2 = Dom.createCheckItem(
tf.fltIds[colIndex]+'_2',
tf.nmOperator,
tf.nonEmptyText
);
li2.className = this.checkListItemCssClass;
ul.appendChild(li2);
Event.add(li2.check, 'click', (evt) => {
this.optionClick(evt);
});
Event.add(li2.check, 'click', (evt)=> this.optionClick(evt));
chkCt++;
}
return chkCt;
@ -343,32 +359,32 @@ export class CheckList{
if(!o){
return;
}
var tf = this.tf;
var chkValue = o.value; //checked item value
var chkIndex = parseInt(o.id.split('_')[2], 10);
var filterTag = 'ul', itemTag = 'li';
var n = o;
let tf = this.tf;
let chkValue = o.value; //checked item value
let chkIndex = parseInt(o.id.split('_')[2], 10);
let filterTag = 'ul', itemTag = 'li';
let n = o;
//ul tag search
while(Str.lower(n.nodeName)!==filterTag){
n = n.parentNode;
}
var li = n.childNodes[chkIndex];
var colIndex = n.getAttribute('colIndex');
var fltValue = n.getAttribute('value'); //filter value (ul tag)
var fltIndexes = n.getAttribute('indexes'); //selected items (ul tag)
let li = n.childNodes[chkIndex];
let colIndex = n.getAttribute('colIndex');
let fltValue = n.getAttribute('value'); //filter value (ul tag)
let fltIndexes = n.getAttribute('indexes'); //selected items (ul tag)
if(o.checked){
//show all item
if(chkValue===''){
if((fltIndexes && fltIndexes!=='')){
//items indexes
var indSplit = fltIndexes.split(tf.separator);
let indSplit = fltIndexes.split(tf.separator);
//checked items loop
for(var u=0; u<indSplit.length; u++){
for(let u=0; u<indSplit.length; u++){
//checked item
var cChk = Dom.id(tf.fltIds[colIndex]+'_'+indSplit[u]);
let cChk = Dom.id(tf.fltIds[colIndex]+'_'+indSplit[u]);
if(cChk){
cChk.checked = false;
Dom.removeClass(
@ -386,7 +402,7 @@ export class CheckList{
chkValue = Str.trim(
fltValue+' '+chkValue+' '+tf.orOperator);
chkIndex = fltIndexes + chkIndex + tf.separator;
n.setAttribute('value', chkValue );
n.setAttribute('value', chkValue);
n.setAttribute('indexes', chkIndex);
//1st option unchecked
if(Dom.id(tf.fltIds[colIndex]+'_0')){
@ -401,12 +417,12 @@ export class CheckList{
}
} else { //removes values and indexes
if(chkValue!==''){
var replaceValue = new RegExp(
let replaceValue = new RegExp(
Str.rgxEsc(chkValue+' '+tf.orOperator));
fltValue = fltValue.replace(replaceValue,'');
n.setAttribute('value', Str.trim(fltValue));
var replaceIndex = new RegExp(
let replaceIndex = new RegExp(
Str.rgxEsc(chkIndex + tf.separator));
fltIndexes = fltIndexes.replace(replaceIndex, '');
n.setAttribute('indexes', fltIndexes);
@ -416,4 +432,49 @@ export class CheckList{
}
}
}
/**
* Select filter options programmatically
* @param {Number} colIndex Column index
* @param {Array} values Array of option values to select
*/
selectOptions(colIndex, values=[]){
let tf = this.tf;
if(tf.getFilterType(colIndex) !== tf.fltTypeCheckList ||
values.length === 0){
return;
}
let flt = tf.getFilterElement(colIndex);
let lisNb = Dom.tag(flt, 'li').length;
flt.setAttribute('value', '');
flt.setAttribute('indexes', '');
for(let k=0; k<lisNb; k++){
let li = Dom.tag(flt, 'li')[k],
lbl = Dom.tag(li, 'label')[0],
chk = Dom.tag(li, 'input')[0],
lblTxt = Str.matchCase(Dom.getText(lbl), tf.caseSensitive);
if(lblTxt !== '' && Arr.has(values, lblTxt, tf.caseSensitive)){
chk.checked = true;
this.setCheckListValues(chk);
}
else{
chk.checked = false;
this.setCheckListValues(chk);
}
}
}
destroy(){
this.emitter.off(
['build-checklist-filter'],
(tf, colIndex, isExternal)=> this.build(colIndex, isExternal)
);
this.emitter.off(
['select-checklist-options'],
(tf, colIndex, values)=> this.selectOptions(colIndex, values)
);
}
}

View file

@ -1,17 +1,21 @@
import {Feature} from './feature';
import Dom from '../dom';
import Arr from '../array';
import Str from '../string';
import Sort from '../sort';
import Event from '../event';
export class Dropdown{
export class Dropdown extends Feature{
/**
* Dropdown UI component
* @param {Object} tf TableFilter instance
*/
constructor(tf){
super(tf, 'dropdown');
// Configuration object
var f = tf.config();
let f = tf.config();
this.enableSlcResetFilter = f.enable_slc_reset_filter===false ?
false : true;
@ -30,51 +34,108 @@ export class Dropdown{
this.opts = null;
this.optsTxt = null;
this.slcInnerHtml = null;
}
this.tf = tf;
onSlcFocus(e) {
let elm = Event.target(e);
let tf = this.tf;
tf.activeFilterId = elm.getAttribute('id');
tf.activeFlt = Dom.id(tf.activeFilterId);
// select is populated when element has focus
if(tf.loadFltOnDemand && elm.getAttribute('filled') === '0'){
let ct = elm.getAttribute('ct');
this.build(ct);
}
this.emitter.emit('filter-focus', tf, this);
}
onSlcChange() {
if(this.tf.onSlcChange){
this.tf.filter();
}
}
/**
* Build drop-down filter UI asynchronously
* @param {Number} colIndex Column index
* @param {Boolean} isLinked Enable linked refresh behaviour
* @param {Boolean} isExternal Render in external container
* @param {String} extSlcId External container id
* Initialize drop-down filter
* @param {Number} colIndex Column index
* @param {Boolean} isExternal External filter flag
* @param {DOMElement} container Dom element containing the filter
*/
build(colIndex, isLinked, isExternal, extSlcId){
var tf = this.tf;
tf.EvtManager(
tf.Evt.name.dropdown,
{
slcIndex: colIndex,
slcRefreshed: isLinked,
slcExternal: isExternal,
slcId: extSlcId
}
init(colIndex, isExternal, container){
let tf = this.tf;
let col = tf.getFilterType(colIndex);
let externalFltTgtId = isExternal ?
tf.externalFltTgtIds[colIndex] : null;
let slc = Dom.create(tf.fltTypeSlc,
['id', tf.prfxFlt+colIndex+'_'+tf.id],
['ct', colIndex], ['filled', '0']
);
if(col === tf.fltTypeMulti){
slc.multiple = tf.fltTypeMulti;
slc.title = this.multipleSlcTooltip;
}
slc.className = Str.lower(col) === tf.fltTypeSlc ?
tf.fltCssClass : tf.fltMultiCssClass;
//filter is appended in container element
if(externalFltTgtId){
Dom.id(externalFltTgtId).appendChild(slc);
tf.externalFltEls.push(slc);
} else {
container.appendChild(slc);
}
tf.fltIds.push(slc.id);
if(!tf.loadFltOnDemand){
this.build(colIndex);
} else {
//1st option is created here since build isn't invoked
let opt0 = Dom.createOpt(tf.displayAllText, '');
slc.appendChild(opt0);
}
Event.add(slc, 'change', ()=> this.onSlcChange());
Event.add(slc, 'focus', (e)=> this.onSlcFocus(e));
this.emitter.on(
['build-select-filter'],
(tf, colIndex, isLinked, isExternal)=>
this.build(colIndex, isLinked, isExternal)
);
this.emitter.on(
['select-options'],
(tf, colIndex, values)=> this.selectOptions(colIndex, values)
);
this.initialized = true;
}
/**
* Build drop-down filter UI
* @param {Number} colIndex Column index
* @param {Boolean} isLinked Enable linked refresh behaviour
* @param {Boolean} isLinked Enable linked refresh behaviour
* @param {Boolean} isExternal Render in external container
* @param {String} extSlcId External container id
*/
_build(colIndex, isLinked=false, isExternal=false, extSlcId=null){
var tf = this.tf;
build(colIndex, isLinked=false, isExternal=false, extSlcId=null){
let tf = this.tf;
colIndex = parseInt(colIndex, 10);
this.emitter.emit('before-populating-filter', tf, colIndex);
this.opts = [];
this.optsTxt = [];
this.slcInnerHtml = '';
var slcId = tf.fltIds[colIndex];
let slcId = tf.fltIds[colIndex];
if((!Dom.id(slcId) && !isExternal) ||
(!Dom.id(extSlcId) && isExternal)){
return;
}
var slc = !isExternal ? Dom.id(slcId) : Dom.id(extSlcId),
let slc = !isExternal ? Dom.id(slcId) : Dom.id(extSlcId),
rows = tf.tbl.rows,
matchCase = tf.matchCase;
@ -82,41 +143,27 @@ export class Dropdown{
this.isCustom = tf.isCustomOptions(colIndex);
//custom selects text
var activeFlt;
let activeFlt;
if(isLinked && tf.activeFilterId){
activeFlt = tf.activeFilterId.split('_')[0];
activeFlt = activeFlt.split(tf.prfxFlt)[1];
}
/*** remember grid values ***/
var fltsValues = [], fltArr = [];
if(tf.rememberGridValues){
fltsValues =
tf.feature('store').getFilterValues(tf.fltsValuesCookie);
if(fltsValues && !Str.isEmpty(fltsValues.toString())){
if(this.isCustom){
fltArr.push(fltsValues[colIndex]);
} else {
fltArr = fltsValues[colIndex].split(' '+tf.orOperator+' ');
}
}
}
var excludedOpts = null,
let excludedOpts = null,
filteredDataCol = null;
if(isLinked && tf.disableExcludedOptions){
excludedOpts = [];
filteredDataCol = [];
}
for(var k=tf.refRow; k<tf.nbRows; k++){
for(let k=tf.refRow; k<tf.nbRows; k++){
// always visible rows don't need to appear on selects as always
// valid
if(tf.hasVisibleRows && tf.visibleRows.indexOf(k) !== -1){
continue;
}
var cell = rows[k].cells,
let cell = rows[k].cells,
nchilds = cell.length;
// checks if row has exact cell #
@ -125,7 +172,7 @@ export class Dropdown{
}
// this loop retrieves cell data
for(var j=0; j<nchilds; j++){
for(let j=0; j<nchilds; j++){
// WTF: cyclomatic complexity hell
if((colIndex===j &&
(!isLinked ||
@ -138,7 +185,7 @@ export class Dropdown{
((activeFlt===undefined || activeFlt==colIndex) ||
(activeFlt!=colIndex &&
tf.validRowsIndex.indexOf(k) != -1 ))) ))){
var cell_data = tf.getCellData(cell[j]),
let cell_data = tf.getCellData(cell[j]),
//Vary Peter's patch
cell_string = Str.matchCase(cell_data, matchCase);
@ -148,14 +195,13 @@ export class Dropdown{
}
if(isLinked && tf.disableExcludedOptions){
var filteredCol = filteredDataCol[j];
let filteredCol = filteredDataCol[j];
if(!filteredCol){
filteredCol = tf.getFilteredDataCol(j);
}
if(!Arr.has(filteredCol, cell_string, matchCase) &&
!Arr.has(
excludedOpts, cell_string, matchCase) &&
!this.isFirstLoad){
excludedOpts, cell_string, matchCase)){
excludedOpts.push(cell_data);
}
}
@ -165,7 +211,7 @@ export class Dropdown{
//Retrieves custom values
if(this.isCustom){
var customValues = tf.getCustomOptions(colIndex);
let customValues = tf.getCustomOptions(colIndex);
this.opts = customValues[0];
this.optsTxt = customValues[1];
}
@ -224,8 +270,9 @@ export class Dropdown{
}
//populates drop-down
this.addOptions(
colIndex, slc, isLinked, excludedOpts, fltsValues, fltArr);
this.addOptions(colIndex, slc, isLinked, excludedOpts);
this.emitter.emit('after-populating-filter', tf, colIndex, slc);
}
/**
@ -234,24 +281,22 @@ export class Dropdown{
* @param {Object} slc Select Dom element
* @param {Boolean} isLinked Enable linked refresh behaviour
* @param {Array} excludedOpts Array of excluded options
* @param {Array} fltsValues Collection of persisted filter values
* @param {Array} fltArr Collection of persisted filter values
*/
addOptions(colIndex, slc, isLinked, excludedOpts, fltsValues, fltArr){
var tf = this.tf,
addOptions(colIndex, slc, isLinked, excludedOpts){
let tf = this.tf,
fillMethod = Str.lower(this.slcFillingMethod),
slcValue = slc.value;
slc.innerHTML = '';
slc = this.addFirstOption(slc);
for(var y=0; y<this.opts.length; y++){
for(let y=0; y<this.opts.length; y++){
if(this.opts[y]===''){
continue;
}
var val = this.opts[y]; //option value
var lbl = this.isCustom ? this.optsTxt[y] : val; //option text
var isDisabled = false;
let val = this.opts[y]; //option value
let lbl = this.isCustom ? this.optsTxt[y] : val; //option text
let isDisabled = false;
if(isLinked && tf.disableExcludedOptions &&
Arr.has(
excludedOpts,
@ -262,7 +307,7 @@ export class Dropdown{
}
if(fillMethod === 'innerhtml'){
var slcAttr = '';
let slcAttr = '';
if(tf.loadFltOnDemand && slcValue===this.opts[y]){
slcAttr = 'selected="selected"';
}
@ -270,30 +315,13 @@ export class Dropdown{
(isDisabled ? 'disabled="disabled"' : '')+ '>' +
lbl+'</option>';
} else {
var opt;
let opt;
//fill select on demand
if(tf.loadFltOnDemand && slcValue===this.opts[y] &&
tf.getFilterType(colIndex) === tf.fltTypeSlc){
opt = Dom.createOpt(lbl, val, true);
} else {
if(tf.getFilterType(colIndex) !== tf.fltTypeMulti){
opt = Dom.createOpt(
lbl,
val,
(fltsValues[colIndex]!==' ' &&
val===fltsValues[colIndex]) ? true : false
);
} else {
opt = Dom.createOpt(
lbl,
val,
(Arr.has(fltArr,
Str.matchCase(this.opts[y], tf.matchCase),
tf.matchCase) ||
fltArr.toString().indexOf(val)!== -1) ?
true : false
);
}
opt = Dom.createOpt(lbl, val, false);
}
if(isDisabled){
opt.disabled = true;
@ -313,7 +341,7 @@ export class Dropdown{
* @param {Object} slc Select DOM element
*/
addFirstOption(slc){
var tf = this.tf,
let tf = this.tf,
fillMethod = Str.lower(this.slcFillingMethod);
if(fillMethod === 'innerhtml'){
@ -321,22 +349,59 @@ export class Dropdown{
'</option>';
}
else {
var opt0 = Dom.createOpt(
let opt0 = Dom.createOpt(
(!this.enableSlcResetFilter ? '' : tf.displayAllText),'');
if(!this.enableSlcResetFilter){
opt0.style.display = 'none';
}
slc.appendChild(opt0);
if(tf.enableEmptyOption){
var opt1 = Dom.createOpt(tf.emptyText, tf.emOperator);
let opt1 = Dom.createOpt(tf.emptyText, tf.emOperator);
slc.appendChild(opt1);
}
if(tf.enableNonEmptyOption){
var opt2 = Dom.createOpt(tf.nonEmptyText, tf.nmOperator);
let opt2 = Dom.createOpt(tf.nonEmptyText, tf.nmOperator);
slc.appendChild(opt2);
}
}
return slc;
}
/**
* Select filter options programmatically
* @param {Number} colIndex Column index
* @param {Array} values Array of option values to select
*/
selectOptions(colIndex, values=[]){
let tf = this.tf;
if(tf.getFilterType(colIndex) !== tf.fltTypeMulti ||
values.length === 0){
return;
}
let slc = tf.getFilterElement(colIndex);
[].forEach.call(slc.options, (option)=> {
// Empty value means clear all selections and first option is the
// clear all option
if(values[0] === '' || option.value === ''){
option.selected = false;
}
if(option.value !== '' &&
Arr.has(values, option.value, true)){
option.selected = true;
}//if
});
}
destroy(){
this.emitter.off(
['build-select-filter'],
(colIndex, isLinked, isExternal)=>
this.build(colIndex, isLinked, isExternal)
);
this.emitter.off(
['select-options'],
(tf, colIndex, values)=> this.selectOptions(colIndex, values)
);
}
}

View file

@ -7,6 +7,7 @@ export class Feature {
this.feature = feature;
this.enabled = tf[feature];
this.config = tf.config();
this.emitter = tf.emitter;
this.initialized = false;
}

View file

@ -13,7 +13,7 @@ export class GridLayout extends Feature{
constructor(tf){
super(tf, 'gridLayout');
var f = this.config;
let f = this.config;
//defines grid width
this.gridWidth = f.grid_width || null;
@ -54,27 +54,35 @@ export class GridLayout extends Feature{
this.prfxGridTh = 'tblHeadTh_';
this.sourceTblHtml = tf.tbl.outerHTML;
// filters flag at TF level
tf.fltGrid = this.gridEnableFilters;
}
/**
* Generates a grid with fixed headers
*/
init(){
var tf = this.tf;
var f = this.config;
var tbl = tf.tbl;
let tf = this.tf;
let f = this.config;
let tbl = tf.tbl;
if(this.initialized){
return;
}
// Override reference rows indexes
tf.refRow = Types.isNull(tf.startRow) ? 0 : tf.startRow;
tf.headersRow = 0;
tf.filtersRowIndex = 1;
tf.isExternalFlt = true;
// default width of 100px if column widths not set
if(!tf.hasColWidths){
tf.colWidths = [];
for(var k=0; k<tf.nbCells; k++){
var colW,
for(let k=0; k<tf.nbCells; k++){
let colW,
cell = tbl.rows[this.gridHeadRowIndex].cells[k];
if(cell.width !== ''){
colW = cell.width;
@ -89,7 +97,7 @@ export class GridLayout extends Feature{
}
tf.setColWidths(this.gridHeadRowIndex);
var tblW;//initial table width
let tblW;//initial table width
if(tbl.width !== ''){
tblW = tbl.width;
}
@ -122,7 +130,7 @@ export class GridLayout extends Feature{
this.tblCont.style.height = this.gridHeight;
}
tbl.parentNode.insertBefore(this.tblCont, tbl);
var t = Dom.remove(tbl);
let t = Dom.remove(tbl);
this.tblCont.appendChild(t);
//In case table width is expressed in %
@ -131,7 +139,7 @@ export class GridLayout extends Feature{
tbl.clientWidth : tblW) + 'px';
}
var d = Dom.remove(this.tblCont);
let d = Dom.remove(this.tblCont);
this.tblMainCont.appendChild(d);
//Headers table container: div wrapping headers table
@ -148,15 +156,15 @@ export class GridLayout extends Feature{
//Headers table
this.headTbl = Dom.create('table', ['id', this.prfxHeadTbl + tf.id]);
var tH = Dom.create('tHead');
let tH = Dom.create('tHead');
//1st row should be headers row, ids are added if not set
//Those ids are used by the sort feature
var hRow = tbl.rows[this.gridHeadRowIndex];
var sortTriggers = [];
for(var n=0; n<tf.nbCells; n++){
var c = hRow.cells[n];
var thId = c.getAttribute('id');
let hRow = tbl.rows[this.gridHeadRowIndex];
let sortTriggers = [];
for(let n=0; n<tf.nbCells; n++){
let c = hRow.cells[n];
let thId = c.getAttribute('id');
if(!thId || thId===''){
thId = this.prfxGridTh+n+'_'+tf.id;
c.setAttribute('id', thId);
@ -165,24 +173,24 @@ export class GridLayout extends Feature{
}
//Filters row is created
var filtersRow = Dom.create('tr');
let filtersRow = Dom.create('tr');
if(this.gridEnableFilters && tf.fltGrid){
tf.externalFltTgtIds = [];
for(var j=0; j<tf.nbCells; j++){
var fltTdId = tf.prfxFlt+j+ this.prfxGridFltTd +tf.id;
var cl = Dom.create(tf.fltCellTag, ['id', fltTdId]);
for(let j=0; j<tf.nbCells; j++){
let fltTdId = tf.prfxFlt+j+ this.prfxGridFltTd +tf.id;
let cl = Dom.create(tf.fltCellTag, ['id', fltTdId]);
filtersRow.appendChild(cl);
tf.externalFltTgtIds[j] = fltTdId;
}
}
//Headers row are moved from content table to headers table
for(var i=0; i<this.gridHeadRows.length; i++){
var headRow = tbl.rows[this.gridHeadRows[0]];
for(let i=0; i<this.gridHeadRows.length; i++){
let headRow = tbl.rows[this.gridHeadRows[0]];
tH.appendChild(headRow);
}
this.headTbl.appendChild(tH);
if(tf.filtersRowIndex === 0){
tH.insertBefore(filtersRow,hRow);
tH.insertBefore(filtersRow, hRow);
} else {
tH.appendChild(filtersRow);
}
@ -191,7 +199,7 @@ export class GridLayout extends Feature{
this.tblCont.parentNode.insertBefore(this.headTblCont, this.tblCont);
//THead needs to be removed in content table for sort feature
var thead = Dom.tag(tbl, 'thead');
let thead = Dom.tag(tbl, 'thead');
if(thead.length>0){
tbl.removeChild(thead[0]);
}
@ -216,15 +224,15 @@ export class GridLayout extends Feature{
//scroll synchronisation
Event.add(this.tblCont, 'scroll', (evt)=> {
var elm = Event.target(evt);
var scrollLeft = elm.scrollLeft;
let elm = Event.target(evt);
let scrollLeft = elm.scrollLeft;
this.headTblCont.scrollLeft = scrollLeft;
//New pointerX calc taking into account scrollLeft
// if(!o.isPointerXOverwritten){
// try{
// o.Evt.pointerX = function(evt){
// var e = evt || global.event;
// var bdScrollLeft = tf_StandardBody().scrollLeft +
// let e = evt || global.event;
// let bdScrollLeft = tf_StandardBody().scrollLeft +
// scrollLeft;
// return (e.pageX + scrollLeft) ||
// (e.clientX + bdScrollLeft);
@ -237,7 +245,7 @@ export class GridLayout extends Feature{
});
//Configure sort extension if any
var sort = (f.extensions || []).filter(function(itm){
let sort = (f.extensions || []).filter(function(itm){
return itm.name === 'sort';
});
if(sort.length === 1){
@ -250,9 +258,9 @@ export class GridLayout extends Feature{
//Col elements are enough to keep column widths after sorting and
//filtering
var createColTags = function(){
for(var k=(tf.nbCells-1); k>=0; k--){
var col = Dom.create('col', ['id', tf.id+'_col_'+k]);
let createColTags = function(){
for(let k=(tf.nbCells-1); k>=0; k--){
let col = Dom.create('col', ['id', tf.id+'_col_'+k]);
tbl.insertBefore(col, tbl.firstChild);
col.style.width = tf.colWidths[k];
this.gridColElms[k] = col;
@ -263,26 +271,26 @@ export class GridLayout extends Feature{
if(!this.tblHasColTag){
createColTags.call(this);
} else {
var cols = Dom.tag(tbl, 'col');
for(var ii=0; ii<tf.nbCells; ii++){
let cols = Dom.tag(tbl, 'col');
for(let ii=0; ii<tf.nbCells; ii++){
cols[ii].setAttribute('id', tf.id+'_col_'+ii);
cols[ii].style.width = tf.colWidths[ii];
this.gridColElms.push(cols[ii]);
}
}
var afterColResizedFn = Types.isFn(f.on_after_col_resized) ?
let afterColResizedFn = Types.isFn(f.on_after_col_resized) ?
f.on_after_col_resized : null;
f.on_after_col_resized = function(o, colIndex){
if(!colIndex){
return;
}
var w = o.crWColsRow.cells[colIndex].style.width;
var col = o.gridColElms[colIndex];
let w = o.crWColsRow.cells[colIndex].style.width;
let col = o.gridColElms[colIndex];
col.style.width = w;
var thCW = o.crWColsRow.cells[colIndex].clientWidth;
var tdCW = o.crWRowDataTbl.cells[colIndex].clientWidth;
let thCW = o.crWColsRow.cells[colIndex].clientWidth;
let tdCW = o.crWRowDataTbl.cells[colIndex].clientWidth;
if(thCW != tdCW){
o.headTbl.style.width = tbl.clientWidth+'px';
@ -308,13 +316,13 @@ export class GridLayout extends Feature{
* Removes the grid layout
*/
destroy(){
var tf = this.tf;
var tbl = tf.tbl;
let tf = this.tf;
let tbl = tf.tbl;
if(!this.initialized){
return;
}
var t = Dom.remove(tbl);
let t = Dom.remove(tbl);
this.tblMainCont.parentNode.insertBefore(t, this.tblMainCont);
Dom.remove(this.tblMainCont);
@ -325,7 +333,7 @@ export class GridLayout extends Feature{
tbl.outerHTML = this.sourceTblHtml;
//needed to keep reference of table element for future usage
this.tf.tbl = t;
this.tf.tbl = Dom.id(tf.id);
this.initialized = false;
}

View file

@ -59,6 +59,8 @@ export class Help extends Feature{
this.prfxHelpSpan = 'helpSpan_';
//id prefix for help elements
this.prfxHelpDiv = 'helpDiv_';
this.emitter.on(['init-help'], ()=> this.init());
}
init(){

View file

@ -1,5 +1,6 @@
import Dom from '../dom';
import Str from '../string';
import Types from '../types';
export class HighlightKeyword{
@ -14,6 +15,19 @@ export class HighlightKeyword{
this.highlightedNodes = [];
this.tf = tf;
this.emitter = tf.emitter;
}
init(){
this.emitter.on(
['before-filtering', 'destroy'],
()=> this.unhighlightAll()
);
this.emitter.on(
['highlight-keyword'],
(tf, cell, word)=>
this.highlight(cell, word, this.highlightCssClass)
);
}
/**
@ -96,13 +110,30 @@ export class HighlightKeyword{
* Clear all occurrences of highlighted nodes
*/
unhighlightAll(){
if(!this.tf.highlightKeywords || !this.tf.searchArgs){
if(!this.tf.highlightKeywords){
return;
}
for(var y=0; y<this.tf.searchArgs.length; y++){
this.unhighlight(
this.tf.searchArgs[y], this.highlightCssClass);
}
// iterate filters values to unhighlight all values
this.tf.getFiltersValue().forEach((val)=> {
if(Types.isArray(val)){
val.forEach((item)=>
this.unhighlight(item, this.highlightCssClass));
} else {
this.unhighlight(val, this.highlightCssClass);
}
});
this.highlightedNodes = [];
}
destroy(){
this.emitter.off(
['before-filtering', 'destroy'],
()=> this.unhighlightAll()
);
this.emitter.off(
['highlight-keyword'],
(tf, cell, word)=>
this.highlight(cell, word, this.highlightCssClass)
);
}
}

View file

@ -2,7 +2,7 @@ import {Feature} from './feature';
import Dom from '../dom';
import Types from '../types';
var global = window;
let global = window;
export class Loader extends Feature{
@ -10,11 +10,11 @@ export class Loader extends Feature{
* Loading message/spinner
* @param {Object} tf TableFilter instance
*/
constructor(tf){
constructor(tf) {
super(tf, 'loader');
// TableFilter configuration
var f = this.config;
let f = this.config;
//id of container element
this.loaderTgtId = f.loader_target_id || null;
@ -27,7 +27,7 @@ export class Loader extends Feature{
//defines css class for loader div
this.loaderCssClass = f.loader_css_class || 'loader';
//delay for hiding loader
this.loaderCloseDelay = 200;
this.loaderCloseDelay = 250;
//callback function before loader is displayed
this.onShowLoader = Types.isFn(f.on_show_loader) ?
f.on_show_loader : null;
@ -43,12 +43,13 @@ export class Loader extends Feature{
return;
}
var tf = this.tf;
let tf = this.tf;
let emitter = this.emitter;
var containerDiv = Dom.create('div', ['id', this.prfxLoader+tf.id]);
let containerDiv = Dom.create('div', ['id', this.prfxLoader+tf.id]);
containerDiv.className = this.loaderCssClass;
var targetEl = !this.loaderTgtId ?
let targetEl = !this.loaderTgtId ?
tf.tbl.parentNode : Dom.id(this.loaderTgtId);
if(!this.loaderTgtId){
targetEl.insertBefore(containerDiv, tf.tbl);
@ -63,15 +64,44 @@ export class Loader extends Feature{
}
this.show('none');
// Subscribe to events
emitter.on([
'before-filtering',
'before-populating-filter',
'before-changing-page',
'before-clearing-filters',
'before-changing-results-per-page',
'before-reset-page',
'before-reset-page-length',
'before-loading-extensions',
'before-loading-themes'
],
()=> this.show('')
);
emitter.on([
'after-filtering',
'after-populating-filter',
'after-changing-page',
'after-clearing-filters',
'after-changing-results-per-page',
'after-reset-page',
'after-reset-page-length',
'after-loading-extensions',
'after-loading-themes'
],
()=> this.show('none')
);
this.initialized = true;
}
show(p) {
if(!this.isEnabled() || this.loaderDiv.style.display === p){
if(!this.isEnabled() /*|| this.loaderDiv.style.display === p*/){
return;
}
var displayLoader = () => {
let displayLoader = () => {
if(!this.loaderDiv){
return;
}
@ -84,17 +114,48 @@ export class Loader extends Feature{
}
};
var t = p === 'none' ? this.loaderCloseDelay : 1;
let t = p === 'none' ? this.loaderCloseDelay : 1;
global.setTimeout(displayLoader, t);
}
destroy(){
destroy() {
if(!this.initialized){
return;
}
let emitter = this.emitter;
Dom.remove(this.loaderDiv);
this.loaderDiv = null;
// Unsubscribe to events
emitter.off([
'before-filtering',
'before-populating-filter',
'before-changing-page',
'before-clearing-filters',
'before-changing-results-per-page',
'before-reset-page',
'before-reset-page-length',
'before-loading-extensions',
'before-loading-themes'
],
()=> this.show('')
);
emitter.off([
'after-filtering',
'after-populating-filter',
'after-changing-page',
'after-clearing-filters',
'after-changing-results-per-page',
'after-reset-page',
'after-reset-page-length',
'after-loading-extensions',
'after-loading-themes'
],
()=> this.show('none')
);
this.initialized = false;
}
}

View file

@ -59,10 +59,22 @@ export class NoResults extends Feature{
}
this.cont = cont;
// subscribe to after-filtering event
this.emitter.on(['after-filtering'], ()=> this.toggle());
this.initialized = true;
this.hide();
}
toggle(){
if(this.tf.nbVisibleRows > 0){
this.hide();
} else {
this.show();
}
}
show(){
if(!this.initialized || !this.isEnabled()){
return;
@ -115,6 +127,9 @@ export class NoResults extends Feature{
}
Dom.remove(this.cont);
this.cont = null;
// unsubscribe to after-filtering event
this.emitter.off(['after-filtering'], ()=> this.toggle());
this.initialized = false;
}
}

View file

@ -120,8 +120,8 @@ export class Paging extends Feature{
//span following pages select (contains ' of ')
this.prfxPgAfterSpan = 'pgafterspan_';
var start_row = this.refRow;
var nrows = this.nbRows;
var start_row = tf.refRow;
var nrows = tf.nbRows;
//calculates page nb
this.nbPages = Math.ceil((nrows-start_row)/this.pagingLength);
@ -334,6 +334,9 @@ export class Paging extends Feature{
this.setPagingInfo(tf.validRowsIndex);
}
this.emitter.on(['after-filtering'], ()=> this.resetPagingInfo());
this.emitter.on(['initialized'], ()=> this.resetValues());
this.initialized = true;
}
@ -343,45 +346,38 @@ export class Paging extends Feature{
*/
reset(filterTable=false){
var tf = this.tf;
if(!tf.hasGrid() || this.isEnabled()){
if(this.isEnabled()){
return;
}
this.enable();
this.init();
tf.resetValues();
// tf.resetValues();
if(filterTable){
tf.filter();
}
}
/**
* Reset paging info from scratch after a filtering process
*/
resetPagingInfo(){
this.startPagingRow = 0;
this.currentPageNb = 1;
this.setPagingInfo(this.tf.validRowsIndex);
}
/**
* Calculate number of pages based on valid rows
* Refresh paging select according to number of pages
* @param {Array} validRows Collection of valid rows
*/
setPagingInfo(validRows=[]){
setPagingInfo(validRows){
var tf = this.tf;
var rows = tf.tbl.rows;
var mdiv = !this.pagingTgtId ? tf.mDiv : Dom.id(this.pagingTgtId);
var pgspan = Dom.id(this.prfxPgSpan+tf.id);
//store valid rows indexes
tf.validRowsIndex = validRows;
if(validRows.length === 0){
//counts rows to be grouped
for(var j=tf.refRow; j<tf.nbRows; j++){
var row = rows[j];
if(!row){
continue;
}
var isRowValid = row.getAttribute('validRow');
if(Types.isNull(isRowValid) || Boolean(isRowValid==='true')){
tf.validRowsIndex.push(j);
}
}
}
tf.validRowsIndex = validRows || tf.getValidRows(true);
//calculate nb of pages
this.nbPages = Math.ceil(tf.validRowsIndex.length/this.pagingLength);
@ -417,7 +413,6 @@ export class Paging extends Feature{
*/
groupByPage(validRows){
var tf = this.tf;
var alternateRows = tf.feature('alternateRows');
var rows = tf.tbl.rows;
var startPagingRow = parseInt(this.startPagingRow, 10);
var endPagingRow = startPagingRow + parseInt(this.pagingLength, 10);
@ -432,25 +427,23 @@ export class Paging extends Feature{
var validRowIdx = tf.validRowsIndex[h];
var r = rows[validRowIdx];
var isRowValid = r.getAttribute('validRow');
var rowDisplayed = false;
if(h>=startPagingRow && h<endPagingRow){
if(Types.isNull(isRowValid) || Boolean(isRowValid==='true')){
r.style.display = '';
}
if(tf.alternateRows && alternateRows){
alternateRows.setRowBg(validRowIdx, h);
rowDisplayed = true;
}
} else {
r.style.display = 'none';
if(tf.alternateRows && alternateRows){
alternateRows.removeRowBg(validRowIdx);
}
}
this.emitter.emit('row-paged', tf, validRowIdx, h, rowDisplayed);
}
tf.nbVisibleRows = tf.validRowsIndex.length;
//re-applies filter behaviours after filtering process
tf.applyProps();
// broadcast grouping by page
this.emitter.emit('grouped-by-page', tf, this);
}
/**
@ -504,9 +497,6 @@ export class Paging extends Feature{
var tf = this.tf;
var evt = this.evt;
if(!tf.hasGrid() && !tf.isFirstLoad){
return;
}
if(this.resultsPerPageSlc || !this.resultsPerPage){
return;
}
@ -569,53 +559,19 @@ export class Paging extends Feature{
this.resultsPerPageSlc = null;
}
/**
* Change the page asynchronously according to passed index
* @param {Number} index Index of the page (0-n)
*/
changePage(index){
var tf = this.tf;
var evt = tf.Evt;
tf.EvtManager(evt.name.changepage, { pgIndex:index });
}
/**
* Change rows asynchronously according to page results
*/
changeResultsPerPage(){
var tf = this.tf;
var evt = tf.Evt;
tf.EvtManager(evt.name.changeresultsperpage);
}
/**
* Re-set asynchronously page nb at page re-load
*/
resetPage(){
var tf = this.tf;
var evt = tf.Evt;
tf.EvtManager(evt.name.resetpage);
}
/**
* Re-set asynchronously page length at page re-load
*/
resetPageLength(){
var tf = this.tf;
var evt = tf.Evt;
tf.EvtManager(evt.name.resetpagelength);
}
/**
* Change the page according to passed index
* @param {Number} index Index of the page (0-n)
*/
_changePage(index){
changePage(index){
var tf = this.tf;
if(!this.isEnabled()){
return;
}
this.emitter.emit('before-changing-page', tf, index);
if(index === null){
index = this.pageSelectorType===tf.fltTypeSlc ?
this.pagingSlc.options.selectedIndex : (this.pagingSlc.value-1);
@ -643,18 +599,23 @@ export class Paging extends Feature{
this.onAfterChangePage.call(null, this, index);
}
}
this.emitter.emit('after-changing-page', tf, index);
}
/**
* Change rows according to page results drop-down
* TODO: accept a parameter setting the results per page length
*/
_changeResultsPerPage(){
changeResultsPerPage(){
var tf = this.tf;
if(!this.isEnabled()){
return;
}
this.emitter.emit('before-changing-results-per-page', tf);
var slcR = this.resultsPerPageSlc;
var slcPagesSelIndex = (this.pageSelectorType===tf.fltTypeSlc) ?
this.pagingSlc.selectedIndex :
@ -678,33 +639,55 @@ export class Paging extends Feature{
tf.feature('store').savePageLength(tf.pgLenCookie);
}
}
this.emitter.emit('after-changing-results-per-page', tf);
}
/**
* Re-set persisted pagination info
*/
resetValues(){
var tf = this.tf;
if(tf.rememberPageLen){
this.resetPageLength(tf.pgLenCookie);
}
if(tf.rememberPageNb){
this.resetPage(tf.pgNbCookie);
}
}
/**
* Re-set page nb at page re-load
*/
_resetPage(name){
resetPage(name){
var tf = this.tf;
if(!this.isEnabled()){
return;
}
this.emitter.emit('before-reset-page', tf);
var pgnb = tf.feature('store').getPageNb(name);
if(pgnb!==''){
if(pgnb !== ''){
this.changePage((pgnb-1));
}
this.emitter.emit('after-reset-page', tf, pgnb);
}
/**
* Re-set page length value at page re-load
*/
_resetPageLength(name){
resetPageLength(name){
var tf = this.tf;
if(!this.isEnabled()){
return;
}
this.emitter.emit('before-reset-page-length', tf);
var pglenIndex = tf.feature('store').getPageLength(name);
if(pglenIndex!==''){
this.resultsPerPageSlc.options[pglenIndex].selected = true;
this.changeResultsPerPage();
}
this.emitter.emit('after-reset-page-length', tf, pglenIndex);
}
/**
@ -776,6 +759,9 @@ export class Paging extends Feature{
this.removeResultsPerPage();
}
this.emitter.off(['after-filtering'], ()=> this.resetPagingInfo());
this.emitter.off(['initialized'], ()=> this.resetValues());
this.pagingSlc = null;
this.nbPages = 0;
this.disable();

View file

@ -15,7 +15,7 @@ export class PopupFilter extends Feature{
// Configuration object
var f = this.config;
// Enable external filters behaviour
// Enable external filters
tf.isExternalFlt = true;
tf.externalFltTgtIds = [];
@ -84,6 +84,12 @@ export class PopupFilter extends Feature{
}
var tf = this.tf;
// Override headers row index if no grouped headers
if(tf.headersRow <= 1){
tf.headersRow = 0;
}
for(var i=0; i<tf.nbCells; i++){
if(tf.getFilterType(i) === tf.fltTypeNone){
continue;
@ -101,6 +107,15 @@ export class PopupFilter extends Feature{
this.popUpFltImgs[i] = popUpSpan.firstChild;
}
// subscribe to events
this.emitter.on(['before-filtering'], ()=> this.buildIcons());
this.emitter.on(['after-filtering'], ()=> this.closeAll());
this.emitter.on(['cell-processed'],
(tf, cellIndex)=> this.buildIcon(cellIndex, true));
this.emitter.on(['filters-row-inserted'], ()=> this.tf.headersRow++);
this.emitter.on(['before-filter-init'],
(tf, colIndex)=> this.build(colIndex));
this.initialized = true;
}
@ -204,7 +219,7 @@ export class PopupFilter extends Feature{
}
/**
* Build specified icon
* Apply specified icon state
* @param {Number} colIndex Column index
* @param {Boolean} active Apply active state
*/
@ -245,6 +260,16 @@ export class PopupFilter extends Feature{
this.popUpFltElms = [];
this.popUpFltSpans = [];
this.popUpFltImgs = [];
// unsubscribe to events
this.emitter.off(['before-filtering'], ()=> this.buildIcons());
this.emitter.off(['after-filtering'], ()=> this.closeAll());
this.emitter.off(['cell-processed'],
(tf, cellIndex)=> this.buildIcon(cellIndex, true));
this.emitter.off(['filters-row-inserted'], ()=> this.tf.headersRow++);
this.emitter.off(['before-filter-init'],
(tf, colIndex)=> this.build(colIndex));
this.initialized = false;
}

View file

@ -76,6 +76,11 @@ export class RowsCounter extends Feature{
this.rowsCounterDiv = countDiv;
this.rowsCounterSpan = countSpan;
// subscribe to events
this.emitter.on(['after-filtering', 'grouped-by-page'],
()=> this.refresh(tf.nbVisibleRows));
this.emitter.on(['rows-changed'], ()=> this.refresh());
this.initialized = true;
this.refresh();
}
@ -132,6 +137,12 @@ export class RowsCounter extends Feature{
}
this.rowsCounterSpan = null;
this.rowsCounterDiv = null;
// unsubscribe to events
this.emitter.off(['after-filtering', 'grouped-by-page'],
()=> this.refresh(tf.nbVisibleRows));
this.emitter.off(['rows-changed'], ()=> this.refresh());
this.initialized = false;
}
}

View file

@ -2,7 +2,7 @@ import {Feature} from './feature';
import Dom from '../dom';
import Types from '../types';
var global = window;
let global = window;
export class StatusBar extends Feature{
@ -14,7 +14,7 @@ export class StatusBar extends Feature{
super(tf, 'statusBar');
// Configuration object
var f = this.config;
let f = this.config;
//id of custom container element
this.statusBarTgtId = f.status_bar_target_id || null;
@ -38,6 +38,33 @@ export class StatusBar extends Feature{
this.onAfterShowMsg = Types.isFn(f.on_after_show_msg) ?
f.on_after_show_msg : null;
//status messages
this.msgFilter = f.msg_filter || 'Filtering data...';
//populating drop-downs
this.msgPopulate = f.msg_populate || 'Populating filter...';
//populating drop-downs
this.msgPopulateCheckList = f.msg_populate_checklist ||
'Populating list...';
//changing paging page
this.msgChangePage = f.msg_change_page || 'Collecting paging data...';
//clearing filters
this.msgClear = f.msg_clear || 'Clearing filters...';
//changing nb results/page
this.msgChangeResults = f.msg_change_results ||
'Changing results per page...';
//re-setting page
this.msgResetPage = f.msg_reset_page || 'Re-setting page...';
//re-setting page length
this.msgResetPageLength = f.msg_reset_page_length ||
'Re-setting page length...';
//table sorting
this.msgSort = f.msg_sort || 'Sorting data...';
//extensions loading
this.msgLoadExtensions = f.msg_load_extensions ||
'Loading extensions...';
//themes loading
this.msgLoadThemes = f.msg_load_themes || 'Loading theme(s)...';
// status bar div
this.prfxStatus = 'status_';
// status bar label
@ -51,16 +78,17 @@ export class StatusBar extends Feature{
return;
}
var tf = this.tf;
let tf = this.tf;
let emitter = this.emitter;
//status bar container
var statusDiv = Dom.create('div', ['id', this.prfxStatus+tf.id]);
let statusDiv = Dom.create('div', ['id', this.prfxStatus+tf.id]);
statusDiv.className = this.statusBarCssClass;
//status bar label
var statusSpan = Dom.create('span', ['id', this.prfxStatusSpan+tf.id]);
let statusSpan = Dom.create('span', ['id', this.prfxStatusSpan+tf.id]);
//preceding text
var statusSpanText = Dom.create('span',
let statusSpanText = Dom.create('span',
['id', this.prfxStatusTxt+tf.id]);
statusSpanText.appendChild(Dom.text(this.statusBarText));
@ -68,7 +96,7 @@ export class StatusBar extends Feature{
if(!this.statusBarTgtId){
tf.setToolbar();
}
var targetEl = (!this.statusBarTgtId) ?
let targetEl = (!this.statusBarTgtId) ?
tf.lDiv : Dom.id(this.statusBarTgtId);
//default container: 'lDiv'
@ -86,6 +114,38 @@ export class StatusBar extends Feature{
this.statusBarSpan = statusSpan;
this.statusBarSpanText = statusSpanText;
// Subscribe to events
emitter.on(['before-filtering'], ()=> this.message(this.msgFilter));
emitter.on(['before-populating-filter'],
()=> this.message(this.msgPopulate));
emitter.on(['before-changing-page'],
()=> this.message(this.msgChangePage));
emitter.on(['before-clearing-filters'], ()=>
this.message(this.msgClear));
emitter.on(['before-changing-results-per-page'],
()=> this.message(this.msgChangeResults));
emitter.on(['before-reset-page'], ()=> this.message(this.msgResetPage));
emitter.on(['before-reset-page-length'],
()=> this.message(this.msgResetPageLength));
emitter.on(['before-loading-extensions'],
()=> this.message(this.msgLoadExtensions));
emitter.on(['before-loading-themes'],
()=> this.message(this.msgLoadThemes));
emitter.on([
'after-filtering',
'after-populating-filter',
'after-changing-page',
'after-clearing-filters',
'after-changing-results-per-page',
'after-reset-page',
'after-reset-page-length',
'after-loading-extensions',
'after-loading-themes'
],
()=> this.message('')
);
this.initialized = true;
}
@ -98,8 +158,11 @@ export class StatusBar extends Feature{
this.onBeforeShowMsg.call(null, this.tf, t);
}
var d = t==='' ? this.statusBarCloseDelay : 1;
let d = t==='' ? this.statusBarCloseDelay : 1;
global.setTimeout(() => {
if(!this.initialized){
return;
}
this.statusBarSpan.innerHTML = t;
if(this.onAfterShowMsg){
this.onAfterShowMsg.call(null, this.tf, t);
@ -112,11 +175,49 @@ export class StatusBar extends Feature{
return;
}
let emitter = this.emitter;
this.statusBarDiv.innerHTML = '';
Dom.remove(this.statusBarDiv);
if(!this.statusBarTgtId){
Dom.remove(this.statusBarDiv);
}
this.statusBarSpan = null;
this.statusBarSpanText = null;
this.statusBarDiv = null;
// Unsubscribe to events
emitter.off(['before-filtering'], ()=> this.message(this.msgFilter));
emitter.off(['before-populating-filter'],
()=> this.message(this.msgPopulate));
emitter.off(['before-changing-page'],
()=> this.message(this.msgChangePage));
emitter.off(['before-clearing-filters'],
()=> this.message(this.msgClear));
emitter.off(['before-changing-results-per-page'],
()=> this.message(this.msgChangeResults));
emitter.off(['before-reset-page'], ()=>
this.message(this.msgResetPage));
emitter.off(['before-reset-page-length'],
()=> this.message(this.msgResetPageLength));
emitter.off(['before-loading-extensions'],
()=> this.message(this.msgLoadExtensions));
emitter.off(['before-loading-themes'],
()=> this.message(this.msgLoadThemes));
emitter.off([
'after-filtering',
'after-populating-filter',
'after-changing-page',
'after-clearing-filters',
'after-changing-results-per-page',
'after-reset-page',
'after-reset-page-length',
'after-loading-extensions',
'after-loading-themes'
],
()=> this.message('')
);
this.initialized = false;
}

View file

@ -1,4 +1,5 @@
import Cookie from '../cookie';
import Types from '../types';
export class Store{
@ -8,13 +9,20 @@ export class Store{
*
* TODO: use localStorage and fallback to cookie persistence
*/
constructor(tf) {
var f = tf.config();
constructor(tf){
let f = tf.config();
this.duration = !isNaN(f.set_cookie_duration) ?
parseInt(f.set_cookie_duration, 10) : 100000;
this.tf = tf;
this.emitter = tf.emitter;
}
init(){
this.emitter.on(['after-filtering'],
()=> this.saveFilterValues(this.tf.fltsValuesCookie));
this.emitter.on(['after-clearing-filters'], ()=> this.clearCookies());
}
/**
@ -22,20 +30,29 @@ export class Store{
* @param {String} cookie name
*/
saveFilterValues(name){
var tf = this.tf;
var fltValues = [];
let tf = this.tf;
let fltValues = [];
if(!tf.rememberGridValues){
return;
}
//store filters' values
for(var i=0; i<tf.fltIds.length; i++){
var value = tf.getFilterValue(i);
for(let i=0; i<tf.fltIds.length; i++){
let value = tf.getFilterValue(i);
//convert array to a || separated values
if(Types.isArray(value)){
let rgx = new RegExp(tf.separator, 'g');
value = value.toString()
.replace(rgx, ' ' + tf.orOperator + ' ');
}
if (value === ''){
value = ' ';
}
fltValues.push(value);
}
//adds array size
fltValues.push(tf.fltIds.length);
//writes cookie
//write cookie
Cookie.write(
name,
fltValues.join(tf.separator),
@ -49,8 +66,8 @@ export class Store{
* @return {Array}
*/
getFilterValues(name){
var flts = Cookie.read(name);
var rgx = new RegExp(this.tf.separator, 'g');
let flts = Cookie.read(name);
let rgx = new RegExp(this.tf.separator, 'g');
// filters' values array
return flts.split(rgx);
}
@ -60,6 +77,9 @@ export class Store{
* @param {String} cookie name
*/
savePageNb(name){
if(!this.tf.rememberPageNb){
return;
}
Cookie.write(
name,
this.tf.feature('paging').currentPageNb,
@ -81,6 +101,9 @@ export class Store{
* @param {String} cookie name
*/
savePageLength(name){
if(!this.tf.rememberPageLen){
return;
}
Cookie.write(
name,
this.tf.feature('paging').resultsPerPageSlc.selectedIndex,
@ -97,4 +120,18 @@ export class Store{
return Cookie.read(name);
}
/**
* Remove all cookies
*/
clearCookies(){
Cookie.remove(this.tf.fltsValuesCookie);
Cookie.remove(this.tf.pgLenCookie);
Cookie.remove(this.tf.pgNbCookie);
}
destroy(){
this.emitter.off(['after-filtering'],
()=> this.saveFilterValues(this.tf.fltsValuesCookie));
this.emitter.off(['after-clearing-filters'], ()=> this.clearCookies());
}
}

File diff suppressed because it is too large Load diff

View file

@ -36,9 +36,10 @@
<script data-config>
var tfConfig = {
base_path: '../dist/tablefilter/',
col_0: "multiple",
col_1: "select",
col_2: "checklist",
btn: true,
col_0: 'multiple',
col_1: 'select',
col_2: 'checklist',
col_number_format: [
null, null, 'US',
'US', 'US', 'US',

View file

@ -21,6 +21,7 @@ test('Properties', function() {
deepEqual(altRows.feature, 'alternateRows', 'Feature name');
deepEqual(altRows.enabled, true, 'Feature enabled');
deepEqual(altRows.initialized, true, 'Feature enabled');
deepEqual(typeof altRows.emitter, 'object', 'Feature has emitter instance');
deepEqual(typeof altRows.config, 'object', 'TF configuration object');
deepEqual(typeof altRows.init, 'function', 'Feature init method');
deepEqual(typeof altRows.destroy, 'function', 'Feature destroy method');

View file

@ -12,9 +12,9 @@
});
module('Behaviour');
tf.setFilterValue(0, 'Hello');
tf.filter();
test('for filtered table', function() {
tf.setFilterValue(0, 'Hello');
tf.filter();
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
deepEqual(
@ -29,68 +29,8 @@
);
});
tf.clearFilters();
test('after filters are cleared', function() {
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'',
'Row display for alwaysVisibleRow1'
);
deepEqual(
tf.getRowDisplay(alwaysVisibleRow2),
'',
'Row display for alwaysVisibleRow2'
);
});
tf.destroy();
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
rows_always_visible: [4, 9],
paging: true,
paging_length: 2
});
tf.init();
var paging = tf.feature('paging');
module('Behaviour with paging');
tf.setFilterValue(0, 'Hello');
tf.filter();
test('for filtered table', function() {
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'',
'Row display for alwaysVisibleRow1'
);
deepEqual(
tf.getRowDisplay(alwaysVisibleRow2),
'',
'Row display for alwaysVisibleRow2'
);
});
tf.clearFilters();
test('after filters are cleared', function() {
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'',
'Row display for alwaysVisibleRow1'
);
deepEqual(
tf.getRowDisplay(alwaysVisibleRow2),
'',
'Row display for alwaysVisibleRow2'
);
});
paging.setPage(2);
test('after changing pagination page', function() {
tf.clearFilters();
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
deepEqual(
@ -104,8 +44,72 @@
'Row display for alwaysVisibleRow2'
);
paging.setPage(0);
testPaging();
});
function testPaging(){
tf.destroy();
});
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
rows_always_visible: [4, 9],
paging: true,
paging_length: 2
});
tf.init();
var paging = tf.feature('paging');
module('Behaviour with paging');
test('for filtered table', function() {
tf.setFilterValue(0, 'Hello');
tf.filter();
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'',
'Row display for alwaysVisibleRow1'
);
deepEqual(
tf.getRowDisplay(alwaysVisibleRow2),
'',
'Row display for alwaysVisibleRow2'
);
});
test('after filters are cleared', function() {
tf.clearFilters();
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'none',
'Row display for alwaysVisibleRow1'
);
deepEqual(
tf.getRowDisplay(alwaysVisibleRow2),
'none',
'Row display for alwaysVisibleRow2'
);
});
test('after changing pagination page', function() {
paging.setPage(2);
var alwaysVisibleRow1 = tf.tbl.rows[4];
var alwaysVisibleRow2 = tf.tbl.rows[9];
deepEqual(
tf.getRowDisplay(alwaysVisibleRow1),
'',
'Row display for alwaysVisibleRow1'
);
deepEqual(
tf.getRowDisplay(alwaysVisibleRow2),
'none',
'Row display for alwaysVisibleRow2'
);
tf.destroy();
});
}
})(window, TableFilter);

View file

@ -53,7 +53,7 @@
tf.setFilterValue(0, 'Syd');
tf.setFilterValue(1, 'Ade');
deepEqual(tf.getFilterValue(0), 'Syd', 'Column 0 filter value');
deepEqual(tf.getFiltersValue(), ['syd', 'ade', '', '', '']);
deepEqual(tf.getFiltersValue(), ['Syd', 'Ade', '', '', '']);
});
test('Filter table', function() {
@ -65,6 +65,20 @@
deepEqual(tf.getValidRows().length, 4, 'Filtered rows number');
});
test('Filter table with range', function() {
tf.clearFilters();
tf.setFilterValue(2, '>1500 && <=2871');
tf.filter();
deepEqual(tf.getValidRows().length, 3, 'Filtered rows number');
});
test('Filter table with operator', function() {
tf.clearFilters();
tf.setFilterValue(1, '{Bri');
tf.filter();
deepEqual(tf.getValidRows().length, 2, 'Filtered rows number');
});
test('Clear filters', function() {
tf.clearFilters();
deepEqual(tf.nbVisibleRows, 7, 'Filtered rows number');
@ -185,17 +199,63 @@
tf.setFilterValue(0, 'Sydney');
tf.setFilterValue(1, 'Adelaide');
deepEqual(tf.getFilterValue(0), 'Sydney', 'Column 0 filter value');
deepEqual(tf.getFiltersValue(), ['sydney', 'adelaide', '', '', '']);
deepEqual(tf.getFiltersValue(),
['Sydney', ['Adelaide'], '', '', '']);
});
test('Filter table', function() {
tf.clearFilters();
tf.setFilterValue(1, 'Adelaide');
tf.setFilterValue(1, 'Alice Springs');
tf.filter();
deepEqual(tf.getValidRows().length, 1, 'Filtered rows number');
});
module('TableFilter with pop-up filtes');
test('Can filter table with multiple filter', function() {
tf.clearFilters();
tf.setFilterValue(1, ['Alice Springs', 'Canberra']);
tf.filter();
deepEqual(tf.getValidRows().length, 2, 'Filtered rows number');
});
test('Can filter table with checklist filter', function() {
tf.clearFilters();
tf.setFilterValue(2, ['2045', '2781']);
tf.filter();
deepEqual(tf.getValidRows().length, 2, 'Filtered rows number');
});
test('Can select dropdown options with or operator', function() {
tf.setFilterValue(1, '');
tf.setFilterValue(1, 'Brisbane || Melbourne');
deepEqual(tf.getFilterValue(1), ['Brisbane', 'Melbourne'],
'Column 2 filter values');
});
test('Can select dropdown options with array', function() {
tf.setFilterValue(1, '');
tf.setFilterValue(1, ['Canberra', 'Perth']);
deepEqual(tf.getFilterValue(1), ['Canberra', 'Perth'],
'Column 2 filter values');
});
test('Can select checklist options', function() {
tf.setFilterValue(2, '2045 || 2781');
deepEqual(tf.getFilterValue(2), ['2045', '2781'],
'Column 2 filter values');
});
test('Can select checklist options with array', function() {
tf.setFilterValue(2, '');
tf.setFilterValue(2, ['1412', '982']);
deepEqual(tf.getFilterValue(2), ['1412', '982'],
'Column 2 filter values');
});
module('TableFilter with pop-up filters');
test('Sanity checks', function() {
tf.destroy();
tf = null;
@ -217,7 +277,7 @@
tf.setFilterValue(0, 'Sydney');
tf.setFilterValue(1, 'Adelaide');
deepEqual(tf.getFilterValue(0), 'Sydney', 'Column 0 filter value');
deepEqual(tf.getFiltersValue(), ['sydney', 'adelaide', '', '', '']);
deepEqual(tf.getFiltersValue(), ['Sydney', 'Adelaide', '', '', '']);
});
test('Filter table', function() {
@ -265,7 +325,7 @@
tf.setFilterValue(0, 'Sydney');
tf.setFilterValue(1, 'Adelaide');
deepEqual(tf.getFilterValue(0), 'Sydney', 'Column 0 filter value');
deepEqual(tf.getFiltersValue(), ['sydney', 'adelaide', '', '', '']);
deepEqual(tf.getFiltersValue(), ['Sydney', ['Adelaide'], '', '', '']);
});
test('Filter table', function() {

View file

@ -14,25 +14,25 @@
module('Behaviour');
test('After filtering with `sydney`', function() {
tf.setFilterValue(0, 'sydney');
tf._filter();
tf.filter();
deepEqual(tf.getValidRows().length, 0, 'No matches');
});
test('After filtering with `Sydney`', function() {
tf.setFilterValue(0, 'Sydney');
tf._filter();
tf.filter();
deepEqual(tf.getValidRows().length>0, true, 'Matches');
});
test('After filtering with `ade`', function() {
tf.setFilterValue(0, 'ade');
tf._filter();
tf.filter();
deepEqual(tf.getValidRows().length, 0, 'No matches');
});
test('After filtering with `Ade`', function() {
tf.setFilterValue(0, 'Ade');
tf._filter();
tf.filter();
deepEqual(tf.getValidRows().length>0, true, 'Matches');
});

View file

@ -22,8 +22,30 @@ test('CheckList UI elements', function() {
deepEqual(flt.childNodes.length, 8, 'number of checklist options');
});
module('Behaviour');
test('Can filter on checkList change', function() {
var flt1 = id(tf.fltIds[3]);
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent('change', true, true);
tf.activeFlt = flt1;
tf.setFilterValue(3, '1.1');
flt1.dispatchEvent(evObj);
deepEqual(tf.getValidRows().length, 1, 'Table filtered');
deepEqual(tf.getFilteredData()[0][1][3], '1.1', 'Matched value');
});
test('Can select options', function() {
tf.clearFilters();
var flt1 = id(tf.fltIds[3]);
checkList.selectOptions(3, ['1.4', '.6']);
notEqual(flt1.getAttribute('value').indexOf('1.4'), -1, 'Option selected');
notEqual(flt1.getAttribute('value').indexOf('.6'), -1, 'Option selected');
});
test('TableFilter removed', function() {
tf.destroy();
deepEqual(id(tf.fltIds[3]), null, 'CheckList UL element');
});

View file

@ -19,14 +19,16 @@ test('Properties', function() {
deepEqual(clearButton.feature, 'btnReset', 'Feature name');
deepEqual(clearButton.enabled, true, 'Feature enabled');
deepEqual(clearButton.initialized, true, 'Feature enabled');
deepEqual(typeof clearButton.emitter, 'object',
'Feature has emitter instance');
deepEqual(typeof clearButton.config, 'object', 'TF configuration object');
deepEqual(typeof clearButton.init, 'function', 'Feature init method');
deepEqual(typeof clearButton.destroy, 'function', 'Feature destroy method');
deepEqual(typeof clearButton.reset, 'function', 'Feature reset method');
deepEqual(typeof clearButton.enable, 'function', 'Feature enable method');
deepEqual(typeof clearButton.disable, 'function', 'Feature enable method');
deepEqual(
typeof clearButton.isEnabled, 'function', 'Feature enable method');
deepEqual(typeof clearButton.isEnabled, 'function',
'Feature enable method');
});
test('Can destroy', function() {
clearButton.destroy();

View file

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TableFilter disable select filter onchange event</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" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<th>From</th>
<th>Destination</th>
<th>Road Distance (km)</th>
<th>By Air (hrs)</th>
<th>By Rail (hrs)</th>
</tr>
<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-disable-filter-onchange.js"></script>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
</body>
</html>

View file

@ -0,0 +1,40 @@
(function(win, TableFilter){
var id = function (id){ return document.getElementById(id); };
var tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
col_0: 'select',
col_1: 'multiple',
on_change: false
});
tf.init();
module('Sanity checks');
test('Disable onchange event on select filter', function() {
deepEqual(tf instanceof TableFilter, true, 'TableFilter type');
deepEqual(tf.onSlcChange, false, 'Onchange event disabled');
});
module('Behaviour');
test('Cannot filter on selection change', function() {
var flt0 = id(tf.fltIds[0]);
var flt1 = id(tf.fltIds[1]);
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent('change', true, true);
tf.setFilterValue(0, 'Sydney');
flt0.dispatchEvent(evObj);
tf.setFilterValue(1, 'Canberra');
flt1.dispatchEvent(evObj);
deepEqual(tf.getValidRows().length, 0, 'Table not filtered');
deepEqual(tf.nbHiddenRows, 0, 'No hidden rows');
});
module('Tear-down');
test('TableFilter removed', function() {
tf.destroy();
deepEqual(tf.hasGrid(), false, 'Filters removed');
});
})(window, TableFilter);

View file

@ -24,6 +24,30 @@ test('Drop-down UI elements', function() {
deepEqual(flt2.hasAttribute('multiple'), true, 'Multiple select exists');
});
module('Behaviour');
test('Can filter on drop-down change', function() {
var flt1 = id(tf.fltIds[3]);
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent('change', true, true);
tf.activeFlt = flt1;
tf.setFilterValue(3, '1.1');
flt1.dispatchEvent(evObj);
deepEqual(tf.getValidRows().length, 1, 'Table filtered');
deepEqual(tf.getFilteredData()[0][1][3], '1.1', 'Matched value');
});
test('Can select options', function() {
tf.clearFilters();
var flt1 = id(tf.fltIds[2]);
dropdown.selectOptions(2, ['872', '286']);
deepEqual(flt1.options[5].selected, true, 'Option selected');
deepEqual(flt1.options[6].selected, true, 'Option selected');
});
test('TableFilter removed', function() {
tf.destroy();
deepEqual(id(tf.fltIds[3]), null, 'Filter is removed');

78
test/test-emitter.html Normal file
View file

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TableFilter event emitter</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" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<th>From</th>
<th>Destination</th>
<th>Road Distance (km)</th>
<th>By Air (hrs)</th>
<th>By Rail (hrs)</th>
</tr>
<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-emitter.js"></script>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
</body>
</html>

57
test/test-emitter.js Normal file
View file

@ -0,0 +1,57 @@
var tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/'
});
tf.init();
module('Sanity checks');
test('Emitter instance', function() {
deepEqual(typeof tf.emitter, 'object', 'Emitter instanciated');
deepEqual(typeof tf.emitter.events, 'object', 'Emitter events property');
deepEqual(typeof tf.emitter.on, 'function', 'Emitter on method');
deepEqual(typeof tf.emitter.off, 'function', 'Emitter off method');
deepEqual(typeof tf.emitter.emit, 'function', 'Emitter emit method');
});
module('Behaviour');
test('Can subscribe', function(){
var emitter = tf.emitter;
var output = null;
emitter.on(['before-filtering'],
function(){ output = 'before-filtering'; });
tf.filter();
deepEqual(emitter.events['before-filtering'].length, 1,
'Expected number of listeners');
deepEqual(output, 'before-filtering', 'Expected output');
});
test('Can unsubscribe', function(){
var emitter = tf.emitter;
var output = null;
emitter.off(['before-filtering'],
function(){ output = 'before-filtering'; });
tf.filter();
deepEqual(emitter.events['before-filtering'].length, 0,
'Expected number of listeners');
deepEqual(output, null, 'Expected output');
});
test('Can emit', function(){
var emitter = tf.emitter;
var output = null;
emitter.on(['hello'], function(arg){ output = arg; });
emitter.emit('hello', 'world');
deepEqual(output, 'world', 'Event emitted');
});
module('Tear-down');
test('can destroy TableFilter DOM elements', function() {
tf.destroy();
deepEqual(tf.hasGrid(), false, 'Filters removed');
});

View file

@ -14,13 +14,13 @@
module('Behaviour');
test('After filtering with `syd`', function() {
tf.setFilterValue(0, 'syd');
tf._filter();
tf.filter();
deepEqual(tf.getValidRows().length, 0, 'No matches');
});
test('After filtering with `sydney`', function() {
tf.setFilterValue(0, 'sydney');
tf._filter();
tf.filter();
deepEqual(tf.getValidRows().length>0, true, 'Matches');
});
@ -42,14 +42,14 @@
test('After filtering with `syd`', function() {
tf.setFilterValue(0, 'syd');
tf.setFilterValue(1, 'bris');
tf._filter();
tf.filter();
deepEqual(tf.getValidRows().length, 0, 'No matches');
});
test('After filtering with `sydney`', function() {
tf.clearFilters();
tf.setFilterValue(0, 'sydney');
tf._filter();
tf.filter();
deepEqual(tf.getValidRows().length>0, true, 'Matches');
});

View file

@ -1,8 +1,7 @@
var tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
grid_layout: true,
sort: false
grid_layout: true
});
tf.init();
@ -14,9 +13,13 @@ test('GridLayout component', function() {
notEqual(gridLayout.tblCont, null, 'GridLayout main HTML table container element');
notEqual(gridLayout.headTblCont, null, 'GridLayout headers container element');
notEqual(gridLayout.headTbl, null, 'GridLayout headers HTML table');
deepEqual(tf.startRow, null, 'Optional startRow row index');
deepEqual(tf.refRow, 0, 'Reference row index');
deepEqual(tf.headersRow, 0, 'Headers row index');
deepEqual(tf.filtersRowIndex, 1, 'Filters row index');
});
test('Destroy GridLayout component', function() {
test('Destroy TableFilter', function() {
gridLayout.destroy();
deepEqual(gridLayout.tblMainCont, null, 'Main container element removed');
deepEqual(gridLayout.tblCont, null, 'Main HTML table container element removed');
@ -24,3 +27,10 @@ test('Destroy GridLayout component', function() {
deepEqual(gridLayout.headTbl, null, 'Headers HTML table element removed');
notEqual(gridLayout.sourceTblHtml, null, 'Table reference is kept');
});
test('Reset TableFilter', function() {
tf.destroy();
tf.init();
deepEqual(tf instanceof TableFilter, true, 'TableFilter type');
deepEqual(typeof gridLayout, 'object', 'GridLayout instanciated');
});

View file

@ -18,6 +18,7 @@ test('Properties', function() {
deepEqual(help.feature, 'help', 'Feature name');
deepEqual(help.enabled, true, 'Feature enabled');
deepEqual(help.initialized, true, 'Feature enabled');
deepEqual(typeof help.emitter, 'object', 'Feature has emitter instance');
deepEqual(typeof help.config, 'object', 'TF configuration object');
deepEqual(typeof help.init, 'function', 'Feature init method');
deepEqual(typeof help.destroy, 'function', 'Feature destroy method');
@ -87,6 +88,19 @@ test('Re-set UI', function() {
notEqual(helpBtn.innerHTML.indexOf('→Help←'), -1, 'Help button text');
});
module('Destroy and re-init with help property undefined');
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.init();
notEqual(help.btn, null, 'btn property');
});
module('Tear-down');
test('can destroy TableFilter DOM elements', function() {
tf.destroy();

View file

@ -16,20 +16,34 @@ test('HighlightKeyword component', function() {
test('Highlighted keywords', function() {
tf.setFilterValue(1, 'Perth');
tf.setFilterValue(3, '3.1');
tf._filter();
tf.filter();
deepEqual(highlightKeyword.highlightedNodes.length,
2, 'Number of highlighted words');
deepEqual(tf.tbl.querySelectorAll('.keyword').length, 2,
'Number of applied CSS classes');
tf._clearFilters();
tf._filter();
tf.clearFilters();
deepEqual(highlightKeyword.highlightedNodes.length,
0, 'Number of highlighted words');
// TODO: uncomment when fixed
// deepEqual(tf.tbl.querySelectorAll('.keyword').length, 0,
// 'Number of applied CSS classes');
});
module('Reset feature');
test('can destroy and init TableFilter', function() {
tf.destroy();
tf.init();
deepEqual(typeof highlightKeyword, 'object', 'Instanciated');
deepEqual(highlightKeyword.highlightedNodes instanceof Array,
true, 'Property check');
});
module('Tear-down');
test('can destroy TableFilter DOM elements', function() {
test('can destroy TableFilter DOM elements and clean highlighted words',
function() {
tf.setFilterValue(1, 'Perth');
tf._filter();
tf.filter();
tf.destroy();
deepEqual(tf.hasGrid(), false, 'Filters removed');
deepEqual(highlightKeyword.highlightedNodes.length,

View file

@ -12,14 +12,14 @@
tf.init();
tf.setFilterValue(0, 'Sydney');
tf.getFilterElement(0).focus();
tf._filter();
tf.filter();
module('Sanity checks');
test('Linked filters feature', function() {
deepEqual(tf instanceof TableFilter, true, 'TableFilter instantiated');
deepEqual(tf.linkedFilters, true, 'Linked filters enabled');
tf._clearFilters();
tf.clearFilters();
tf.onAfterFilter = null;
tf.destroy();
tf = null;
@ -54,7 +54,7 @@
tf.init();
tf.setFilterValue(0, 'Sydney');
tf.getFilterElement(0).focus();
tf._filter();
tf.filter();
}
function testExcludedOptions(tf){
@ -75,7 +75,7 @@
});
tf.onAfterFilter = null;
tf.clearFilters();
setTimeout(tf.clearFilters, 0);
}
// Tests for https://github.com/koalyptus/TableFilter/pull/42 issue

View file

@ -18,7 +18,7 @@ var flt3Cont = id(flt3ContId);
function buildChecklist(tf, colIdx){
var checkList = tf.feature('checkList');
checkList._build(colIdx);
checkList.build(colIdx);
checkList.checkListDiv[colIdx].onclick = null;
checkList.checkListDiv[colIdx].title = '';
}

View file

@ -63,10 +63,6 @@ test('Can show loader', function() {
loader.show('');
deepEqual(loader.loaderDiv.style.display, '', 'Loader is displayed');
});
test('Can show loader', function() {
loader.show('');
deepEqual(loader.loaderDiv.style.display, '', 'Loader is displayed');
});
module('Tear-down');
test('can destroy TableFilter DOM elements', function() {

View file

@ -11,6 +11,7 @@
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
deepEqual(tf.getFilterElement(0), null,
'No filter element for column 0');
deepEqual(tf.refRow, 1, 'Reference row index');
});
test('Paging with no filters', function() {
@ -25,6 +26,7 @@
tf.init();
deepEqual(tf.getFilterElement(4), null,
'No filter element for column 4');
deepEqual(tf.refRow, 1, 'Reference row index');
});
test('Grid layout with no filters', function() {
@ -39,6 +41,16 @@
tf.init();
deepEqual(tf.getFilterElement(2), null,
'No filter element for column 2');
deepEqual(tf.refRow, 0, 'Reference row index');
tf.setFilterValue(1, 'Bris');
deepEqual(tf.getValidRows().length, 0, 'does not fail on setFilterValue');
});
module('Tear-down');
test('TableFilter removed', function() {
tf.destroy();
deepEqual(tf.hasGrid(), false, 'Filters removed');
});
})(window, TableFilter);

View file

@ -19,6 +19,8 @@ test('No Results Feature', function() {
deepEqual(noResults.feature, 'noResults', 'Feature name');
deepEqual(noResults.enabled, true, 'Feature enabled');
deepEqual(noResults.initialized, true, 'Feature initialized');
deepEqual(typeof noResults.emitter, 'object',
'Feature has emitter instance');
deepEqual(typeof noResults.config, 'object', 'TF configuration object');
deepEqual(typeof noResults.init, 'function', 'Feature init method');
deepEqual(typeof noResults.destroy, 'function',
@ -60,7 +62,7 @@ test('No Results Feature', function() {
module('Behaviour');
test('Can display no results message', function() {
tf.setFilterValue(0, 'sadasd');
tf._filter();
tf.filter();
deepEqual(tf.getValidRows().length, 0, 'Filtered rows number');
deepEqual(noResults.cont.innerHTML, 'No results', 'No results message');
deepEqual(noResults.cont.style.display, 'block',
@ -105,7 +107,7 @@ test('External container sanity checks', function() {
test('Can display external no results message', function() {
tfCustom.setFilterValue(0, 'sadasd');
tfCustom._filter();
tfCustom.filter();
deepEqual(noResultsCustom.cont.innerHTML, '<h3>No results found</h3>',
'No results message markup');
deepEqual(noResultsCustom.cont.style.display, 'block',
@ -145,7 +147,7 @@ test('Sanity checks', function() {
test('Can display no results message in grid layout', function() {
tfGl.setFilterValue(0, 'sadasd');
tfGl._filter();
tfGl.filter();
deepEqual(noResultsGl.cont.innerHTML, 'No results',
'No results message');
deepEqual(noResultsGl.cont.style.display, 'block',

View file

@ -23,6 +23,7 @@ test('Properties', function() {
deepEqual(paging.feature, 'paging', 'Feature name');
deepEqual(paging.enabled, true, 'Feature enabled');
deepEqual(paging.initialized, true, 'Feature enabled');
deepEqual(typeof paging.emitter, 'object', 'Feature has emitter instance');
deepEqual(typeof paging.config, 'object', 'TF configuration object');
deepEqual(typeof paging.init, 'function', 'Feature init method');
deepEqual(typeof paging.destroy, 'function', 'Feature destroy method');
@ -209,6 +210,15 @@ test('Set results per page', function() {
deepEqual(paging.nbPages, 2, 'Expected number of pages');
});
module('Reset feature');
test('can destroy and init TableFilter', function() {
tf.destroy();
tf.init();
notEqual(paging, null, 'Paging instanciated');
deepEqual(paging.pagingLength, 2, 'Paging length');
deepEqual(paging.nbPages, 4, 'Number of pages');
});
module('Tear-down');
test('can destroy TableFilter DOM elements', function() {
tf.destroy();

View file

@ -16,6 +16,7 @@ test('Pop-up filter component', function() {
notEqual(popupFilter, null, 'PopupFilter instanciated');
deepEqual(popupFilter.popUpFltElms instanceof Array,
true, 'Type of popUpFltElms property');
deepEqual(tf.headersRow, 1, 'Headers row index');
// issue 99: getHeadersText for pick-list filter types
deepEqual(
tf.getHeadersText()[2],
@ -45,6 +46,32 @@ test('Pop-up filter UI elements', function() {
deepEqual(fltIcn3, undefined, 'Filter icon does not exist for column 4');
});
test('Pop-up filter state after filtering', function(){
var fltIcn0 = popupFilter.popUpFltImgs[0];
tf.setFilterValue(0, 'syd');
tf.filter();
deepEqual(fltIcn0.src.indexOf('icn_filterActive') !== -1,
true, 'Icon state');
});
test('Pop-up filter state after clearing', function(){
var fltIcn0 = popupFilter.popUpFltImgs[0];
var fltIcn1 = popupFilter.popUpFltImgs[1];
var fltIcn2 = popupFilter.popUpFltImgs[2];
var fltIcn3 = popupFilter.popUpFltImgs[3];
tf.clearFilters();
deepEqual(fltIcn0.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
deepEqual(fltIcn1.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
deepEqual(fltIcn2.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
deepEqual(fltIcn3.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
});
test('TableFilter removed', function() {
tf.destroy();
var fltIcn1 = popupFilter.popUpFltImgs[3];
@ -76,6 +103,7 @@ test('Re-instantiated with grid-layout', function() {
notEqual(popupFilter, null, 'PopupFilter instanciated');
deepEqual(popupFilter.popUpFltElms instanceof Array,
true, 'Type of popUpFltElms property');
deepEqual(tf.headersRow, 0, 'Headers row index');
// issue 99: getHeadersText for pick-list filter types
deepEqual(
tf.getHeadersText()[2],
@ -105,6 +133,34 @@ test('Pop-up filter UI elements with grid-layout', function() {
deepEqual(fltIcn3, undefined, 'Filter icon does not exist for column 4');
});
test('Pop-up filter state after filtering', function(){
var popupFilter = tf.feature('popupFilter');
var fltIcn0 = popupFilter.popUpFltImgs[0];
tf.setFilterValue(0, 'syd');
tf.filter();
deepEqual(fltIcn0.src.indexOf('icn_filterActive') !== -1,
true, 'Icon state');
});
test('Pop-up filter state after clearing', function(){
var popupFilter = tf.feature('popupFilter');
var fltIcn0 = popupFilter.popUpFltImgs[0];
var fltIcn1 = popupFilter.popUpFltImgs[1];
var fltIcn2 = popupFilter.popUpFltImgs[2];
var fltIcn3 = popupFilter.popUpFltImgs[3];
tf.clearFilters();
deepEqual(fltIcn0.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
deepEqual(fltIcn1.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
deepEqual(fltIcn2.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
deepEqual(fltIcn3.src.indexOf('icn_filterActive') === -1,
true, 'Icon state');
});
module('Feature interface');
test('Properties', function() {
var popupFilter = tf.feature('popupFilter');
@ -114,6 +170,8 @@ test('Properties', function() {
deepEqual(popupFilter.feature, 'popupFilters', 'Feature name');
deepEqual(popupFilter.enabled, true, 'Feature enabled');
deepEqual(popupFilter.initialized, true, 'Feature enabled');
deepEqual(typeof popupFilter.emitter, 'object',
'Feature has emitter instance');
deepEqual(typeof popupFilter.config, 'object', 'TF configuration object');
deepEqual(typeof popupFilter.init, 'function', 'Feature init method');
deepEqual(typeof popupFilter.destroy, 'function', 'Feature destroy method');

View file

@ -18,6 +18,8 @@ test('Properties', function() {
deepEqual(rowsCounter.feature, 'rowsCounter', 'Feature name');
deepEqual(rowsCounter.enabled, true, 'Feature enabled');
deepEqual(rowsCounter.initialized, true, 'Feature enabled');
deepEqual(typeof rowsCounter.emitter, 'object',
'Feature has emitter instance');
deepEqual(typeof rowsCounter.config, 'object', 'TF configuration object');
deepEqual(typeof rowsCounter.init, 'function', 'Feature init method');
deepEqual(typeof rowsCounter.destroy, 'function', 'Feature destroy method');

View file

@ -18,6 +18,8 @@ test('Properties', function() {
deepEqual(statusBar.feature, 'statusBar', 'Feature name');
deepEqual(statusBar.enabled, true, 'Feature enabled');
deepEqual(statusBar.initialized, true, 'Feature enabled');
deepEqual(typeof statusBar.emitter, 'object',
'Feature has emitter instance');
deepEqual(typeof statusBar.config, 'object', 'TF configuration object');
deepEqual(typeof statusBar.init, 'function', 'Feature init method');
deepEqual(typeof statusBar.destroy, 'function', 'Feature destroy method');

View file

@ -9,6 +9,24 @@ function removeCookie(name){
document.cookie = name + '=' + expire;
}
function readCookie(name){
var cookieValue = '',
search = name + '=';
if(document.cookie.length > 0){
var cookie = document.cookie,
offset = cookie.indexOf(search);
if(offset !== -1){
offset += search.length;
var end = cookie.indexOf(';', offset);
if(end === -1){
end = cookie.length;
}
cookieValue = unescape(cookie.substring(offset, end));
}
}
return cookieValue;
}
var tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
paging: true,
@ -42,7 +60,6 @@ test('Page number value', function() {
var cookieName = tf.pgNbCookie;
deepEqual(tf.feature('store').getPageNb(cookieName), '2', 'Page number value');
tf.clearFilters();
tf.filter();
});
module('Check page length persistence');
@ -53,21 +70,86 @@ test('Page length value', function() {
var cookieName = tf.pgLenCookie;
deepEqual(tf.feature('store').getPageLength(cookieName), '2', 'Page length value');
tf.clearFilters();
tf.filter();
});
module('Check filters persistence');
test('Filters value', function() {
test('Filters value in cookie', function() {
tf.setFilterValue(0, 'Sydney');
tf.setFilterValue(3, '1.5');
tf.filter();
var cookieName = tf.fltsValuesCookie;
deepEqual(tf.feature('store').getFilterValues(cookieName)[0], 'Sydney', 'Filter 0 value');
deepEqual(tf.feature('store').getFilterValues(cookieName)[3], '1.5', 'Filter 3 value');
tf.destroy();
});
test('Filters value in cookie', function() {
tf.setFilterValue(0, 'Sydney');
tf.setFilterValue(3, '1.5');
tf.filter();
var cookieName = tf.fltsValuesCookie;
deepEqual(tf.feature('store').getFilterValues(cookieName)[0], 'Sydney', 'Filter 0 value');
deepEqual(tf.feature('store').getFilterValues(cookieName)[3], '1.5', 'Filter 3 value');
});
test('Filters value with operators in cookie', function() {
tf.setFilterValue(0, '');
tf.setFilterValue(1, 'Canberra || Perth');
tf.setFilterValue(3, '>.6');
tf.filter();
var cookieName = tf.fltsValuesCookie;
deepEqual(tf.feature('store').getFilterValues(cookieName)[0], ' ', 'Filter 0 value');
deepEqual(tf.feature('store').getFilterValues(cookieName)[1], 'Canberra || Perth', 'Filter 1 value');
deepEqual(tf.feature('store').getFilterValues(cookieName)[3], '>.6', 'Filter 3 value');
deepEqual(tf.getValidRows().length, 1, 'Expected nb of filtered rows');
});
test('Apply cookie filters value', function() {
tf.setFilterValue(0, 'Adelaide');
tf.setFilterValue(3, '>=2');
tf.filter();
tf.destroy();
tf.init();
deepEqual(tf.getFilterValue(0), 'Adelaide', 'Applied filter value');
deepEqual(tf.getFilterValue(3), '>=2', 'Applied filter value');
});
test('Can remove cookies on clearFilters', function() {
tf.clearFilters();
deepEqual(readCookie(tf.fltsValuesCookie), '',
'fltsValuesCookie cookie removed');
deepEqual(readCookie(tf.pgLenCookie), '', 'pgLenCookie cookie removed');
deepEqual(readCookie(tf.pgNbCookie), '', 'pgNbCookie cookie removed');
});
module('Multiple and checklist filters persistence');
test('Filters value in cookie', function() {
tf.destroy();
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
remember_grid_values: true,
col_0: 'multiple',
col_1: 'checklist'
});
tf.init();
tf.setFilterValue(0, ['Sydney', 'Adelaide']);
tf.setFilterValue(1, ['Alice Springs', 'Brisbane']);
tf.filter();
var cookieName = tf.fltsValuesCookie;
deepEqual(tf.feature('store').getFilterValues(cookieName)[0], 'Adelaide || Sydney', 'Filter 0 value');
deepEqual(tf.feature('store').getFilterValues(cookieName)[1], 'Alice Springs || Brisbane', 'Filter 1 value');
deepEqual(tf.getValidRows().length, 3, 'Expected nb of filtered rows');
});
module('Tear-down');
test('TableFilter removed', function() {
tf.destroy();
removeCookie(tf.fltsValuesCookie);
removeCookie(tf.pgNbCookie);
removeCookie(tf.pgLenCookie);
});
deepEqual(tf.hasGrid(), false, 'Filters removed');
});

80
test/test-watermark.html Normal file
View file

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TableFilter watermark 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-watermark.js"></script>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
</body>
</html>

81
test/test-watermark.js Normal file
View file

@ -0,0 +1,81 @@
(function(win, TableFilter){
var tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
watermark: 'foobar'
});
tf.init();
module('Sanity checks');
test('Watermark properties', function() {
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
deepEqual(tf.watermark, 'foobar', 'Property value');
deepEqual(tf.isWatermarkArray, false,
'Type: same watermark for all filters');
});
test('DOM element', function(){
var flt0 = tf.getFilterElement(0);
var flt1 = tf.getFilterElement(3);
deepEqual(flt0.placeholder, 'foobar', 'filter`s placeholder value');
deepEqual(flt1.placeholder, 'foobar', 'filter`s placeholder value');
});
module('Per column watermark');
test('Sanity checks', function() {
tf.destroy();
tf = new TableFilter('demo', {
base_path: '../dist/tablefilter/',
watermark: ['City', 'City', 'Distance', 'Time', 'Time']
});
tf.init();
deepEqual(tf instanceof TableFilter, true, 'TableFilter instanciated');
deepEqual(tf.isWatermarkArray, true, 'Type: watermark array');
deepEqual(
tf.watermark,
['City', 'City', 'Distance', 'Time', 'Time'],
'Property value'
);
});
test('DOM element', function(){
deepEqual(
tf.getFilterElement(0).placeholder,
'City',
'filter`s placeholder value'
);
deepEqual(
tf.getFilterElement(1).placeholder,
'City',
'filter`s placeholder value'
);
deepEqual(
tf.getFilterElement(2).placeholder,
'Distance',
'filter`s placeholder value'
);
deepEqual(
tf.getFilterElement(3).placeholder,
'Time',
'filter`s placeholder value'
);
deepEqual(
tf.getFilterElement(4).placeholder,
'Time',
'filter`s placeholder value'
);
});
module('Tear-down');
test('TableFilter removed', function() {
tf.destroy();
deepEqual(tf.hasGrid(), false, 'Filters removed');
deepEqual(
tf.watermark,
['City', 'City', 'Distance', 'Time', 'Time'],
'Property value'
);
});
})(window, TableFilter);