@@ -627,7 +627,7 @@
- source
+ source
@@ -688,7 +688,7 @@
- source
+ source
@@ -728,7 +728,7 @@
- source
+ source
@@ -768,7 +768,7 @@
- source
+ source
@@ -808,7 +808,7 @@
- source
+ source
@@ -848,7 +848,7 @@
- source
+ source
@@ -888,7 +888,7 @@
- source
+ source
@@ -928,7 +928,7 @@
- source
+ source
@@ -968,7 +968,7 @@
- source
+ source
@@ -1008,7 +1008,7 @@
- source
+ source
@@ -1048,7 +1048,7 @@
- source
+ source
@@ -1091,7 +1091,7 @@
- source
+ source
@@ -1159,7 +1159,7 @@
- source
+ source
@@ -1238,7 +1238,7 @@
- source
+ source
@@ -1317,7 +1317,7 @@
- source
+ source
@@ -1357,7 +1357,7 @@
- source
+ source
@@ -1429,7 +1429,7 @@
- source
+ source
@@ -1469,7 +1469,7 @@
- source
+ source
@@ -1525,7 +1525,7 @@
- source
+ source
diff --git a/docs/class/src/modules/feature.js~Feature.html b/docs/class/src/modules/feature.js~Feature.html
index cba5d239..3d68bf99 100644
--- a/docs/class/src/modules/feature.js~Feature.html
+++ b/docs/class/src/modules/feature.js~Feature.html
@@ -3,7 +3,7 @@
-
Feature | tablefilter v0.1.10 API Document
+
Feature | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/gridLayout.js~GridLayout.html b/docs/class/src/modules/gridLayout.js~GridLayout.html
index 33224a25..0873492b 100644
--- a/docs/class/src/modules/gridLayout.js~GridLayout.html
+++ b/docs/class/src/modules/gridLayout.js~GridLayout.html
@@ -3,7 +3,7 @@
-
GridLayout | tablefilter v0.1.10 API Document
+
GridLayout | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/help.js~Help.html b/docs/class/src/modules/help.js~Help.html
index f77bc305..f2b4ad7d 100644
--- a/docs/class/src/modules/help.js~Help.html
+++ b/docs/class/src/modules/help.js~Help.html
@@ -3,7 +3,7 @@
-
Help | tablefilter v0.1.10 API Document
+
Help | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/highlightKeywords.js~HighlightKeyword.html b/docs/class/src/modules/highlightKeywords.js~HighlightKeyword.html
index 82b59e51..1165d0a6 100644
--- a/docs/class/src/modules/highlightKeywords.js~HighlightKeyword.html
+++ b/docs/class/src/modules/highlightKeywords.js~HighlightKeyword.html
@@ -3,7 +3,7 @@
-
HighlightKeyword | tablefilter v0.1.10 API Document
+
HighlightKeyword | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/loader.js~Loader.html b/docs/class/src/modules/loader.js~Loader.html
index 17e506aa..54028c41 100644
--- a/docs/class/src/modules/loader.js~Loader.html
+++ b/docs/class/src/modules/loader.js~Loader.html
@@ -3,7 +3,7 @@
-
Loader | tablefilter v0.1.10 API Document
+
Loader | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/noResults.js~NoResults.html b/docs/class/src/modules/noResults.js~NoResults.html
index 68410176..a5eacfa2 100644
--- a/docs/class/src/modules/noResults.js~NoResults.html
+++ b/docs/class/src/modules/noResults.js~NoResults.html
@@ -3,7 +3,7 @@
-
NoResults | tablefilter v0.1.10 API Document
+
NoResults | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/paging.js~Paging.html b/docs/class/src/modules/paging.js~Paging.html
index b23e8c4f..eab02472 100644
--- a/docs/class/src/modules/paging.js~Paging.html
+++ b/docs/class/src/modules/paging.js~Paging.html
@@ -3,7 +3,7 @@
-
Paging | tablefilter v0.1.10 API Document
+
Paging | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/popupFilter.js~PopupFilter.html b/docs/class/src/modules/popupFilter.js~PopupFilter.html
index 2854289a..956225f3 100644
--- a/docs/class/src/modules/popupFilter.js~PopupFilter.html
+++ b/docs/class/src/modules/popupFilter.js~PopupFilter.html
@@ -3,7 +3,7 @@
-
PopupFilter | tablefilter v0.1.10 API Document
+
PopupFilter | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/rowsCounter.js~RowsCounter.html b/docs/class/src/modules/rowsCounter.js~RowsCounter.html
index 6eface77..32585c60 100644
--- a/docs/class/src/modules/rowsCounter.js~RowsCounter.html
+++ b/docs/class/src/modules/rowsCounter.js~RowsCounter.html
@@ -3,7 +3,7 @@
-
RowsCounter | tablefilter v0.1.10 API Document
+
RowsCounter | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/statusBar.js~StatusBar.html b/docs/class/src/modules/statusBar.js~StatusBar.html
index e4141388..03c1c54c 100644
--- a/docs/class/src/modules/statusBar.js~StatusBar.html
+++ b/docs/class/src/modules/statusBar.js~StatusBar.html
@@ -3,7 +3,7 @@
-
StatusBar | tablefilter v0.1.10 API Document
+
StatusBar | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/modules/store.js~Store.html b/docs/class/src/modules/store.js~Store.html
index b6f68ba3..0f2df7da 100644
--- a/docs/class/src/modules/store.js~Store.html
+++ b/docs/class/src/modules/store.js~Store.html
@@ -3,7 +3,7 @@
-
Store | tablefilter v0.1.10 API Document
+
Store | tablefilter v0.1.11 API Document
diff --git a/docs/class/src/tablefilter.js~TableFilter.html b/docs/class/src/tablefilter.js~TableFilter.html
index 55fe614d..8bcfd6ff 100644
--- a/docs/class/src/tablefilter.js~TableFilter.html
+++ b/docs/class/src/tablefilter.js~TableFilter.html
@@ -3,7 +3,7 @@
-
TableFilter | tablefilter v0.1.10 API Document
+
TableFilter | tablefilter v0.1.11 API Document
diff --git a/docs/dump.json b/docs/dump.json
index dd981ea2..e6337f73 100644
--- a/docs/dump.json
+++ b/docs/dump.json
@@ -3907,7 +3907,27 @@
"access": null,
"description": null,
"lineNumber": 1,
- "content": "import {Feature} from './feature';\nimport Dom from '../dom';\nimport Arr from '../array';\nimport Str from '../string';\nimport Sort from '../sort';\nimport Event from '../event';\n\nexport class CheckList extends Feature{\n\n /**\n * Checklist UI component\n * @param {Object} tf TableFilter instance\n */\n constructor(tf){\n super(tf, 'checkList');\n\n // Configuration object\n let f = tf.config();\n\n this.checkListDiv = []; //checklist container div\n //defines css class for div containing checklist filter\n this.checkListDivCssClass = f.div_checklist_css_class ||\n 'div_checklist';\n //defines css class for checklist filters\n this.checkListCssClass = f.checklist_css_class || 'flt_checklist';\n //defines css class for checklist item (li)\n this.checkListItemCssClass = f.checklist_item_css_class ||\n 'flt_checklist_item';\n //defines css class for selected checklist item (li)\n this.checkListSlcItemCssClass = f.checklist_selected_item_css_class ||\n 'flt_checklist_slc_item';\n //Load on demand text\n this.activateCheckListTxt = f.activate_checklist_text ||\n 'Click to load filter data';\n //defines css class for checklist filters\n this.checkListItemDisabledCssClass =\n f.checklist_item_disabled_css_class ||\n 'flt_checklist_item_disabled';\n this.enableCheckListResetFilter =\n f.enable_checklist_reset_filter===false ? false : true;\n //checklist filter container div\n this.prfxCheckListDiv = 'chkdiv_';\n\n this.isCustom = null;\n this.opts = null;\n this.optsTxt = null;\n this.excludedOpts = null;\n }\n\n onChange(evt){\n let elm = evt.target;\n let tf = this.tf;\n tf.activeFilterId = elm.getAttribute('id');\n tf.activeFlt = Dom.id(tf.activeFilterId);\n tf.filter();\n }\n\n optionClick(evt){\n this.setCheckListValues(evt.target);\n this.onChange(evt);\n }\n\n onCheckListClick(evt){\n let elm = Event.target(evt);\n if(this.tf.loadFltOnDemand && elm.getAttribute('filled') === '0'){\n let ct = elm.getAttribute('ct');\n let div = this.checkListDiv[ct];\n this.build(ct);\n Event.remove(div, 'click', (evt)=> this.onCheckListClick(evt));\n }\n }\n\n /**\n * Initialize checklist filter\n * @param {Number} colIndex Column index\n * @param {Boolean} isExternal External filter flag\n * @param {DOMElement} container Dom element containing the filter\n */\n init(colIndex, isExternal, container){\n let tf = this.tf;\n let externalFltTgtId = isExternal ?\n tf.externalFltTgtIds[colIndex] : null;\n\n let divCont = Dom.create('div',\n ['id', this.prfxCheckListDiv+colIndex+'_'+tf.id],\n ['ct', colIndex], ['filled', '0']);\n divCont.className = this.checkListDivCssClass;\n\n //filter is appended in desired element\n if(externalFltTgtId){\n Dom.id(externalFltTgtId).appendChild(divCont);\n tf.externalFltEls.push(divCont);\n } else {\n container.appendChild(divCont);\n }\n\n this.checkListDiv[colIndex] = divCont;\n tf.fltIds.push(tf.prfxFlt+colIndex+'_'+tf.id);\n\n if(!tf.loadFltOnDemand){\n this.build(colIndex);\n } else {\n Event.add(divCont, 'click', (evt)=> this.onCheckListClick(evt));\n divCont.appendChild(Dom.text(this.activateCheckListTxt));\n }\n\n this.emitter.on(\n ['build-checklist-filter'],\n (tf, colIndex, isExternal)=> this.build(colIndex, isExternal)\n );\n\n this.emitter.on(\n ['select-checklist-options'],\n (tf, colIndex, values)=> this.selectOptions(colIndex, values)\n );\n\n this.initialized = true;\n }\n\n /**\n * Build checklist UI\n * @param {Number} colIndex Column index\n * @param {Boolean} isExternal Render in external container\n * @param {String} extFltId External container id\n */\n build(colIndex, isExternal=false, extFltId=null){\n let tf = this.tf;\n colIndex = parseInt(colIndex, 10);\n\n this.emitter.emit('before-populating-filter', tf, colIndex);\n\n this.opts = [];\n this.optsTxt = [];\n\n let divFltId = this.prfxCheckListDiv+colIndex+'_'+tf.id;\n if((!Dom.id(divFltId) && !isExternal) ||\n (!Dom.id(extFltId) && isExternal)){\n return;\n }\n\n let flt = !isExternal ? this.checkListDiv[colIndex] : Dom.id(extFltId);\n let ul = Dom.create(\n 'ul', ['id', tf.fltIds[colIndex]], ['colIndex', colIndex]);\n ul.className = this.checkListCssClass;\n Event.add(ul, 'change', (evt)=> this.onChange(evt));\n\n let rows = tf.tbl.rows;\n this.isCustom = tf.isCustomOptions(colIndex);\n\n let activeFlt;\n if(tf.linkedFilters && tf.activeFilterId){\n activeFlt = tf.activeFilterId.split('_')[0];\n activeFlt = activeFlt.split(tf.prfxFlt)[1];\n }\n\n let filteredDataCol = [];\n if(tf.linkedFilters && tf.disableExcludedOptions){\n this.excludedOpts = [];\n }\n\n for(let k=tf.refRow; k
this.optionClick(evt));\n }\n ul.appendChild(li);\n\n if(val === ''){\n //item is hidden\n li.style.display = 'none';\n }\n }\n }\n\n /**\n * Add checklist header option\n * @param {Number} colIndex Column index\n * @param {Object} ul Ul element\n */\n addTChecks(colIndex, ul){\n let tf = this.tf;\n let chkCt = 1;\n let li0 = Dom.createCheckItem(\n tf.fltIds[colIndex]+'_0', '', tf.displayAllText);\n li0.className = this.checkListItemCssClass;\n ul.appendChild(li0);\n\n Event.add(li0.check, 'click', (evt)=> this.optionClick(evt));\n\n if(!this.enableCheckListResetFilter){\n li0.style.display = 'none';\n }\n\n if(tf.enableEmptyOption){\n let li1 = Dom.createCheckItem(\n tf.fltIds[colIndex]+'_1', tf.emOperator, tf.emptyText);\n li1.className = this.checkListItemCssClass;\n ul.appendChild(li1);\n Event.add(li1.check, 'click', (evt)=> this.optionClick(evt));\n chkCt++;\n }\n\n if(tf.enableNonEmptyOption){\n let li2 = Dom.createCheckItem(\n tf.fltIds[colIndex]+'_2',\n tf.nmOperator,\n tf.nonEmptyText\n );\n li2.className = this.checkListItemCssClass;\n ul.appendChild(li2);\n Event.add(li2.check, 'click', (evt)=> this.optionClick(evt));\n chkCt++;\n }\n return chkCt;\n }\n\n /**\n * Store checked options in DOM element attribute\n * @param {Object} o checklist option DOM element\n */\n setCheckListValues(o){\n if(!o){\n return;\n }\n let tf = this.tf;\n let chkValue = o.value; //checked item value\n let chkIndex = parseInt(o.id.split('_')[2], 10);\n let filterTag = 'ul', itemTag = 'li';\n let n = o;\n\n //ul tag search\n while(Str.lower(n.nodeName)!==filterTag){\n n = n.parentNode;\n }\n\n let li = n.childNodes[chkIndex];\n let colIndex = n.getAttribute('colIndex');\n let fltValue = n.getAttribute('value'); //filter value (ul tag)\n let fltIndexes = n.getAttribute('indexes'); //selected items (ul tag)\n\n if(o.checked){\n //show all item\n if(chkValue===''){\n if((fltIndexes && fltIndexes!=='')){\n //items indexes\n let indSplit = fltIndexes.split(tf.separator);\n //checked items loop\n for(let u=0; u this.build(colIndex, isExternal)\n );\n this.emitter.off(\n ['select-checklist-options'],\n (tf, colIndex, values)=> this.selectOptions(colIndex, values)\n );\n }\n}\n"
+ "content": "import {Feature} from './feature';\nimport Dom from '../dom';\nimport Arr from '../array';\nimport Str from '../string';\nimport Sort from '../sort';\nimport Event from '../event';\n\nconst SORT_ERROR = 'Filter options for column {0} cannot be sorted in ' +\n '{1} manner.';\n\nexport class CheckList extends Feature{\n\n /**\n * Checklist UI component\n * @param {Object} tf TableFilter instance\n */\n constructor(tf){\n super(tf, 'checkList');\n\n // Configuration object\n let f = tf.config();\n\n this.checkListDiv = []; //checklist container div\n //defines css class for div containing checklist filter\n this.checkListDivCssClass = f.div_checklist_css_class ||\n 'div_checklist';\n //defines css class for checklist filters\n this.checkListCssClass = f.checklist_css_class || 'flt_checklist';\n //defines css class for checklist item (li)\n this.checkListItemCssClass = f.checklist_item_css_class ||\n 'flt_checklist_item';\n //defines css class for selected checklist item (li)\n this.checkListSlcItemCssClass = f.checklist_selected_item_css_class ||\n 'flt_checklist_slc_item';\n //Load on demand text\n this.activateCheckListTxt = f.activate_checklist_text ||\n 'Click to load filter data';\n //defines css class for checklist filters\n this.checkListItemDisabledCssClass =\n f.checklist_item_disabled_css_class ||\n 'flt_checklist_item_disabled';\n this.enableCheckListResetFilter =\n f.enable_checklist_reset_filter===false ? false : true;\n //checklist filter container div\n this.prfxCheckListDiv = 'chkdiv_';\n\n this.isCustom = null;\n this.opts = null;\n this.optsTxt = null;\n this.excludedOpts = null;\n }\n\n onChange(evt){\n let elm = evt.target;\n let tf = this.tf;\n tf.activeFilterId = elm.getAttribute('id');\n tf.activeFlt = Dom.id(tf.activeFilterId);\n tf.filter();\n }\n\n optionClick(evt){\n this.setCheckListValues(evt.target);\n this.onChange(evt);\n }\n\n onCheckListClick(evt){\n let elm = Event.target(evt);\n if(this.tf.loadFltOnDemand && elm.getAttribute('filled') === '0'){\n let ct = elm.getAttribute('ct');\n let div = this.checkListDiv[ct];\n this.build(ct);\n Event.remove(div, 'click', (evt)=> this.onCheckListClick(evt));\n }\n }\n\n /**\n * Initialize checklist filter\n * @param {Number} colIndex Column index\n * @param {Boolean} isExternal External filter flag\n * @param {DOMElement} container Dom element containing the filter\n */\n init(colIndex, isExternal, container){\n let tf = this.tf;\n let externalFltTgtId = isExternal ?\n tf.externalFltTgtIds[colIndex] : null;\n\n let divCont = Dom.create('div',\n ['id', this.prfxCheckListDiv+colIndex+'_'+tf.id],\n ['ct', colIndex], ['filled', '0']);\n divCont.className = this.checkListDivCssClass;\n\n //filter is appended in desired element\n if(externalFltTgtId){\n Dom.id(externalFltTgtId).appendChild(divCont);\n tf.externalFltEls.push(divCont);\n } else {\n container.appendChild(divCont);\n }\n\n this.checkListDiv[colIndex] = divCont;\n tf.fltIds.push(tf.prfxFlt+colIndex+'_'+tf.id);\n\n if(!tf.loadFltOnDemand){\n this.build(colIndex);\n } else {\n Event.add(divCont, 'click', (evt)=> this.onCheckListClick(evt));\n divCont.appendChild(Dom.text(this.activateCheckListTxt));\n }\n\n this.emitter.on(\n ['build-checklist-filter'],\n (tf, colIndex, isExternal)=> this.build(colIndex, isExternal)\n );\n\n this.emitter.on(\n ['select-checklist-options'],\n (tf, colIndex, values)=> this.selectOptions(colIndex, values)\n );\n\n this.initialized = true;\n }\n\n /**\n * Build checklist UI\n * @param {Number} colIndex Column index\n * @param {Boolean} isExternal Render in external container\n * @param {String} extFltId External container id\n */\n build(colIndex, isExternal=false, extFltId=null){\n let tf = this.tf;\n colIndex = parseInt(colIndex, 10);\n\n this.emitter.emit('before-populating-filter', tf, colIndex);\n\n this.opts = [];\n this.optsTxt = [];\n\n let divFltId = this.prfxCheckListDiv+colIndex+'_'+tf.id;\n if((!Dom.id(divFltId) && !isExternal) ||\n (!Dom.id(extFltId) && isExternal)){\n return;\n }\n\n let flt = !isExternal ? this.checkListDiv[colIndex] : Dom.id(extFltId);\n let ul = Dom.create(\n 'ul', ['id', tf.fltIds[colIndex]], ['colIndex', colIndex]);\n ul.className = this.checkListCssClass;\n Event.add(ul, 'change', (evt)=> this.onChange(evt));\n\n let rows = tf.tbl.rows;\n this.isCustom = tf.isCustomOptions(colIndex);\n\n let activeFlt;\n if(tf.linkedFilters && tf.activeFilterId){\n activeFlt = tf.activeFilterId.split('_')[0];\n activeFlt = activeFlt.split(tf.prfxFlt)[1];\n }\n\n let filteredDataCol = [];\n if(tf.linkedFilters && tf.disableExcludedOptions){\n this.excludedOpts = [];\n }\n\n for(let k=tf.refRow; k this.optionClick(evt));\n }\n ul.appendChild(li);\n\n if(val === ''){\n //item is hidden\n li.style.display = 'none';\n }\n }\n }\n\n /**\n * Add checklist header option\n * @param {Number} colIndex Column index\n * @param {Object} ul Ul element\n */\n addTChecks(colIndex, ul){\n let tf = this.tf;\n let chkCt = 1;\n let li0 = Dom.createCheckItem(\n tf.fltIds[colIndex]+'_0', '', tf.displayAllText);\n li0.className = this.checkListItemCssClass;\n ul.appendChild(li0);\n\n Event.add(li0.check, 'click', (evt)=> this.optionClick(evt));\n\n if(!this.enableCheckListResetFilter){\n li0.style.display = 'none';\n }\n\n if(tf.enableEmptyOption){\n let li1 = Dom.createCheckItem(\n tf.fltIds[colIndex]+'_1', tf.emOperator, tf.emptyText);\n li1.className = this.checkListItemCssClass;\n ul.appendChild(li1);\n Event.add(li1.check, 'click', (evt)=> this.optionClick(evt));\n chkCt++;\n }\n\n if(tf.enableNonEmptyOption){\n let li2 = Dom.createCheckItem(\n tf.fltIds[colIndex]+'_2',\n tf.nmOperator,\n tf.nonEmptyText\n );\n li2.className = this.checkListItemCssClass;\n ul.appendChild(li2);\n Event.add(li2.check, 'click', (evt)=> this.optionClick(evt));\n chkCt++;\n }\n return chkCt;\n }\n\n /**\n * Store checked options in DOM element attribute\n * @param {Object} o checklist option DOM element\n */\n setCheckListValues(o){\n if(!o){\n return;\n }\n let tf = this.tf;\n let chkValue = o.value; //checked item value\n let chkIndex = parseInt(o.id.split('_')[2], 10);\n let filterTag = 'ul', itemTag = 'li';\n let n = o;\n\n //ul tag search\n while(Str.lower(n.nodeName)!==filterTag){\n n = n.parentNode;\n }\n\n let li = n.childNodes[chkIndex];\n let colIndex = n.getAttribute('colIndex');\n let fltValue = n.getAttribute('value'); //filter value (ul tag)\n let fltIndexes = n.getAttribute('indexes'); //selected items (ul tag)\n\n if(o.checked){\n //show all item\n if(chkValue===''){\n if((fltIndexes && fltIndexes!=='')){\n //items indexes\n let indSplit = fltIndexes.split(tf.separator);\n //checked items loop\n for(let u=0; u this.build(colIndex, isExternal)\n );\n this.emitter.off(\n ['select-checklist-options'],\n (tf, colIndex, values)=> this.selectOptions(colIndex, values)\n );\n }\n}\n"
+ },
+ {
+ "kind": "variable",
+ "static": true,
+ "variation": null,
+ "name": "SORT_ERROR",
+ "memberof": "src/modules/checkList.js",
+ "longname": "src/modules/checkList.js~SORT_ERROR",
+ "access": null,
+ "export": false,
+ "importPath": "tablefilter/src/modules/checkList.js",
+ "importStyle": null,
+ "description": null,
+ "lineNumber": 8,
+ "undocument": true,
+ "type": {
+ "types": [
+ "*"
+ ]
+ }
},
{
"kind": "class",
@@ -3921,7 +3941,7 @@
"importPath": "tablefilter/src/modules/checkList.js",
"importStyle": "{CheckList}",
"description": null,
- "lineNumber": 8,
+ "lineNumber": 11,
"undocument": true,
"interface": false,
"extends": [
@@ -3937,7 +3957,7 @@
"longname": "src/modules/checkList.js~CheckList#constructor",
"access": null,
"description": "Checklist UI component",
- "lineNumber": 14,
+ "lineNumber": 17,
"params": [
{
"nullable": null,
@@ -3961,7 +3981,7 @@
"longname": "src/modules/checkList.js~CheckList#checkListDiv",
"access": null,
"description": null,
- "lineNumber": 20,
+ "lineNumber": 23,
"undocument": true,
"type": {
"types": [
@@ -3978,7 +3998,7 @@
"longname": "src/modules/checkList.js~CheckList#checkListDivCssClass",
"access": null,
"description": null,
- "lineNumber": 22,
+ "lineNumber": 25,
"undocument": true,
"type": {
"types": [
@@ -3995,7 +4015,7 @@
"longname": "src/modules/checkList.js~CheckList#checkListCssClass",
"access": null,
"description": null,
- "lineNumber": 25,
+ "lineNumber": 28,
"undocument": true,
"type": {
"types": [
@@ -4012,7 +4032,7 @@
"longname": "src/modules/checkList.js~CheckList#checkListItemCssClass",
"access": null,
"description": null,
- "lineNumber": 27,
+ "lineNumber": 30,
"undocument": true,
"type": {
"types": [
@@ -4029,7 +4049,7 @@
"longname": "src/modules/checkList.js~CheckList#checkListSlcItemCssClass",
"access": null,
"description": null,
- "lineNumber": 30,
+ "lineNumber": 33,
"undocument": true,
"type": {
"types": [
@@ -4046,7 +4066,7 @@
"longname": "src/modules/checkList.js~CheckList#activateCheckListTxt",
"access": null,
"description": null,
- "lineNumber": 33,
+ "lineNumber": 36,
"undocument": true,
"type": {
"types": [
@@ -4063,7 +4083,7 @@
"longname": "src/modules/checkList.js~CheckList#checkListItemDisabledCssClass",
"access": null,
"description": null,
- "lineNumber": 36,
+ "lineNumber": 39,
"undocument": true,
"type": {
"types": [
@@ -4080,7 +4100,7 @@
"longname": "src/modules/checkList.js~CheckList#enableCheckListResetFilter",
"access": null,
"description": null,
- "lineNumber": 39,
+ "lineNumber": 42,
"undocument": true,
"type": {
"types": [
@@ -4097,7 +4117,7 @@
"longname": "src/modules/checkList.js~CheckList#prfxCheckListDiv",
"access": null,
"description": null,
- "lineNumber": 42,
+ "lineNumber": 45,
"undocument": true,
"type": {
"types": [
@@ -4114,7 +4134,7 @@
"longname": "src/modules/checkList.js~CheckList#isCustom",
"access": null,
"description": null,
- "lineNumber": 44,
+ "lineNumber": 47,
"undocument": true,
"type": {
"types": [
@@ -4131,7 +4151,7 @@
"longname": "src/modules/checkList.js~CheckList#opts",
"access": null,
"description": null,
- "lineNumber": 45,
+ "lineNumber": 48,
"undocument": true,
"type": {
"types": [
@@ -4148,7 +4168,7 @@
"longname": "src/modules/checkList.js~CheckList#optsTxt",
"access": null,
"description": null,
- "lineNumber": 46,
+ "lineNumber": 49,
"undocument": true,
"type": {
"types": [
@@ -4165,7 +4185,7 @@
"longname": "src/modules/checkList.js~CheckList#excludedOpts",
"access": null,
"description": null,
- "lineNumber": 47,
+ "lineNumber": 50,
"undocument": true,
"type": {
"types": [
@@ -4182,7 +4202,7 @@
"longname": "src/modules/checkList.js~CheckList#onChange",
"access": null,
"description": null,
- "lineNumber": 50,
+ "lineNumber": 53,
"undocument": true,
"params": [
{
@@ -4203,7 +4223,7 @@
"longname": "src/modules/checkList.js~CheckList#optionClick",
"access": null,
"description": null,
- "lineNumber": 58,
+ "lineNumber": 61,
"undocument": true,
"params": [
{
@@ -4224,7 +4244,7 @@
"longname": "src/modules/checkList.js~CheckList#onCheckListClick",
"access": null,
"description": null,
- "lineNumber": 63,
+ "lineNumber": 66,
"undocument": true,
"params": [
{
@@ -4245,7 +4265,7 @@
"longname": "src/modules/checkList.js~CheckList#init",
"access": null,
"description": "Initialize checklist filter",
- "lineNumber": 79,
+ "lineNumber": 82,
"params": [
{
"nullable": null,
@@ -4289,7 +4309,7 @@
"longname": "src/modules/checkList.js~CheckList#initialized",
"access": null,
"description": null,
- "lineNumber": 117,
+ "lineNumber": 120,
"undocument": true,
"type": {
"types": [
@@ -4306,7 +4326,7 @@
"longname": "src/modules/checkList.js~CheckList#build",
"access": null,
"description": "Build checklist UI",
- "lineNumber": 126,
+ "lineNumber": 129,
"params": [
{
"nullable": null,
@@ -4350,7 +4370,7 @@
"longname": "src/modules/checkList.js~CheckList#opts",
"access": null,
"description": null,
- "lineNumber": 132,
+ "lineNumber": 135,
"undocument": true,
"type": {
"types": [
@@ -4367,7 +4387,7 @@
"longname": "src/modules/checkList.js~CheckList#optsTxt",
"access": null,
"description": null,
- "lineNumber": 133,
+ "lineNumber": 136,
"undocument": true,
"type": {
"types": [
@@ -4384,7 +4404,7 @@
"longname": "src/modules/checkList.js~CheckList#isCustom",
"access": null,
"description": null,
- "lineNumber": 148,
+ "lineNumber": 151,
"undocument": true,
"type": {
"types": [
@@ -4401,7 +4421,7 @@
"longname": "src/modules/checkList.js~CheckList#excludedOpts",
"access": null,
"description": null,
- "lineNumber": 158,
+ "lineNumber": 161,
"undocument": true,
"type": {
"types": [
@@ -4418,7 +4438,7 @@
"longname": "src/modules/checkList.js~CheckList#opts",
"access": null,
"description": null,
- "lineNumber": 211,
+ "lineNumber": 214,
"undocument": true,
"type": {
"types": [
@@ -4435,7 +4455,7 @@
"longname": "src/modules/checkList.js~CheckList#optsTxt",
"access": null,
"description": null,
- "lineNumber": 212,
+ "lineNumber": 215,
"undocument": true,
"type": {
"types": [
@@ -4452,7 +4472,7 @@
"longname": "src/modules/checkList.js~CheckList#addChecks",
"access": null,
"description": "Add checklist options",
- "lineNumber": 284,
+ "lineNumber": 278,
"params": [
{
"nullable": null,
@@ -4486,7 +4506,7 @@
"longname": "src/modules/checkList.js~CheckList#addTChecks",
"access": null,
"description": "Add checklist header option",
- "lineNumber": 317,
+ "lineNumber": 311,
"params": [
{
"nullable": null,
@@ -4525,7 +4545,7 @@
"longname": "src/modules/checkList.js~CheckList#setCheckListValues",
"access": null,
"description": "Store checked options in DOM element attribute",
- "lineNumber": 358,
+ "lineNumber": 352,
"params": [
{
"nullable": null,
@@ -4549,7 +4569,7 @@
"longname": "src/modules/checkList.js~CheckList#selectOptions",
"access": null,
"description": "Select filter options programmatically",
- "lineNumber": 441,
+ "lineNumber": 435,
"params": [
{
"nullable": null,
@@ -4583,7 +4603,7 @@
"longname": "src/modules/checkList.js~CheckList#destroy",
"access": null,
"description": null,
- "lineNumber": 470,
+ "lineNumber": 464,
"undocument": true,
"params": [],
"generator": false
@@ -4863,7 +4883,27 @@
"access": null,
"description": null,
"lineNumber": 1,
- "content": "import {Feature} from './feature';\nimport Dom from '../dom';\nimport Arr from '../array';\nimport Str from '../string';\nimport Sort from '../sort';\nimport Event from '../event';\n\nexport class Dropdown extends Feature{\n\n /**\n * Dropdown UI component\n * @param {Object} tf TableFilter instance\n */\n constructor(tf){\n super(tf, 'dropdown');\n\n // Configuration object\n let f = tf.config();\n\n this.enableSlcResetFilter = f.enable_slc_reset_filter===false ?\n false : true;\n //defines empty option text\n this.nonEmptyText = f.non_empty_text || '(Non empty)';\n //sets select filling method: 'innerHTML' or 'createElement'\n this.slcFillingMethod = f.slc_filling_method || 'createElement';\n //IE only, tooltip text appearing on select before it is populated\n this.activateSlcTooltip = f.activate_slc_tooltip ||\n 'Click to activate';\n //tooltip text appearing on multiple select\n this.multipleSlcTooltip = f.multiple_slc_tooltip ||\n 'Use Ctrl key for multiple selections';\n\n this.isCustom = null;\n this.opts = null;\n this.optsTxt = null;\n this.slcInnerHtml = null;\n }\n\n onSlcFocus(e) {\n let elm = Event.target(e);\n let tf = this.tf;\n tf.activeFilterId = elm.getAttribute('id');\n tf.activeFlt = Dom.id(tf.activeFilterId);\n // select is populated when element has focus\n if(tf.loadFltOnDemand && elm.getAttribute('filled') === '0'){\n let ct = elm.getAttribute('ct');\n this.build(ct);\n }\n this.emitter.emit('filter-focus', tf, this);\n }\n\n onSlcChange() {\n if(this.tf.onSlcChange){\n this.tf.filter();\n }\n }\n\n /**\n * Initialize drop-down filter\n * @param {Number} colIndex Column index\n * @param {Boolean} isExternal External filter flag\n * @param {DOMElement} container Dom element containing the filter\n */\n init(colIndex, isExternal, container){\n let tf = this.tf;\n let col = tf.getFilterType(colIndex);\n let externalFltTgtId = isExternal ?\n tf.externalFltTgtIds[colIndex] : null;\n\n let slc = Dom.create(tf.fltTypeSlc,\n ['id', tf.prfxFlt+colIndex+'_'+tf.id],\n ['ct', colIndex], ['filled', '0']\n );\n\n if(col === tf.fltTypeMulti){\n slc.multiple = tf.fltTypeMulti;\n slc.title = this.multipleSlcTooltip;\n }\n slc.className = Str.lower(col) === tf.fltTypeSlc ?\n tf.fltCssClass : tf.fltMultiCssClass;\n\n //filter is appended in container element\n if(externalFltTgtId){\n Dom.id(externalFltTgtId).appendChild(slc);\n tf.externalFltEls.push(slc);\n } else {\n container.appendChild(slc);\n }\n\n tf.fltIds.push(slc.id);\n\n if(!tf.loadFltOnDemand){\n this.build(colIndex);\n } else {\n //1st option is created here since build isn't invoked\n let opt0 = Dom.createOpt(tf.displayAllText, '');\n slc.appendChild(opt0);\n }\n\n Event.add(slc, 'change', ()=> this.onSlcChange());\n Event.add(slc, 'focus', (e)=> this.onSlcFocus(e));\n\n this.emitter.on(\n ['build-select-filter'],\n (tf, colIndex, isLinked, isExternal)=>\n this.build(colIndex, isLinked, isExternal)\n );\n this.emitter.on(\n ['select-options'],\n (tf, colIndex, values)=> this.selectOptions(colIndex, values)\n );\n\n this.initialized = true;\n }\n\n /**\n * Build drop-down filter UI\n * @param {Number} colIndex Column index\n * @param {Boolean} isLinked Enable linked refresh behaviour\n * @param {Boolean} isExternal Render in external container\n * @param {String} extSlcId External container id\n */\n build(colIndex, isLinked=false, isExternal=false, extSlcId=null){\n let tf = this.tf;\n colIndex = parseInt(colIndex, 10);\n\n this.emitter.emit('before-populating-filter', tf, colIndex);\n\n this.opts = [];\n this.optsTxt = [];\n this.slcInnerHtml = '';\n\n let slcId = tf.fltIds[colIndex];\n if((!Dom.id(slcId) && !isExternal) ||\n (!Dom.id(extSlcId) && isExternal)){\n return;\n }\n let slc = !isExternal ? Dom.id(slcId) : Dom.id(extSlcId),\n rows = tf.tbl.rows,\n matchCase = tf.matchCase;\n\n //custom select test\n this.isCustom = tf.isCustomOptions(colIndex);\n\n //custom selects text\n let activeFlt;\n if(isLinked && tf.activeFilterId){\n activeFlt = tf.activeFilterId.split('_')[0];\n activeFlt = activeFlt.split(tf.prfxFlt)[1];\n }\n\n let excludedOpts = null,\n filteredDataCol = null;\n if(isLinked && tf.disableExcludedOptions){\n excludedOpts = [];\n filteredDataCol = [];\n }\n\n for(let k=tf.refRow; k' +\n lbl+'';\n } else {\n let opt;\n //fill select on demand\n if(tf.loadFltOnDemand && slcValue===this.opts[y] &&\n tf.getFilterType(colIndex) === tf.fltTypeSlc){\n opt = Dom.createOpt(lbl, val, true);\n } else {\n opt = Dom.createOpt(lbl, val, false);\n }\n if(isDisabled){\n opt.disabled = true;\n }\n slc.appendChild(opt);\n }\n }// for y\n\n if(fillMethod === 'innerhtml'){\n slc.innerHTML += this.slcInnerHtml;\n }\n slc.setAttribute('filled', '1');\n }\n\n /**\n * Add drop-down header option\n * @param {Object} slc Select DOM element\n */\n addFirstOption(slc){\n let tf = this.tf,\n fillMethod = Str.lower(this.slcFillingMethod);\n\n if(fillMethod === 'innerhtml'){\n this.slcInnerHtml += '';\n }\n else {\n let opt0 = Dom.createOpt(\n (!this.enableSlcResetFilter ? '' : tf.displayAllText),'');\n if(!this.enableSlcResetFilter){\n opt0.style.display = 'none';\n }\n slc.appendChild(opt0);\n if(tf.enableEmptyOption){\n let opt1 = Dom.createOpt(tf.emptyText, tf.emOperator);\n slc.appendChild(opt1);\n }\n if(tf.enableNonEmptyOption){\n let opt2 = Dom.createOpt(tf.nonEmptyText, tf.nmOperator);\n slc.appendChild(opt2);\n }\n }\n return slc;\n }\n\n /**\n * Select filter options programmatically\n * @param {Number} colIndex Column index\n * @param {Array} values Array of option values to select\n */\n selectOptions(colIndex, values=[]){\n let tf = this.tf;\n if(tf.getFilterType(colIndex) !== tf.fltTypeMulti ||\n values.length === 0){\n return;\n }\n let slc = tf.getFilterElement(colIndex);\n [].forEach.call(slc.options, (option)=> {\n // Empty value means clear all selections and first option is the\n // clear all option\n if(values[0] === '' || option.value === ''){\n option.selected = false;\n }\n\n if(option.value !== '' &&\n Arr.has(values, option.value, true)){\n option.selected = true;\n }//if\n });\n }\n\n destroy(){\n this.emitter.off(\n ['build-select-filter'],\n (colIndex, isLinked, isExternal)=>\n this.build(colIndex, isLinked, isExternal)\n );\n this.emitter.off(\n ['select-options'],\n (tf, colIndex, values)=> this.selectOptions(colIndex, values)\n );\n }\n}\n"
+ "content": "import {Feature} from './feature';\nimport Dom from '../dom';\nimport Arr from '../array';\nimport Str from '../string';\nimport Sort from '../sort';\nimport Event from '../event';\n\nconst SORT_ERROR = 'Filter options for column {0} cannot be sorted in ' +\n '{1} manner.';\n\nexport class Dropdown extends Feature{\n\n /**\n * Dropdown UI component\n * @param {Object} tf TableFilter instance\n */\n constructor(tf){\n super(tf, 'dropdown');\n\n // Configuration object\n let f = tf.config();\n\n this.enableSlcResetFilter = f.enable_slc_reset_filter===false ?\n false : true;\n //defines empty option text\n this.nonEmptyText = f.non_empty_text || '(Non empty)';\n //sets select filling method: 'innerHTML' or 'createElement'\n this.slcFillingMethod = f.slc_filling_method || 'createElement';\n //IE only, tooltip text appearing on select before it is populated\n this.activateSlcTooltip = f.activate_slc_tooltip ||\n 'Click to activate';\n //tooltip text appearing on multiple select\n this.multipleSlcTooltip = f.multiple_slc_tooltip ||\n 'Use Ctrl key for multiple selections';\n\n this.isCustom = null;\n this.opts = null;\n this.optsTxt = null;\n this.slcInnerHtml = null;\n }\n\n onSlcFocus(e) {\n let elm = Event.target(e);\n let tf = this.tf;\n tf.activeFilterId = elm.getAttribute('id');\n tf.activeFlt = Dom.id(tf.activeFilterId);\n // select is populated when element has focus\n if(tf.loadFltOnDemand && elm.getAttribute('filled') === '0'){\n let ct = elm.getAttribute('ct');\n this.build(ct);\n }\n this.emitter.emit('filter-focus', tf, this);\n }\n\n onSlcChange() {\n if(this.tf.onSlcChange){\n this.tf.filter();\n }\n }\n\n /**\n * Initialize drop-down filter\n * @param {Number} colIndex Column index\n * @param {Boolean} isExternal External filter flag\n * @param {DOMElement} container Dom element containing the filter\n */\n init(colIndex, isExternal, container){\n let tf = this.tf;\n let col = tf.getFilterType(colIndex);\n let externalFltTgtId = isExternal ?\n tf.externalFltTgtIds[colIndex] : null;\n\n let slc = Dom.create(tf.fltTypeSlc,\n ['id', tf.prfxFlt+colIndex+'_'+tf.id],\n ['ct', colIndex], ['filled', '0']\n );\n\n if(col === tf.fltTypeMulti){\n slc.multiple = tf.fltTypeMulti;\n slc.title = this.multipleSlcTooltip;\n }\n slc.className = Str.lower(col) === tf.fltTypeSlc ?\n tf.fltCssClass : tf.fltMultiCssClass;\n\n //filter is appended in container element\n if(externalFltTgtId){\n Dom.id(externalFltTgtId).appendChild(slc);\n tf.externalFltEls.push(slc);\n } else {\n container.appendChild(slc);\n }\n\n tf.fltIds.push(slc.id);\n\n if(!tf.loadFltOnDemand){\n this.build(colIndex);\n } else {\n //1st option is created here since build isn't invoked\n let opt0 = Dom.createOpt(tf.displayAllText, '');\n slc.appendChild(opt0);\n }\n\n Event.add(slc, 'change', ()=> this.onSlcChange());\n Event.add(slc, 'focus', (e)=> this.onSlcFocus(e));\n\n this.emitter.on(\n ['build-select-filter'],\n (tf, colIndex, isLinked, isExternal)=>\n this.build(colIndex, isLinked, isExternal)\n );\n this.emitter.on(\n ['select-options'],\n (tf, colIndex, values)=> this.selectOptions(colIndex, values)\n );\n\n this.initialized = true;\n }\n\n /**\n * Build drop-down filter UI\n * @param {Number} colIndex Column index\n * @param {Boolean} isLinked Enable linked refresh behaviour\n * @param {Boolean} isExternal Render in external container\n * @param {String} extSlcId External container id\n */\n build(colIndex, isLinked=false, isExternal=false, extSlcId=null){\n let tf = this.tf;\n colIndex = parseInt(colIndex, 10);\n\n this.emitter.emit('before-populating-filter', tf, colIndex);\n\n this.opts = [];\n this.optsTxt = [];\n this.slcInnerHtml = '';\n\n let slcId = tf.fltIds[colIndex];\n if((!Dom.id(slcId) && !isExternal) ||\n (!Dom.id(extSlcId) && isExternal)){\n return;\n }\n let slc = !isExternal ? Dom.id(slcId) : Dom.id(extSlcId),\n rows = tf.tbl.rows,\n matchCase = tf.matchCase;\n\n //custom select test\n this.isCustom = tf.isCustomOptions(colIndex);\n\n //custom selects text\n let activeFlt;\n if(isLinked && tf.activeFilterId){\n activeFlt = tf.activeFilterId.split('_')[0];\n activeFlt = activeFlt.split(tf.prfxFlt)[1];\n }\n\n let excludedOpts = null,\n filteredDataCol = null;\n if(isLinked && tf.disableExcludedOptions){\n excludedOpts = [];\n filteredDataCol = [];\n }\n\n for(let k=tf.refRow; k' +\n lbl+'';\n } else {\n let opt;\n //fill select on demand\n if(tf.loadFltOnDemand && slcValue===this.opts[y] &&\n tf.getFilterType(colIndex) === tf.fltTypeSlc){\n opt = Dom.createOpt(lbl, val, true);\n } else {\n opt = Dom.createOpt(lbl, val, false);\n }\n if(isDisabled){\n opt.disabled = true;\n }\n slc.appendChild(opt);\n }\n }// for y\n\n if(fillMethod === 'innerhtml'){\n slc.innerHTML += this.slcInnerHtml;\n }\n slc.setAttribute('filled', '1');\n }\n\n /**\n * Add drop-down header option\n * @param {Object} slc Select DOM element\n */\n addFirstOption(slc){\n let tf = this.tf,\n fillMethod = Str.lower(this.slcFillingMethod);\n\n if(fillMethod === 'innerhtml'){\n this.slcInnerHtml += '';\n }\n else {\n let opt0 = Dom.createOpt(\n (!this.enableSlcResetFilter ? '' : tf.displayAllText),'');\n if(!this.enableSlcResetFilter){\n opt0.style.display = 'none';\n }\n slc.appendChild(opt0);\n if(tf.enableEmptyOption){\n let opt1 = Dom.createOpt(tf.emptyText, tf.emOperator);\n slc.appendChild(opt1);\n }\n if(tf.enableNonEmptyOption){\n let opt2 = Dom.createOpt(tf.nonEmptyText, tf.nmOperator);\n slc.appendChild(opt2);\n }\n }\n return slc;\n }\n\n /**\n * Select filter options programmatically\n * @param {Number} colIndex Column index\n * @param {Array} values Array of option values to select\n */\n selectOptions(colIndex, values=[]){\n let tf = this.tf;\n if(tf.getFilterType(colIndex) !== tf.fltTypeMulti ||\n values.length === 0){\n return;\n }\n let slc = tf.getFilterElement(colIndex);\n [].forEach.call(slc.options, (option)=> {\n // Empty value means clear all selections and first option is the\n // clear all option\n if(values[0] === '' || option.value === ''){\n option.selected = false;\n }\n\n if(option.value !== '' &&\n Arr.has(values, option.value, true)){\n option.selected = true;\n }//if\n });\n }\n\n destroy(){\n this.emitter.off(\n ['build-select-filter'],\n (colIndex, isLinked, isExternal)=>\n this.build(colIndex, isLinked, isExternal)\n );\n this.emitter.off(\n ['select-options'],\n (tf, colIndex, values)=> this.selectOptions(colIndex, values)\n );\n }\n}\n"
+ },
+ {
+ "kind": "variable",
+ "static": true,
+ "variation": null,
+ "name": "SORT_ERROR",
+ "memberof": "src/modules/dropdown.js",
+ "longname": "src/modules/dropdown.js~SORT_ERROR",
+ "access": null,
+ "export": false,
+ "importPath": "tablefilter/src/modules/dropdown.js",
+ "importStyle": null,
+ "description": null,
+ "lineNumber": 8,
+ "undocument": true,
+ "type": {
+ "types": [
+ "*"
+ ]
+ }
},
{
"kind": "class",
@@ -4877,7 +4917,7 @@
"importPath": "tablefilter/src/modules/dropdown.js",
"importStyle": "{Dropdown}",
"description": null,
- "lineNumber": 8,
+ "lineNumber": 11,
"undocument": true,
"interface": false,
"extends": [
@@ -4893,7 +4933,7 @@
"longname": "src/modules/dropdown.js~Dropdown#constructor",
"access": null,
"description": "Dropdown UI component",
- "lineNumber": 14,
+ "lineNumber": 17,
"params": [
{
"nullable": null,
@@ -4917,7 +4957,7 @@
"longname": "src/modules/dropdown.js~Dropdown#enableSlcResetFilter",
"access": null,
"description": null,
- "lineNumber": 20,
+ "lineNumber": 23,
"undocument": true,
"type": {
"types": [
@@ -4934,7 +4974,7 @@
"longname": "src/modules/dropdown.js~Dropdown#nonEmptyText",
"access": null,
"description": null,
- "lineNumber": 23,
+ "lineNumber": 26,
"undocument": true,
"type": {
"types": [
@@ -4951,7 +4991,7 @@
"longname": "src/modules/dropdown.js~Dropdown#slcFillingMethod",
"access": null,
"description": null,
- "lineNumber": 25,
+ "lineNumber": 28,
"undocument": true,
"type": {
"types": [
@@ -4968,7 +5008,7 @@
"longname": "src/modules/dropdown.js~Dropdown#activateSlcTooltip",
"access": null,
"description": null,
- "lineNumber": 27,
+ "lineNumber": 30,
"undocument": true,
"type": {
"types": [
@@ -4985,7 +5025,7 @@
"longname": "src/modules/dropdown.js~Dropdown#multipleSlcTooltip",
"access": null,
"description": null,
- "lineNumber": 30,
+ "lineNumber": 33,
"undocument": true,
"type": {
"types": [
@@ -5002,7 +5042,7 @@
"longname": "src/modules/dropdown.js~Dropdown#isCustom",
"access": null,
"description": null,
- "lineNumber": 33,
+ "lineNumber": 36,
"undocument": true,
"type": {
"types": [
@@ -5019,7 +5059,7 @@
"longname": "src/modules/dropdown.js~Dropdown#opts",
"access": null,
"description": null,
- "lineNumber": 34,
+ "lineNumber": 37,
"undocument": true,
"type": {
"types": [
@@ -5036,7 +5076,7 @@
"longname": "src/modules/dropdown.js~Dropdown#optsTxt",
"access": null,
"description": null,
- "lineNumber": 35,
+ "lineNumber": 38,
"undocument": true,
"type": {
"types": [
@@ -5053,7 +5093,7 @@
"longname": "src/modules/dropdown.js~Dropdown#slcInnerHtml",
"access": null,
"description": null,
- "lineNumber": 36,
+ "lineNumber": 39,
"undocument": true,
"type": {
"types": [
@@ -5070,7 +5110,7 @@
"longname": "src/modules/dropdown.js~Dropdown#onSlcFocus",
"access": null,
"description": null,
- "lineNumber": 39,
+ "lineNumber": 42,
"undocument": true,
"params": [
{
@@ -5091,7 +5131,7 @@
"longname": "src/modules/dropdown.js~Dropdown#onSlcChange",
"access": null,
"description": null,
- "lineNumber": 52,
+ "lineNumber": 55,
"undocument": true,
"params": [],
"generator": false
@@ -5105,7 +5145,7 @@
"longname": "src/modules/dropdown.js~Dropdown#init",
"access": null,
"description": "Initialize drop-down filter",
- "lineNumber": 64,
+ "lineNumber": 67,
"params": [
{
"nullable": null,
@@ -5149,7 +5189,7 @@
"longname": "src/modules/dropdown.js~Dropdown#initialized",
"access": null,
"description": null,
- "lineNumber": 113,
+ "lineNumber": 116,
"undocument": true,
"type": {
"types": [
@@ -5166,7 +5206,7 @@
"longname": "src/modules/dropdown.js~Dropdown#build",
"access": null,
"description": "Build drop-down filter UI",
- "lineNumber": 123,
+ "lineNumber": 126,
"params": [
{
"nullable": null,
@@ -5220,7 +5260,7 @@
"longname": "src/modules/dropdown.js~Dropdown#opts",
"access": null,
"description": null,
- "lineNumber": 129,
+ "lineNumber": 132,
"undocument": true,
"type": {
"types": [
@@ -5237,7 +5277,7 @@
"longname": "src/modules/dropdown.js~Dropdown#optsTxt",
"access": null,
"description": null,
- "lineNumber": 130,
+ "lineNumber": 133,
"undocument": true,
"type": {
"types": [
@@ -5254,7 +5294,7 @@
"longname": "src/modules/dropdown.js~Dropdown#slcInnerHtml",
"access": null,
"description": null,
- "lineNumber": 131,
+ "lineNumber": 134,
"undocument": true,
"type": {
"types": [
@@ -5271,7 +5311,7 @@
"longname": "src/modules/dropdown.js~Dropdown#isCustom",
"access": null,
"description": null,
- "lineNumber": 143,
+ "lineNumber": 146,
"undocument": true,
"type": {
"types": [
@@ -5288,7 +5328,7 @@
"longname": "src/modules/dropdown.js~Dropdown#opts",
"access": null,
"description": null,
- "lineNumber": 215,
+ "lineNumber": 218,
"undocument": true,
"type": {
"types": [
@@ -5305,7 +5345,7 @@
"longname": "src/modules/dropdown.js~Dropdown#optsTxt",
"access": null,
"description": null,
- "lineNumber": 216,
+ "lineNumber": 219,
"undocument": true,
"type": {
"types": [
@@ -5322,7 +5362,7 @@
"longname": "src/modules/dropdown.js~Dropdown#addOptions",
"access": null,
"description": "Add drop-down options",
- "lineNumber": 285,
+ "lineNumber": 278,
"params": [
{
"nullable": null,
@@ -5376,7 +5416,7 @@
"longname": "src/modules/dropdown.js~Dropdown#slcInnerHtml",
"access": null,
"description": null,
- "lineNumber": 314,
+ "lineNumber": 307,
"undocument": true,
"type": {
"types": [
@@ -5393,7 +5433,7 @@
"longname": "src/modules/dropdown.js~Dropdown#addFirstOption",
"access": null,
"description": "Add drop-down header option",
- "lineNumber": 343,
+ "lineNumber": 336,
"params": [
{
"nullable": null,
@@ -5422,7 +5462,7 @@
"longname": "src/modules/dropdown.js~Dropdown#slcInnerHtml",
"access": null,
"description": null,
- "lineNumber": 348,
+ "lineNumber": 341,
"undocument": true,
"type": {
"types": [
@@ -5439,7 +5479,7 @@
"longname": "src/modules/dropdown.js~Dropdown#selectOptions",
"access": null,
"description": "Select filter options programmatically",
- "lineNumber": 375,
+ "lineNumber": 368,
"params": [
{
"nullable": null,
@@ -5473,7 +5513,7 @@
"longname": "src/modules/dropdown.js~Dropdown#destroy",
"access": null,
"description": null,
- "lineNumber": 396,
+ "lineNumber": 389,
"undocument": true,
"params": [],
"generator": false
@@ -11203,7 +11243,7 @@
"access": null,
"description": null,
"lineNumber": 1,
- "content": "import Str from './string';\n\nexport default {\n ignoreCase(a, b){\n let x = Str.lower(a);\n let y = Str.lower(b);\n return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n }\n};\n"
+ "content": "import Str from './string';\n\nexport default {\n ignoreCase(a, b){\n let x = Str.lower(a);\n let y = Str.lower(b);\n return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n },\n numSortAsc(a, b){\n return (a - b);\n },\n numSortDesc(a, b){\n return (b - a);\n }\n};\n"
},
{
"kind": "file",
@@ -11227,7 +11267,7 @@
"access": null,
"description": null,
"lineNumber": 1,
- "content": "import Event from './event';\nimport Dom from './dom';\nimport Str from './string';\nimport Types from './types';\nimport DateHelper from './date';\nimport Helpers from './helpers';\nimport {Emitter} from './emitter';\n\n// Features\nimport {Store} from './modules/store';\nimport {GridLayout} from './modules/gridLayout';\nimport {Loader} from './modules/loader';\nimport {HighlightKeyword} from './modules/highlightKeywords';\nimport {PopupFilter} from './modules/popupFilter';\nimport {Dropdown} from './modules/dropdown';\nimport {CheckList} from './modules/checkList';\nimport {RowsCounter} from './modules/rowsCounter';\nimport {StatusBar} from './modules/statusBar';\nimport {Paging} from './modules/paging';\nimport {ClearButton} from './modules/clearButton';\nimport {Help} from './modules/help';\nimport {AlternateRows} from './modules/alternateRows';\nimport {NoResults} from './modules/noResults';\n\nlet global = window,\n doc = global.document;\n\nexport class TableFilter {\n\n /**\n * TableFilter object constructor\n * requires `table` or `id` arguments, `row` and `configuration` optional\n * @param {DOMElement} table Table DOM element\n * @param {String} id Table id\n * @param {Number} row index indicating the 1st row\n * @param {Object} configuration object\n */\n constructor(...args) {\n if(args.length === 0){ return; }\n\n this.id = null;\n this.version = '{VERSION}';\n this.year = new Date().getFullYear();\n this.tbl = null;\n this.startRow = null;\n this.refRow = null;\n this.headersRow = null;\n this.cfg = {};\n this.nbFilterableRows = null;\n this.nbRows = null;\n this.nbCells = null;\n this._hasGrid = false;\n\n // TODO: use for-of with babel plug-in\n args.forEach((arg)=> {\n // for (let arg of args) {\n let argtype = typeof arg;\n if(argtype === 'object' && arg && arg.nodeName === 'TABLE'){\n this.tbl = arg;\n this.id = arg.id || `tf_${new Date().getTime()}_`;\n } else if(argtype === 'string'){\n this.id = arg;\n this.tbl = Dom.id(arg);\n } else if(argtype === 'number'){\n this.startRow = arg;\n } else if(argtype === 'object'){\n this.cfg = arg;\n }\n // }\n });\n\n if(!this.tbl || this.tbl.nodeName != 'TABLE' || this.getRowsNb() === 0){\n throw new Error(\n 'Could not instantiate TableFilter: HTML table not found.');\n }\n\n // configuration object\n let f = this.cfg;\n\n this.emitter = new Emitter();\n\n //Start row et cols nb\n this.refRow = this.startRow === null ? 2 : (this.startRow+1);\n try{ this.nbCells = this.getCellsNb(this.refRow); }\n catch(e){ this.nbCells = this.getCellsNb(0); }\n\n //default script base path\n this.basePath = f.base_path || 'tablefilter/';\n\n /*** filter types ***/\n this.fltTypeInp = 'input';\n this.fltTypeSlc = 'select';\n this.fltTypeMulti = 'multiple';\n this.fltTypeCheckList = 'checklist';\n this.fltTypeNone = 'none';\n\n /*** filters' grid properties ***/\n\n //enables/disables filter grid\n this.fltGrid = f.grid === false ? false : true;\n\n //enables/disables grid layout (fixed headers)\n this.gridLayout = Boolean(f.grid_layout);\n\n this.filtersRowIndex = isNaN(f.filters_row_index) ?\n 0 : f.filters_row_index;\n this.headersRow = isNaN(f.headers_row_index) ?\n (this.filtersRowIndex === 0 ? 1 : 0) : f.headers_row_index;\n\n //defines tag of the cells containing filters (td/th)\n this.fltCellTag = f.filters_cell_tag!=='th' ||\n f.filters_cell_tag!=='td' ? 'td' : f.filters_cell_tag;\n\n //stores filters ids\n this.fltIds = [];\n //stores filters DOM elements\n this.fltElms = [];\n //stores valid rows indexes (rows visible upon filtering)\n this.validRowsIndex = [];\n //stores filters row element\n this.fltGridEl = null;\n //container div for paging elements, reset btn etc.\n this.infDiv = null;\n //div for rows counter\n this.lDiv = null;\n //div for reset button and results per page select\n this.rDiv = null;\n //div for paging elements\n this.mDiv = null;\n\n //defines css class for div containing paging elements, rows counter etc\n this.infDivCssClass = f.inf_div_css_class || 'inf';\n //defines css class for left div\n this.lDivCssClass = f.left_div_css_class || 'ldiv';\n //defines css class for right div\n this.rDivCssClass = f.right_div_css_class || 'rdiv';\n //defines css class for mid div\n this.mDivCssClass = f.middle_div_css_class || 'mdiv';\n //table container div css class\n this.contDivCssClass = f.content_div_css_class || 'cont';\n\n /*** filters' grid appearance ***/\n //stylesheet file\n this.stylePath = f.style_path || this.basePath + 'style/';\n this.stylesheet = f.stylesheet || this.stylePath+'tablefilter.css';\n this.stylesheetId = this.id + '_style';\n //defines css class for filters row\n this.fltsRowCssClass = f.flts_row_css_class || 'fltrow';\n //enables/disables icons (paging, reset button)\n this.enableIcons = f.enable_icons===false ? false : true;\n //enables/disbles rows alternating bg colors\n this.alternateRows = Boolean(f.alternate_rows);\n //defines widths of columns\n this.hasColWidths = Types.isArray(f.col_widths);\n this.colWidths = this.hasColWidths ? f.col_widths : null;\n //defines css class for filters\n this.fltCssClass = f.flt_css_class || 'flt';\n //defines css class for multiple selects filters\n this.fltMultiCssClass = f.flt_multi_css_class || 'flt_multi';\n //defines css class for filters\n this.fltSmallCssClass = f.flt_small_css_class || 'flt_s';\n //defines css class for single-filter\n this.singleFltCssClass = f.single_flt_css_class || 'single_flt';\n\n /*** filters' grid behaviours ***/\n //enables/disables enter key\n this.enterKey = f.enter_key===false ? false : true;\n //calls function before filtering starts\n this.onBeforeFilter = Types.isFn(f.on_before_filter) ?\n f.on_before_filter : null;\n //calls function after filtering\n this.onAfterFilter = Types.isFn(f.on_after_filter) ?\n f.on_after_filter : null;\n //enables/disables case sensitivity\n this.caseSensitive = Boolean(f.case_sensitive);\n //has exact match per column\n this.hasExactMatchByCol = Types.isArray(f.columns_exact_match);\n this.exactMatchByCol = this.hasExactMatchByCol ?\n f.columns_exact_match : [];\n //enables/disbles exact match for search\n this.exactMatch = Boolean(f.exact_match);\n //refreshes drop-down lists upon validation\n this.linkedFilters = Boolean(f.linked_filters);\n //wheter excluded options are disabled\n this.disableExcludedOptions = Boolean(f.disable_excluded_options);\n //stores active filter element\n this.activeFlt = null;\n //id of active filter\n this.activeFilterId = null;\n //enables always visible rows\n this.hasVisibleRows = Boolean(f.rows_always_visible);\n //array containing always visible rows\n this.visibleRows = this.hasVisibleRows ? f.rows_always_visible : [];\n //enables/disables external filters generation\n this.isExternalFlt = Boolean(f.external_flt_grid);\n //array containing ids of external elements containing filters\n this.externalFltTgtIds = f.external_flt_grid_ids || [];\n //stores filters elements if isExternalFlt is true\n this.externalFltEls = [];\n //delays any filtering process if loader true\n this.execDelay = !isNaN(f.exec_delay) ? parseInt(f.exec_delay,10) : 100;\n //calls function when filters grid loaded\n this.onFiltersLoaded = Types.isFn(f.on_filters_loaded) ?\n f.on_filters_loaded : null;\n //enables/disables single filter search\n this.singleSearchFlt = Boolean(f.single_filter);\n //calls function after row is validated\n this.onRowValidated = Types.isFn(f.on_row_validated) ?\n f.on_row_validated : null;\n //array defining columns for customCellData event\n this.customCellDataCols = f.custom_cell_data_cols ?\n f.custom_cell_data_cols : [];\n //calls custom function for retrieving cell data\n this.customCellData = Types.isFn(f.custom_cell_data) ?\n f.custom_cell_data : null;\n //input watermark text array\n this.watermark = f.watermark || '';\n this.isWatermarkArray = Types.isArray(this.watermark);\n //id of toolbar container element\n this.toolBarTgtId = f.toolbar_target_id || null;\n //enables/disables help div\n this.help = Types.isUndef(f.help_instructions) ?\n undefined : Boolean(f.help_instructions);\n //popup filters\n this.popupFilters = Boolean(f.popup_filters);\n //active columns color\n this.markActiveColumns = Boolean(f.mark_active_columns);\n //defines css class for active column header\n this.activeColumnsCssClass = f.active_columns_css_class ||\n 'activeHeader';\n //calls function before active column header is marked\n this.onBeforeActiveColumn = Types.isFn(f.on_before_active_column) ?\n f.on_before_active_column : null;\n //calls function after active column header is marked\n this.onAfterActiveColumn = Types.isFn(f.on_after_active_column) ?\n f.on_after_active_column : null;\n\n /*** select filter's customisation and behaviours ***/\n //defines 1st option text\n this.displayAllText = f.display_all_text || 'Clear';\n //enables/disables empty option in combo-box filters\n this.enableEmptyOption = Boolean(f.enable_empty_option);\n //defines empty option text\n this.emptyText = f.empty_text || '(Empty)';\n //enables/disables non empty option in combo-box filters\n this.enableNonEmptyOption = Boolean(f.enable_non_empty_option);\n //defines empty option text\n this.nonEmptyText = f.non_empty_text || '(Non empty)';\n //enables/disables onChange event on combo-box\n this.onSlcChange = f.on_change===false ? false : true;\n //enables/disables select options sorting\n this.sortSlc = f.sort_select===false ? false : true;\n //enables/disables ascending numeric options sorting\n this.isSortNumAsc = Boolean(f.sort_num_asc);\n this.sortNumAsc = this.isSortNumAsc ? f.sort_num_asc : null;\n //enables/disables descending numeric options sorting\n this.isSortNumDesc = Boolean(f.sort_num_desc);\n this.sortNumDesc = this.isSortNumDesc ? f.sort_num_desc : null;\n //Select filters are populated on demand\n this.loadFltOnDemand = Boolean(f.load_filters_on_demand);\n this.hasCustomOptions = Types.isObj(f.custom_options);\n this.customOptions = f.custom_options;\n\n /*** Filter operators ***/\n this.rgxOperator = f.regexp_operator || 'rgx:';\n this.emOperator = f.empty_operator || '[empty]';\n this.nmOperator = f.nonempty_operator || '[nonempty]';\n this.orOperator = f.or_operator || '||';\n this.anOperator = f.and_operator || '&&';\n this.grOperator = f.greater_operator || '>';\n this.lwOperator = f.lower_operator || '<';\n this.leOperator = f.lower_equal_operator || '<=';\n this.geOperator = f.greater_equal_operator || '>=';\n this.dfOperator = f.different_operator || '!';\n this.lkOperator = f.like_operator || '*';\n this.eqOperator = f.equal_operator || '=';\n this.stOperator = f.start_with_operator || '{';\n this.enOperator = f.end_with_operator || '}';\n this.curExp = f.cur_exp || '^[¥£€$]';\n this.separator = f.separator || ',';\n\n /*** rows counter ***/\n //show/hides rows counter\n this.rowsCounter = Boolean(f.rows_counter);\n\n /*** status bar ***/\n //show/hides status bar\n this.statusBar = Boolean(f.status_bar);\n\n /*** loader ***/\n //enables/disables loader/spinner indicator\n this.loader = Boolean(f.loader);\n\n /*** validation - reset buttons/links ***/\n //show/hides filter's validation button\n this.displayBtn = Boolean(f.btn);\n //defines validation button text\n this.btnText = f.btn_text || (!this.enableIcons ? 'Go' : '');\n //defines css class for validation button\n this.btnCssClass = f.btn_css_class ||\n (!this.enableIcons ? 'btnflt' : 'btnflt_icon');\n //show/hides reset link\n this.btnReset = Boolean(f.btn_reset);\n //defines css class for reset button\n this.btnResetCssClass = f.btn_reset_css_class || 'reset';\n //callback function before filters are cleared\n this.onBeforeReset = Types.isFn(f.on_before_reset) ?\n f.on_before_reset : null;\n //callback function after filters are cleared\n this.onAfterReset = Types.isFn(f.on_after_reset) ?\n f.on_after_reset : null;\n\n /*** paging ***/\n //enables/disables table paging\n this.paging = Boolean(f.paging);\n this.nbVisibleRows = 0; //nb visible rows\n this.nbHiddenRows = 0; //nb hidden rows\n\n /*** autofilter on typing ***/\n //enables/disables auto filtering, table is filtered when user stops\n //typing\n this.autoFilter = Boolean(f.auto_filter);\n //onkeyup delay timer (msecs)\n this.autoFilterDelay = !isNaN(f.auto_filter_delay) ?\n f.auto_filter_delay : 900;\n //typing indicator\n this.isUserTyping = null;\n this.autoFilterTimer = null;\n\n /*** keyword highlighting ***/\n //enables/disables keyword highlighting\n this.highlightKeywords = Boolean(f.highlight_keywords);\n\n /*** No results feature ***/\n this.noResults = Types.isObj(f.no_results_message) ||\n Boolean(f.no_results_message);\n\n /*** data types ***/\n //defines default date type (european DMY)\n this.defaultDateType = f.default_date_type || 'DMY';\n //defines default thousands separator\n //US = ',' EU = '.'\n this.thousandsSeparator = f.thousands_separator || ',';\n //defines default decimal separator\n //US & javascript = '.' EU = ','\n this.decimalSeparator = f.decimal_separator || '.';\n //enables number format per column\n this.hasColNbFormat = Types.isArray(f.col_number_format);\n //array containing columns nb formats\n this.colNbFormat = this.hasColNbFormat ? f.col_number_format : null;\n //enables date type per column\n this.hasColDateType = Types.isArray(f.col_date_type);\n //array containing columns date type\n this.colDateType = this.hasColDateType ? f.col_date_type : null;\n\n /*** ids prefixes ***/\n //css class name added to table\n this.prfxTf = 'TF';\n //filters (inputs - selects)\n this.prfxFlt = 'flt';\n //validation button\n this.prfxValButton = 'btn';\n //container div for paging elements, rows counter etc.\n this.prfxInfDiv = 'inf_';\n //left div\n this.prfxLDiv = 'ldiv_';\n //right div\n this.prfxRDiv = 'rdiv_';\n //middle div\n this.prfxMDiv = 'mdiv_';\n //filter values cookie\n this.prfxCookieFltsValues = 'tf_flts_';\n //page nb cookie\n this.prfxCookiePageNb = 'tf_pgnb_';\n //page length cookie\n this.prfxCookiePageLen = 'tf_pglen_';\n\n /*** cookies ***/\n //remembers filters values on page load\n this.rememberGridValues = Boolean(f.remember_grid_values);\n //cookie storing filter values\n this.fltsValuesCookie = this.prfxCookieFltsValues + this.id;\n //remembers page nb on page load\n this.rememberPageNb = this.paging && f.remember_page_number;\n //cookie storing page nb\n this.pgNbCookie = this.prfxCookiePageNb + this.id;\n //remembers page length on page load\n this.rememberPageLen = this.paging && f.remember_page_length;\n //cookie storing page length\n this.pgLenCookie = this.prfxCookiePageLen + this.id;\n\n /*** extensions ***/\n //imports external script\n this.extensions = f.extensions;\n this.hasExtensions = Types.isArray(this.extensions);\n\n /*** themes ***/\n this.enableDefaultTheme = Boolean(f.enable_default_theme);\n //imports themes\n this.hasThemes = (this.enableDefaultTheme || Types.isArray(f.themes));\n this.themes = f.themes || [];\n //themes path\n this.themesPath = f.themes_path || this.stylePath + 'themes/';\n\n // Features registry\n this.Mod = {};\n\n // Extensions registry\n this.ExtRegistry = {};\n\n /*** TF events ***/\n this.Evt = {\n // Detect key\n detectKey(e) {\n if(!this.enterKey){ return; }\n if(e){\n let key = Event.keyCode(e);\n if(key===13){\n this.filter();\n Event.cancel(e);\n Event.stop(e);\n } else {\n this.isUserTyping = true;\n global.clearInterval(this.autoFilterTimer);\n this.autoFilterTimer = null;\n }\n }\n },\n // if auto-filter on, detect user is typing and filter columns\n onKeyUp(e) {\n if(!this.autoFilter){\n return;\n }\n let key = Event.keyCode(e);\n this.isUserTyping = false;\n\n function filter() {\n /*jshint validthis:true */\n global.clearInterval(this.autoFilterTimer);\n this.autoFilterTimer = null;\n if(!this.isUserTyping){\n this.filter();\n this.isUserTyping = null;\n }\n }\n\n if(key!==13 && key!==9 && key!==27 && key!==38 && key!==40) {\n if(this.autoFilterTimer === null){\n this.autoFilterTimer = global.setInterval(\n filter.bind(this), this.autoFilterDelay);\n }\n } else {\n global.clearInterval(this.autoFilterTimer);\n this.autoFilterTimer = null;\n }\n },\n // if auto-filter on, detect user is typing\n onKeyDown() {\n if(!this.autoFilter) { return; }\n this.isUserTyping = true;\n },\n // if auto-filter on, clear interval on filter blur\n onInpBlur() {\n if(this.autoFilter){\n this.isUserTyping = false;\n global.clearInterval(this.autoFilterTimer);\n }\n this.emitter.emit('filter-blur', this);\n },\n // set focused text-box filter as active\n onInpFocus(e) {\n let elm = Event.target(e);\n this.activeFilterId = elm.getAttribute('id');\n this.activeFlt = Dom.id(this.activeFilterId);\n this.emitter.emit('filter-focus', this);\n }\n };\n }\n\n /**\n * Initialise features and layout\n */\n init(){\n if(this._hasGrid){\n return;\n }\n\n let Mod = this.Mod;\n let n = this.singleSearchFlt ? 1 : this.nbCells,\n inpclass;\n\n //loads stylesheet if not imported\n this.import(this.stylesheetId, this.stylesheet, null, 'link');\n\n //loads theme\n if(this.hasThemes){ this.loadThemes(); }\n\n // Instantiate help feature and initialise only if set true\n if(!Mod.help){\n Mod.help = new Help(this);\n }\n if(this.help){\n Mod.help.init();\n }\n\n if(this.rememberGridValues || this.rememberPageNb ||\n this.rememberPageLen){\n if(!Mod.store){\n Mod.store = new Store(this);\n }\n Mod.store.init();\n }\n\n if(this.gridLayout){\n if(!Mod.gridLayout){\n Mod.gridLayout = new GridLayout(this);\n }\n Mod.gridLayout.init();\n }\n\n if(this.loader){\n if(!Mod.loader){\n Mod.loader = new Loader(this);\n }\n Mod.loader.init();\n }\n\n if(this.highlightKeywords){\n Mod.highlightKeyword = new HighlightKeyword(this);\n Mod.highlightKeyword.init();\n }\n\n if(this.popupFilters){\n if(!Mod.popupFilter){\n Mod.popupFilter = new PopupFilter(this);\n }\n Mod.popupFilter.init();\n }\n\n //filters grid is not generated\n if(!this.fltGrid){\n this._initNoFilters();\n } else {\n let fltrow = this._insertFiltersRow();\n\n this.nbFilterableRows = this.getRowsNb();\n this.nbVisibleRows = this.nbFilterableRows;\n this.nbRows = this.tbl.rows.length;\n\n // Generate filters\n for(let i=0; i this.enforceVisibility());\n this.enforceVisibility();\n }\n if(this.rowsCounter){\n Mod.rowsCounter = new RowsCounter(this);\n Mod.rowsCounter.init();\n }\n if(this.statusBar){\n Mod.statusBar = new StatusBar(this);\n Mod.statusBar.init();\n }\n if(this.paging){\n if(!Mod.paging){\n Mod.paging = new Paging(this);\n Mod.paging.init();\n } else{\n Mod.paging.reset();\n }\n }\n if(this.btnReset){\n Mod.clearButton = new ClearButton(this);\n Mod.clearButton.init();\n }\n\n if(this.hasColWidths && !this.gridLayout){\n this.setColWidths();\n }\n if(this.alternateRows){\n Mod.alternateRows = new AlternateRows(this);\n Mod.alternateRows.init();\n }\n if(this.noResults){\n if(!Mod.noResults){\n Mod.noResults = new NoResults(this);\n }\n Mod.noResults.init();\n }\n\n this._hasGrid = true;\n\n if(this.rememberGridValues || this.rememberPageLen ||\n this.rememberPageNb){\n this.resetValues();\n }\n\n //TF css class is added to table\n if(!this.gridLayout){\n Dom.addClass(this.tbl, this.prfxTf);\n }\n\n /* Loads extensions */\n if(this.hasExtensions){\n this.initExtensions();\n }\n\n // Subscribe to events\n if(this.markActiveColumns){\n this.emitter.on(['before-filtering'],\n ()=> this.clearActiveColumns());\n this.emitter.on(['cell-processed'],\n (tf, colIndex)=> this.markActiveColumn(colIndex));\n }\n if(this.linkedFilters){\n this.emitter.on(['after-filtering'], ()=> this.linkFilters());\n }\n\n if(this.onFiltersLoaded){\n this.onFiltersLoaded.call(null, this);\n }\n\n this.initialized = true;\n this.emitter.emit('initialized', this);\n }\n\n /**\n * Insert filters row at initialization\n */\n _insertFiltersRow() {\n if(this.gridLayout){\n return;\n }\n let fltrow;\n\n let thead = Dom.tag(this.tbl, 'thead');\n if(thead.length > 0){\n fltrow = thead[0].insertRow(this.filtersRowIndex);\n } else {\n fltrow = this.tbl.insertRow(this.filtersRowIndex);\n }\n\n if(this.headersRow > 1 && this.filtersRowIndex <= this.headersRow){\n this.headersRow++;\n }\n\n fltrow.className = this.fltsRowCssClass;\n\n if(this.isExternalFlt){\n fltrow.style.display = 'none';\n }\n\n this.emitter.emit('filters-row-inserted', this, fltrow);\n return fltrow;\n }\n\n /**\n * Initialize filtersless table\n */\n _initNoFilters(){\n if(this.fltGrid){\n return;\n }\n this.refRow = this.refRow > 0 ? this.refRow-1 : 0;\n this.nbFilterableRows = this.getRowsNb();\n this.nbVisibleRows = this.nbFilterableRows;\n this.nbRows = this.nbFilterableRows + this.refRow;\n }\n\n /**\n * Build input filter type\n * @param {Number} colIndex Column index\n * @param {String} cssClass Css class applied to filter\n * @param {DOMElement} container Container DOM element\n */\n _buildInputFilter(colIndex, cssClass, container){\n let col = this.getFilterType(colIndex);\n let externalFltTgtId = this.isExternalFlt ?\n this.externalFltTgtIds[colIndex] : null;\n let inptype = col===this.fltTypeInp ? 'text' : 'hidden';\n let inp = Dom.create(this.fltTypeInp,\n ['id', this.prfxFlt+colIndex+'_'+this.id],\n ['type', inptype], ['ct', colIndex]);\n\n if(inptype !== 'hidden' && this.watermark){\n inp.setAttribute('placeholder',\n this.isWatermarkArray ? (this.watermark[colIndex] || '') :\n this.watermark\n );\n }\n inp.className = cssClass || this.fltCssClass;\n Event.add(inp, 'focus', this.Evt.onInpFocus.bind(this));\n\n //filter is appended in custom element\n if(externalFltTgtId){\n Dom.id(externalFltTgtId).appendChild(inp);\n this.externalFltEls.push(inp);\n } else {\n container.appendChild(inp);\n }\n\n this.fltIds.push(inp.id);\n\n Event.add(inp, 'keypress', this.Evt.detectKey.bind(this));\n Event.add(inp, 'keydown', this.Evt.onKeyDown.bind(this));\n Event.add(inp, 'keyup', this.Evt.onKeyUp.bind(this));\n Event.add(inp, 'blur', this.Evt.onInpBlur.bind(this));\n }\n\n /**\n * Build submit button\n * @param {Number} colIndex Column index\n * @param {DOMElement} container Container DOM element\n */\n _buildSubmitButton(colIndex, container){\n let externalFltTgtId = this.isExternalFlt ?\n this.externalFltTgtIds[colIndex] : null;\n let btn = Dom.create(this.fltTypeInp,\n ['id', this.prfxValButton+colIndex+'_'+this.id],\n ['type', 'button'], ['value', this.btnText]);\n btn.className = this.btnCssClass;\n\n //filter is appended in custom element\n if(externalFltTgtId){\n Dom.id(externalFltTgtId).appendChild(btn);\n } else{\n container.appendChild(btn);\n }\n\n Event.add(btn, 'click', ()=> this.filter());\n }\n\n /**\n * Return a feature instance for a given name\n * @param {String} name Name of the feature\n * @return {Object}\n */\n feature(name){\n return this.Mod[name];\n }\n\n /**\n * Initialise all the extensions defined in the configuration object\n */\n initExtensions(){\n let exts = this.extensions;\n // Set config's publicPath dynamically for Webpack...\n __webpack_public_path__ = this.basePath;\n\n this.emitter.emit('before-loading-extensions', this);\n for(let i=0, len=exts.length; i {\n let inst = new mod.default(this, ext);\n inst.init();\n this.ExtRegistry[name] = inst;\n });\n }\n\n /**\n * Get an extension instance\n * @param {String} name Name of the extension\n * @return {Object} Extension instance\n */\n extension(name){\n return this.ExtRegistry[name];\n }\n\n /**\n * Check passed extension name exists\n * @param {String} name Name of the extension\n * @return {Boolean}\n */\n hasExtension(name){\n return !Types.isEmpty(this.ExtRegistry[name]);\n }\n\n /**\n * Destroy all the extensions defined in the configuration object\n */\n destroyExtensions(){\n let exts = this.extensions;\n\n for(let i=0, len=exts.length; i';\n\n //Paging buttons\n this.btnPrevPageHtml = '';\n this.btnNextPageHtml = '';\n this.btnFirstPageHtml = '';\n this.btnLastPageHtml = '';\n\n //Loader\n this.loader = true;\n this.loaderHtml = '';\n this.loaderText = null;\n\n this.emitter.emit('after-loading-themes', this);\n }\n\n /**\n * Return stylesheet DOM element for a given theme name\n * @return {DOMElement} stylesheet element\n */\n getStylesheet(name='default'){\n return Dom.id(this.prfxTf + name);\n }\n\n /**\n * Destroy filter grid\n */\n destroy(){\n if(!this._hasGrid){\n return;\n }\n let rows = this.tbl.rows,\n Mod = this.Mod,\n emitter = this.emitter;\n\n if(this.isExternalFlt && !this.popupFilters){\n this.removeExternalFlts();\n }\n if(this.infDiv){\n this.removeToolbar();\n }\n if(this.markActiveColumns){\n this.clearActiveColumns();\n emitter.off(['before-filtering'], ()=> this.clearActiveColumns());\n emitter.off(['cell-processed'],\n (tf, colIndex)=> this.markActiveColumn(colIndex));\n }\n if(this.hasExtensions){\n this.destroyExtensions();\n }\n\n this.validateAllRows();\n\n if(this.fltGrid && !this.gridLayout){\n this.fltGridEl = rows[this.filtersRowIndex];\n this.tbl.deleteRow(this.filtersRowIndex);\n }\n\n // broadcast destroy event\n emitter.emit('destroy', this);\n\n // Destroy modules\n // TODO: subcribe modules to destroy event instead\n Object.keys(Mod).forEach(function(key){\n var feature = Mod[key];\n if(feature && Types.isFn(feature.destroy)){\n feature.destroy();\n }\n });\n\n // unsubscribe to events\n if(this.hasVisibleRows){\n emitter.off(['after-filtering'], ()=> this.enforceVisibility());\n }\n if(this.linkedFilters){\n emitter.off(['after-filtering'], ()=> this.linkFilters());\n }\n\n Dom.removeClass(this.tbl, this.prfxTf);\n this.nbHiddenRows = 0;\n this.validRowsIndex = [];\n this.fltIds = [];\n this.activeFlt = null;\n this._hasGrid = false;\n this.initialized = false;\n }\n\n /**\n * Generate container element for paging, reset button, rows counter etc.\n */\n setToolbar(){\n if(this.infDiv){\n return;\n }\n\n /*** container div ***/\n let infdiv = Dom.create('div', ['id', this.prfxInfDiv+this.id]);\n infdiv.className = this.infDivCssClass;\n\n //custom container\n if(this.toolBarTgtId){\n Dom.id(this.toolBarTgtId).appendChild(infdiv);\n }\n //grid-layout\n else if(this.gridLayout){\n let gridLayout = this.Mod.gridLayout;\n gridLayout.tblMainCont.appendChild(infdiv);\n infdiv.className = gridLayout.gridInfDivCssClass;\n }\n //default location: just above the table\n else{\n var cont = Dom.create('caption');\n cont.appendChild(infdiv);\n this.tbl.insertBefore(cont, this.tbl.firstChild);\n }\n this.infDiv = Dom.id(this.prfxInfDiv+this.id);\n\n /*** left div containing rows # displayer ***/\n let ldiv = Dom.create('div', ['id', this.prfxLDiv+this.id]);\n ldiv.className = this.lDivCssClass;\n infdiv.appendChild(ldiv);\n this.lDiv = Dom.id(this.prfxLDiv+this.id);\n\n /*** right div containing reset button\n + nb results per page select ***/\n let rdiv = Dom.create('div', ['id', this.prfxRDiv+this.id]);\n rdiv.className = this.rDivCssClass;\n infdiv.appendChild(rdiv);\n this.rDiv = Dom.id(this.prfxRDiv+this.id);\n\n /*** mid div containing paging elements ***/\n let mdiv = Dom.create('div', ['id', this.prfxMDiv+this.id]);\n mdiv.className = this.mDivCssClass;\n infdiv.appendChild(mdiv);\n this.mDiv = Dom.id(this.prfxMDiv+this.id);\n\n // emit help initialisation only if undefined\n if(Types.isUndef(this.help)){\n this.emitter.emit('init-help', this);\n }\n }\n\n /**\n * Remove toolbar container element\n */\n removeToolbar(){\n if(!this.infDiv){\n return;\n }\n Dom.remove(this.infDiv);\n this.infDiv = null;\n\n let tbl = this.tbl;\n let captions = Dom.tag(tbl, 'caption');\n if(captions.length > 0){\n [].forEach.call(captions, (elm)=> tbl.removeChild(elm));\n }\n }\n\n /**\n * Remove all the external column filters\n */\n removeExternalFlts(){\n if(!this.isExternalFlt){\n return;\n }\n let ids = this.externalFltTgtIds,\n len = ids.length;\n for(let ct=0; ct {\n if(val !== ' '){\n this.setFilterValue(idx, val);\n }\n });\n this.filter();\n }\n\n /**\n * Filter the table by retrieving the data from each cell in every single\n * row and comparing it to the search term for current column. A row is\n * hidden when all the search terms are not found in inspected row.\n */\n filter(){\n if(!this.fltGrid || !this._hasGrid){\n return;\n }\n //invoke onbefore callback\n if(this.onBeforeFilter){\n this.onBeforeFilter.call(null, this);\n }\n this.emitter.emit('before-filtering', this);\n\n let row = this.tbl.rows,\n hiddenrows = 0;\n\n this.validRowsIndex = [];\n // search args re-init\n let searchArgs = this.getFiltersValue();\n\n var numCellData, nbFormat;\n var re_le = new RegExp(this.leOperator),\n re_ge = new RegExp(this.geOperator),\n re_l = new RegExp(this.lwOperator),\n re_g = new RegExp(this.grOperator),\n re_d = new RegExp(this.dfOperator),\n re_lk = new RegExp(Str.rgxEsc(this.lkOperator)),\n re_eq = new RegExp(this.eqOperator),\n re_st = new RegExp(this.stOperator),\n re_en = new RegExp(this.enOperator),\n // re_an = new RegExp(this.anOperator),\n // re_cr = new RegExp(this.curExp),\n re_em = this.emOperator,\n re_nm = this.nmOperator,\n re_re = new RegExp(Str.rgxEsc(this.rgxOperator));\n\n //keyword highlighting\n function highlight(str, ok, cell){\n /*jshint validthis:true */\n if(this.highlightKeywords && ok){\n str = str.replace(re_lk, '');\n str = str.replace(re_eq, '');\n str = str.replace(re_st, '');\n str = str.replace(re_en, '');\n let w = str;\n if(re_le.test(str) || re_ge.test(str) || re_l.test(str) ||\n re_g.test(str) || re_d.test(str)){\n w = Dom.getText(cell);\n }\n if(w !== ''){\n this.emitter.emit('highlight-keyword', this, cell, w);\n }\n }\n }\n\n //looks for search argument in current row\n function hasArg(sA, cellData, j){\n /*jshint validthis:true */\n sA = Str.matchCase(sA, this.caseSensitive);\n\n let occurence,\n removeNbFormat = Helpers.removeNbFormat;\n\n //Search arg operator tests\n let hasLO = re_l.test(sA),\n hasLE = re_le.test(sA),\n hasGR = re_g.test(sA),\n hasGE = re_ge.test(sA),\n hasDF = re_d.test(sA),\n hasEQ = re_eq.test(sA),\n hasLK = re_lk.test(sA),\n // hasAN = re_an.test(sA),\n hasST = re_st.test(sA),\n hasEN = re_en.test(sA),\n hasEM = (re_em === sA),\n hasNM = (re_nm === sA),\n hasRE = re_re.test(sA);\n\n //Search arg dates tests\n let isLDate = hasLO &&\n DateHelper.isValid(sA.replace(re_l,''), dtType);\n let isLEDate = hasLE &&\n DateHelper.isValid(sA.replace(re_le,''), dtType);\n let isGDate = hasGR &&\n DateHelper.isValid(sA.replace(re_g,''), dtType);\n let isGEDate = hasGE &&\n DateHelper.isValid(sA.replace(re_ge,''), dtType);\n let isDFDate = hasDF &&\n DateHelper.isValid(sA.replace(re_d,''), dtType);\n let isEQDate = hasEQ &&\n DateHelper.isValid(sA.replace(re_eq,''), dtType);\n\n let dte1, dte2;\n //dates\n if(DateHelper.isValid(cellData, dtType)){\n dte1 = DateHelper.format(cellData, dtType);\n // lower date\n if(isLDate){\n dte2 = DateHelper.format(sA.replace(re_l,''), dtType);\n occurence = dte1 < dte2;\n }\n // lower equal date\n else if(isLEDate){\n dte2 = DateHelper.format(sA.replace(re_le,''), dtType);\n occurence = dte1 <= dte2;\n }\n // greater equal date\n else if(isGEDate){\n dte2 = DateHelper.format(sA.replace(re_ge,''), dtType);\n occurence = dte1 >= dte2;\n }\n // greater date\n else if(isGDate){\n dte2 = DateHelper.format(sA.replace(re_g,''), dtType);\n occurence = dte1 > dte2;\n }\n // different date\n else if(isDFDate){\n dte2 = DateHelper.format(sA.replace(re_d,''), dtType);\n occurence = dte1.toString() != dte2.toString();\n }\n // equal date\n else if(isEQDate){\n dte2 = DateHelper.format(sA.replace(re_eq,''), dtType);\n occurence = dte1.toString() == dte2.toString();\n }\n // searched keyword with * operator doesn't have to be a date\n else if(re_lk.test(sA)){// like date\n occurence = Str.contains(sA.replace(re_lk,''), cellData,\n false, this.caseSensitive);\n }\n else if(DateHelper.isValid(sA,dtType)){\n dte2 = DateHelper.format(sA,dtType);\n occurence = dte1.toString() === dte2.toString();\n }\n //empty\n else if(hasEM){\n occurence = Str.isEmpty(cellData);\n }\n //non-empty\n else if(hasNM){\n occurence = !Str.isEmpty(cellData);\n } else {\n occurence = Str.contains(sA, cellData, this.isExactMatch(j),\n this.caseSensitive);\n }\n }\n\n else{\n //first numbers need to be formated\n if(this.hasColNbFormat && this.colNbFormat[j]){\n numCellData = removeNbFormat(\n cellData, this.colNbFormat[j]);\n nbFormat = this.colNbFormat[j];\n } else {\n if(this.thousandsSeparator === ',' &&\n this.decimalSeparator === '.'){\n numCellData = removeNbFormat(cellData, 'us');\n nbFormat = 'us';\n } else {\n numCellData = removeNbFormat(cellData, 'eu');\n nbFormat = 'eu';\n }\n }\n\n // first checks if there is any operator (<,>,<=,>=,!,*,=,{,},\n // rgx:)\n // lower equal\n if(hasLE){\n occurence = numCellData <= removeNbFormat(\n sA.replace(re_le, ''), nbFormat);\n }\n //greater equal\n else if(hasGE){\n occurence = numCellData >= removeNbFormat(\n sA.replace(re_ge, ''), nbFormat);\n }\n //lower\n else if(hasLO){\n occurence = numCellData < removeNbFormat(\n sA.replace(re_l, ''), nbFormat);\n }\n //greater\n else if(hasGR){\n occurence = numCellData > removeNbFormat(\n sA.replace(re_g, ''), nbFormat);\n }\n //different\n else if(hasDF){\n occurence = Str.contains(sA.replace(re_d, ''), cellData,\n false, this.caseSensitive) ? false : true;\n }\n //like\n else if(hasLK){\n occurence = Str.contains(sA.replace(re_lk, ''), cellData,\n false, this.caseSensitive);\n }\n //equal\n else if(hasEQ){\n occurence = Str.contains(sA.replace(re_eq, ''), cellData,\n true, this.caseSensitive);\n }\n //starts with\n else if(hasST){\n occurence = cellData.indexOf(sA.replace(re_st, '')) === 0 ?\n true : false;\n }\n //ends with\n else if(hasEN){\n let searchArg = sA.replace(re_en, '');\n occurence =\n cellData.lastIndexOf(searchArg, cellData.length-1) ===\n (cellData.length-1)-(searchArg.length-1) &&\n cellData.lastIndexOf(\n searchArg, cellData.length-1) > -1 ? true : false;\n }\n //empty\n else if(hasEM){\n occurence = Str.isEmpty(cellData);\n }\n //non-empty\n else if(hasNM){\n occurence = !Str.isEmpty(cellData);\n }\n //regexp\n else if(hasRE){\n //in case regexp fires an exception\n try{\n //operator is removed\n let srchArg = sA.replace(re_re,'');\n let rgx = new RegExp(srchArg);\n occurence = rgx.test(cellData);\n } catch(e) { occurence = false; }\n } else {\n occurence = Str.contains(sA, cellData, this.isExactMatch(j),\n this.caseSensitive);\n }\n\n }//else\n return occurence;\n }//fn\n\n for(let k=this.refRow; k 1,\n //multiple search parameter operator &&\n sAAndSplit = sA.toString().split(this.anOperator),\n //multiple search && parameter boolean\n hasMultiAndSA = sAAndSplit.length > 1;\n\n //detect operators or array query\n if(Types.isArray(sA) || hasMultiOrSA || hasMultiAndSA){\n let cS,\n s,\n occur = false;\n if(Types.isArray(sA)){\n s = sA;\n } else {\n s = hasMultiOrSA ? sAOrSplit : sAAndSplit;\n }\n // TODO: improve clarity/readability of this block\n for(let w=0, len=s.length; w 0){\n isExludedRow = exclude.indexOf(i) != -1;\n }\n let cell = row[i].cells,\n nchilds = cell.length;\n\n // checks if row has exact cell # and is not excluded\n if(nchilds === this.nbCells && !isExludedRow){\n // this loop retrieves cell data\n for(let j=0; j 0 ? fltValues : '';\n }\n //checklist\n else if(fltColType === this.fltTypeCheckList){\n // TODO: extract a method in checklist module from below\n if(flt.getAttribute('value') !== null){\n fltValues = flt.getAttribute('value');\n //removes last operator ||\n fltValues = fltValues.substr(0, fltValues.length-3);\n //convert || separated values into array\n fltValues = fltValues.split(' ' + this.orOperator + ' ');\n }\n //return empty string if collection is empty\n fltValue = fltValues.length > 0 ? fltValues : '';\n }\n //return an empty string if collection contains a single empty string\n if(Types.isArray(fltValue) && fltValue.length === 1 &&\n fltValue[0] === ''){\n fltValue = '';\n }\n return fltValue;\n }\n\n /**\n * Return the filters' values\n * @return {Array} List of filters' values\n */\n getFiltersValue(){\n if(!this.fltGrid){\n return;\n }\n let searchArgs = [];\n for(let i=0, len=this.fltIds.length; i 0;\n let frag = !tblHasColTag ? doc.createDocumentFragment() : null;\n for(let k=0; k nrows\n if(row <= this.nbRows){\n this.validateRow(row, true);\n }\n }\n }\n\n /**\n * Clear all the filters' values\n */\n clearFilters(){\n if(!this.fltGrid){\n return;\n }\n\n this.emitter.emit('before-clearing-filters', this);\n\n if(this.onBeforeReset){\n this.onBeforeReset.call(null, this, this.getFiltersValue());\n }\n for(let i=0, len=this.fltIds.length; i IE onload event works only for scripts, not for stylesheets\n file.onload = file.onreadystatechange = function(){\n if(!isLoaded &&\n (!this.readyState || this.readyState === 'loaded' ||\n this.readyState === 'complete')){\n isLoaded = true;\n if(typeof callback === 'function'){\n callback.call(null, o);\n }\n }\n };\n file.onerror = function(){\n throw new Error('TF script could not load: ' + filePath);\n };\n head.appendChild(file);\n }\n\n /**\n * Check if table has filters grid\n * @return {Boolean}\n */\n hasGrid(){\n return this._hasGrid;\n }\n\n /**\n * Get list of filter IDs\n * @return {[type]} [description]\n */\n getFiltersId(){\n return this.fltIds || [];\n }\n\n /**\n * Get filtered (valid) rows indexes\n * @param {Boolean} reCalc Force calculation of filtered rows list\n * @return {Array} List of row indexes\n */\n getValidRows(reCalc){\n if(!reCalc){\n return this.validRowsIndex;\n }\n\n this.validRowsIndex = [];\n for(let k=this.refRow; k {\n // for (let arg of args) {\n let argtype = typeof arg;\n if(argtype === 'object' && arg && arg.nodeName === 'TABLE'){\n this.tbl = arg;\n this.id = arg.id || `tf_${new Date().getTime()}_`;\n } else if(argtype === 'string'){\n this.id = arg;\n this.tbl = Dom.id(arg);\n } else if(argtype === 'number'){\n this.startRow = arg;\n } else if(argtype === 'object'){\n this.cfg = arg;\n }\n // }\n });\n\n if(!this.tbl || this.tbl.nodeName != 'TABLE' || this.getRowsNb() === 0){\n throw new Error(\n 'Could not instantiate TableFilter: HTML table not found.');\n }\n\n // configuration object\n let f = this.cfg;\n\n this.emitter = new Emitter();\n\n //Start row et cols nb\n this.refRow = this.startRow === null ? 2 : (this.startRow+1);\n try{ this.nbCells = this.getCellsNb(this.refRow); }\n catch(e){ this.nbCells = this.getCellsNb(0); }\n\n //default script base path\n this.basePath = f.base_path || 'tablefilter/';\n\n /*** filter types ***/\n this.fltTypeInp = 'input';\n this.fltTypeSlc = 'select';\n this.fltTypeMulti = 'multiple';\n this.fltTypeCheckList = 'checklist';\n this.fltTypeNone = 'none';\n\n /*** filters' grid properties ***/\n\n //enables/disables filter grid\n this.fltGrid = f.grid === false ? false : true;\n\n //enables/disables grid layout (fixed headers)\n this.gridLayout = Boolean(f.grid_layout);\n\n this.filtersRowIndex = isNaN(f.filters_row_index) ?\n 0 : f.filters_row_index;\n this.headersRow = isNaN(f.headers_row_index) ?\n (this.filtersRowIndex === 0 ? 1 : 0) : f.headers_row_index;\n\n //defines tag of the cells containing filters (td/th)\n this.fltCellTag = f.filters_cell_tag!=='th' ||\n f.filters_cell_tag!=='td' ? 'td' : f.filters_cell_tag;\n\n //stores filters ids\n this.fltIds = [];\n //stores filters DOM elements\n this.fltElms = [];\n //stores valid rows indexes (rows visible upon filtering)\n this.validRowsIndex = [];\n //stores filters row element\n this.fltGridEl = null;\n //container div for paging elements, reset btn etc.\n this.infDiv = null;\n //div for rows counter\n this.lDiv = null;\n //div for reset button and results per page select\n this.rDiv = null;\n //div for paging elements\n this.mDiv = null;\n\n //defines css class for div containing paging elements, rows counter etc\n this.infDivCssClass = f.inf_div_css_class || 'inf';\n //defines css class for left div\n this.lDivCssClass = f.left_div_css_class || 'ldiv';\n //defines css class for right div\n this.rDivCssClass = f.right_div_css_class || 'rdiv';\n //defines css class for mid div\n this.mDivCssClass = f.middle_div_css_class || 'mdiv';\n //table container div css class\n this.contDivCssClass = f.content_div_css_class || 'cont';\n\n /*** filters' grid appearance ***/\n //stylesheet file\n this.stylePath = f.style_path || this.basePath + 'style/';\n this.stylesheet = f.stylesheet || this.stylePath+'tablefilter.css';\n this.stylesheetId = this.id + '_style';\n //defines css class for filters row\n this.fltsRowCssClass = f.flts_row_css_class || 'fltrow';\n //enables/disables icons (paging, reset button)\n this.enableIcons = f.enable_icons===false ? false : true;\n //enables/disbles rows alternating bg colors\n this.alternateRows = Boolean(f.alternate_rows);\n //defines widths of columns\n this.hasColWidths = Types.isArray(f.col_widths);\n this.colWidths = this.hasColWidths ? f.col_widths : null;\n //defines css class for filters\n this.fltCssClass = f.flt_css_class || 'flt';\n //defines css class for multiple selects filters\n this.fltMultiCssClass = f.flt_multi_css_class || 'flt_multi';\n //defines css class for filters\n this.fltSmallCssClass = f.flt_small_css_class || 'flt_s';\n //defines css class for single-filter\n this.singleFltCssClass = f.single_flt_css_class || 'single_flt';\n\n /*** filters' grid behaviours ***/\n //enables/disables enter key\n this.enterKey = f.enter_key===false ? false : true;\n //calls function before filtering starts\n this.onBeforeFilter = Types.isFn(f.on_before_filter) ?\n f.on_before_filter : null;\n //calls function after filtering\n this.onAfterFilter = Types.isFn(f.on_after_filter) ?\n f.on_after_filter : null;\n //enables/disables case sensitivity\n this.caseSensitive = Boolean(f.case_sensitive);\n //has exact match per column\n this.hasExactMatchByCol = Types.isArray(f.columns_exact_match);\n this.exactMatchByCol = this.hasExactMatchByCol ?\n f.columns_exact_match : [];\n //enables/disbles exact match for search\n this.exactMatch = Boolean(f.exact_match);\n //refreshes drop-down lists upon validation\n this.linkedFilters = Boolean(f.linked_filters);\n //wheter excluded options are disabled\n this.disableExcludedOptions = Boolean(f.disable_excluded_options);\n //stores active filter element\n this.activeFlt = null;\n //id of active filter\n this.activeFilterId = null;\n //enables always visible rows\n this.hasVisibleRows = Boolean(f.rows_always_visible);\n //array containing always visible rows\n this.visibleRows = this.hasVisibleRows ? f.rows_always_visible : [];\n //enables/disables external filters generation\n this.isExternalFlt = Boolean(f.external_flt_grid);\n //array containing ids of external elements containing filters\n this.externalFltTgtIds = f.external_flt_grid_ids || [];\n //stores filters elements if isExternalFlt is true\n this.externalFltEls = [];\n //delays any filtering process if loader true\n this.execDelay = !isNaN(f.exec_delay) ? parseInt(f.exec_delay,10) : 100;\n //calls function when filters grid loaded\n this.onFiltersLoaded = Types.isFn(f.on_filters_loaded) ?\n f.on_filters_loaded : null;\n //enables/disables single filter search\n this.singleSearchFlt = Boolean(f.single_filter);\n //calls function after row is validated\n this.onRowValidated = Types.isFn(f.on_row_validated) ?\n f.on_row_validated : null;\n //array defining columns for customCellData event\n this.customCellDataCols = f.custom_cell_data_cols ?\n f.custom_cell_data_cols : [];\n //calls custom function for retrieving cell data\n this.customCellData = Types.isFn(f.custom_cell_data) ?\n f.custom_cell_data : null;\n //input watermark text array\n this.watermark = f.watermark || '';\n this.isWatermarkArray = Types.isArray(this.watermark);\n //id of toolbar container element\n this.toolBarTgtId = f.toolbar_target_id || null;\n //enables/disables help div\n this.help = Types.isUndef(f.help_instructions) ?\n undefined : Boolean(f.help_instructions);\n //popup filters\n this.popupFilters = Boolean(f.popup_filters);\n //active columns color\n this.markActiveColumns = Boolean(f.mark_active_columns);\n //defines css class for active column header\n this.activeColumnsCssClass = f.active_columns_css_class ||\n 'activeHeader';\n //calls function before active column header is marked\n this.onBeforeActiveColumn = Types.isFn(f.on_before_active_column) ?\n f.on_before_active_column : null;\n //calls function after active column header is marked\n this.onAfterActiveColumn = Types.isFn(f.on_after_active_column) ?\n f.on_after_active_column : null;\n\n /*** select filter's customisation and behaviours ***/\n //defines 1st option text\n this.displayAllText = f.display_all_text || 'Clear';\n //enables/disables empty option in combo-box filters\n this.enableEmptyOption = Boolean(f.enable_empty_option);\n //defines empty option text\n this.emptyText = f.empty_text || '(Empty)';\n //enables/disables non empty option in combo-box filters\n this.enableNonEmptyOption = Boolean(f.enable_non_empty_option);\n //defines empty option text\n this.nonEmptyText = f.non_empty_text || '(Non empty)';\n //enables/disables onChange event on combo-box\n this.onSlcChange = f.on_change===false ? false : true;\n //enables/disables select options sorting\n this.sortSlc = f.sort_select===false ? false : true;\n //enables/disables ascending numeric options sorting\n this.isSortNumAsc = Boolean(f.sort_num_asc);\n this.sortNumAsc = this.isSortNumAsc ? f.sort_num_asc : [];\n //enables/disables descending numeric options sorting\n this.isSortNumDesc = Boolean(f.sort_num_desc);\n this.sortNumDesc = this.isSortNumDesc ? f.sort_num_desc : [];\n //Select filters are populated on demand\n this.loadFltOnDemand = Boolean(f.load_filters_on_demand);\n this.hasCustomOptions = Types.isObj(f.custom_options);\n this.customOptions = f.custom_options;\n\n /*** Filter operators ***/\n this.rgxOperator = f.regexp_operator || 'rgx:';\n this.emOperator = f.empty_operator || '[empty]';\n this.nmOperator = f.nonempty_operator || '[nonempty]';\n this.orOperator = f.or_operator || '||';\n this.anOperator = f.and_operator || '&&';\n this.grOperator = f.greater_operator || '>';\n this.lwOperator = f.lower_operator || '<';\n this.leOperator = f.lower_equal_operator || '<=';\n this.geOperator = f.greater_equal_operator || '>=';\n this.dfOperator = f.different_operator || '!';\n this.lkOperator = f.like_operator || '*';\n this.eqOperator = f.equal_operator || '=';\n this.stOperator = f.start_with_operator || '{';\n this.enOperator = f.end_with_operator || '}';\n this.curExp = f.cur_exp || '^[¥£€$]';\n this.separator = f.separator || ',';\n\n /*** rows counter ***/\n //show/hides rows counter\n this.rowsCounter = Boolean(f.rows_counter);\n\n /*** status bar ***/\n //show/hides status bar\n this.statusBar = Boolean(f.status_bar);\n\n /*** loader ***/\n //enables/disables loader/spinner indicator\n this.loader = Boolean(f.loader);\n\n /*** validation - reset buttons/links ***/\n //show/hides filter's validation button\n this.displayBtn = Boolean(f.btn);\n //defines validation button text\n this.btnText = f.btn_text || (!this.enableIcons ? 'Go' : '');\n //defines css class for validation button\n this.btnCssClass = f.btn_css_class ||\n (!this.enableIcons ? 'btnflt' : 'btnflt_icon');\n //show/hides reset link\n this.btnReset = Boolean(f.btn_reset);\n //defines css class for reset button\n this.btnResetCssClass = f.btn_reset_css_class || 'reset';\n //callback function before filters are cleared\n this.onBeforeReset = Types.isFn(f.on_before_reset) ?\n f.on_before_reset : null;\n //callback function after filters are cleared\n this.onAfterReset = Types.isFn(f.on_after_reset) ?\n f.on_after_reset : null;\n\n /*** paging ***/\n //enables/disables table paging\n this.paging = Boolean(f.paging);\n this.nbVisibleRows = 0; //nb visible rows\n this.nbHiddenRows = 0; //nb hidden rows\n\n /*** autofilter on typing ***/\n //enables/disables auto filtering, table is filtered when user stops\n //typing\n this.autoFilter = Boolean(f.auto_filter);\n //onkeyup delay timer (msecs)\n this.autoFilterDelay = !isNaN(f.auto_filter_delay) ?\n f.auto_filter_delay : 900;\n //typing indicator\n this.isUserTyping = null;\n this.autoFilterTimer = null;\n\n /*** keyword highlighting ***/\n //enables/disables keyword highlighting\n this.highlightKeywords = Boolean(f.highlight_keywords);\n\n /*** No results feature ***/\n this.noResults = Types.isObj(f.no_results_message) ||\n Boolean(f.no_results_message);\n\n /*** data types ***/\n //defines default date type (european DMY)\n this.defaultDateType = f.default_date_type || 'DMY';\n //defines default thousands separator\n //US = ',' EU = '.'\n this.thousandsSeparator = f.thousands_separator || ',';\n //defines default decimal separator\n //US & javascript = '.' EU = ','\n this.decimalSeparator = f.decimal_separator || '.';\n //enables number format per column\n this.hasColNbFormat = Types.isArray(f.col_number_format);\n //array containing columns nb formats\n this.colNbFormat = this.hasColNbFormat ? f.col_number_format : null;\n //enables date type per column\n this.hasColDateType = Types.isArray(f.col_date_type);\n //array containing columns date type\n this.colDateType = this.hasColDateType ? f.col_date_type : null;\n\n /*** ids prefixes ***/\n //css class name added to table\n this.prfxTf = 'TF';\n //filters (inputs - selects)\n this.prfxFlt = 'flt';\n //validation button\n this.prfxValButton = 'btn';\n //container div for paging elements, rows counter etc.\n this.prfxInfDiv = 'inf_';\n //left div\n this.prfxLDiv = 'ldiv_';\n //right div\n this.prfxRDiv = 'rdiv_';\n //middle div\n this.prfxMDiv = 'mdiv_';\n //filter values cookie\n this.prfxCookieFltsValues = 'tf_flts_';\n //page nb cookie\n this.prfxCookiePageNb = 'tf_pgnb_';\n //page length cookie\n this.prfxCookiePageLen = 'tf_pglen_';\n\n /*** cookies ***/\n //remembers filters values on page load\n this.rememberGridValues = Boolean(f.remember_grid_values);\n //cookie storing filter values\n this.fltsValuesCookie = this.prfxCookieFltsValues + this.id;\n //remembers page nb on page load\n this.rememberPageNb = this.paging && f.remember_page_number;\n //cookie storing page nb\n this.pgNbCookie = this.prfxCookiePageNb + this.id;\n //remembers page length on page load\n this.rememberPageLen = this.paging && f.remember_page_length;\n //cookie storing page length\n this.pgLenCookie = this.prfxCookiePageLen + this.id;\n\n /*** extensions ***/\n //imports external script\n this.extensions = f.extensions;\n this.hasExtensions = Types.isArray(this.extensions);\n\n /*** themes ***/\n this.enableDefaultTheme = Boolean(f.enable_default_theme);\n //imports themes\n this.hasThemes = (this.enableDefaultTheme || Types.isArray(f.themes));\n this.themes = f.themes || [];\n //themes path\n this.themesPath = f.themes_path || this.stylePath + 'themes/';\n\n // Features registry\n this.Mod = {};\n\n // Extensions registry\n this.ExtRegistry = {};\n\n /*** TF events ***/\n this.Evt = {\n // Detect key\n detectKey(e) {\n if(!this.enterKey){ return; }\n if(e){\n let key = Event.keyCode(e);\n if(key===13){\n this.filter();\n Event.cancel(e);\n Event.stop(e);\n } else {\n this.isUserTyping = true;\n global.clearInterval(this.autoFilterTimer);\n this.autoFilterTimer = null;\n }\n }\n },\n // if auto-filter on, detect user is typing and filter columns\n onKeyUp(e) {\n if(!this.autoFilter){\n return;\n }\n let key = Event.keyCode(e);\n this.isUserTyping = false;\n\n function filter() {\n /*jshint validthis:true */\n global.clearInterval(this.autoFilterTimer);\n this.autoFilterTimer = null;\n if(!this.isUserTyping){\n this.filter();\n this.isUserTyping = null;\n }\n }\n\n if(key!==13 && key!==9 && key!==27 && key!==38 && key!==40) {\n if(this.autoFilterTimer === null){\n this.autoFilterTimer = global.setInterval(\n filter.bind(this), this.autoFilterDelay);\n }\n } else {\n global.clearInterval(this.autoFilterTimer);\n this.autoFilterTimer = null;\n }\n },\n // if auto-filter on, detect user is typing\n onKeyDown() {\n if(!this.autoFilter) { return; }\n this.isUserTyping = true;\n },\n // if auto-filter on, clear interval on filter blur\n onInpBlur() {\n if(this.autoFilter){\n this.isUserTyping = false;\n global.clearInterval(this.autoFilterTimer);\n }\n this.emitter.emit('filter-blur', this);\n },\n // set focused text-box filter as active\n onInpFocus(e) {\n let elm = Event.target(e);\n this.activeFilterId = elm.getAttribute('id');\n this.activeFlt = Dom.id(this.activeFilterId);\n this.emitter.emit('filter-focus', this);\n }\n };\n }\n\n /**\n * Initialise features and layout\n */\n init(){\n if(this._hasGrid){\n return;\n }\n\n let Mod = this.Mod;\n let n = this.singleSearchFlt ? 1 : this.nbCells,\n inpclass;\n\n //loads stylesheet if not imported\n this.import(this.stylesheetId, this.stylesheet, null, 'link');\n\n //loads theme\n if(this.hasThemes){ this.loadThemes(); }\n\n // Instantiate help feature and initialise only if set true\n if(!Mod.help){\n Mod.help = new Help(this);\n }\n if(this.help){\n Mod.help.init();\n }\n\n if(this.rememberGridValues || this.rememberPageNb ||\n this.rememberPageLen){\n if(!Mod.store){\n Mod.store = new Store(this);\n }\n Mod.store.init();\n }\n\n if(this.gridLayout){\n if(!Mod.gridLayout){\n Mod.gridLayout = new GridLayout(this);\n }\n Mod.gridLayout.init();\n }\n\n if(this.loader){\n if(!Mod.loader){\n Mod.loader = new Loader(this);\n }\n Mod.loader.init();\n }\n\n if(this.highlightKeywords){\n Mod.highlightKeyword = new HighlightKeyword(this);\n Mod.highlightKeyword.init();\n }\n\n if(this.popupFilters){\n if(!Mod.popupFilter){\n Mod.popupFilter = new PopupFilter(this);\n }\n Mod.popupFilter.init();\n }\n\n //filters grid is not generated\n if(!this.fltGrid){\n this._initNoFilters();\n } else {\n let fltrow = this._insertFiltersRow();\n\n this.nbFilterableRows = this.getRowsNb();\n this.nbVisibleRows = this.nbFilterableRows;\n this.nbRows = this.tbl.rows.length;\n\n // Generate filters\n for(let i=0; i this.enforceVisibility());\n this.enforceVisibility();\n }\n if(this.rowsCounter){\n Mod.rowsCounter = new RowsCounter(this);\n Mod.rowsCounter.init();\n }\n if(this.statusBar){\n Mod.statusBar = new StatusBar(this);\n Mod.statusBar.init();\n }\n if(this.paging){\n if(!Mod.paging){\n Mod.paging = new Paging(this);\n Mod.paging.init();\n } else{\n Mod.paging.reset();\n }\n }\n if(this.btnReset){\n Mod.clearButton = new ClearButton(this);\n Mod.clearButton.init();\n }\n\n if(this.hasColWidths && !this.gridLayout){\n this.setColWidths();\n }\n if(this.alternateRows){\n Mod.alternateRows = new AlternateRows(this);\n Mod.alternateRows.init();\n }\n if(this.noResults){\n if(!Mod.noResults){\n Mod.noResults = new NoResults(this);\n }\n Mod.noResults.init();\n }\n\n this._hasGrid = true;\n\n if(this.rememberGridValues || this.rememberPageLen ||\n this.rememberPageNb){\n this.resetValues();\n }\n\n //TF css class is added to table\n if(!this.gridLayout){\n Dom.addClass(this.tbl, this.prfxTf);\n }\n\n /* Loads extensions */\n if(this.hasExtensions){\n this.initExtensions();\n }\n\n // Subscribe to events\n if(this.markActiveColumns){\n this.emitter.on(['before-filtering'],\n ()=> this.clearActiveColumns());\n this.emitter.on(['cell-processed'],\n (tf, colIndex)=> this.markActiveColumn(colIndex));\n }\n if(this.linkedFilters){\n this.emitter.on(['after-filtering'], ()=> this.linkFilters());\n }\n\n if(this.onFiltersLoaded){\n this.onFiltersLoaded.call(null, this);\n }\n\n this.initialized = true;\n this.emitter.emit('initialized', this);\n }\n\n /**\n * Insert filters row at initialization\n */\n _insertFiltersRow() {\n if(this.gridLayout){\n return;\n }\n let fltrow;\n\n let thead = Dom.tag(this.tbl, 'thead');\n if(thead.length > 0){\n fltrow = thead[0].insertRow(this.filtersRowIndex);\n } else {\n fltrow = this.tbl.insertRow(this.filtersRowIndex);\n }\n\n if(this.headersRow > 1 && this.filtersRowIndex <= this.headersRow){\n this.headersRow++;\n }\n\n fltrow.className = this.fltsRowCssClass;\n\n if(this.isExternalFlt){\n fltrow.style.display = 'none';\n }\n\n this.emitter.emit('filters-row-inserted', this, fltrow);\n return fltrow;\n }\n\n /**\n * Initialize filtersless table\n */\n _initNoFilters(){\n if(this.fltGrid){\n return;\n }\n this.refRow = this.refRow > 0 ? this.refRow-1 : 0;\n this.nbFilterableRows = this.getRowsNb();\n this.nbVisibleRows = this.nbFilterableRows;\n this.nbRows = this.nbFilterableRows + this.refRow;\n }\n\n /**\n * Build input filter type\n * @param {Number} colIndex Column index\n * @param {String} cssClass Css class applied to filter\n * @param {DOMElement} container Container DOM element\n */\n _buildInputFilter(colIndex, cssClass, container){\n let col = this.getFilterType(colIndex);\n let externalFltTgtId = this.isExternalFlt ?\n this.externalFltTgtIds[colIndex] : null;\n let inptype = col===this.fltTypeInp ? 'text' : 'hidden';\n let inp = Dom.create(this.fltTypeInp,\n ['id', this.prfxFlt+colIndex+'_'+this.id],\n ['type', inptype], ['ct', colIndex]);\n\n if(inptype !== 'hidden' && this.watermark){\n inp.setAttribute('placeholder',\n this.isWatermarkArray ? (this.watermark[colIndex] || '') :\n this.watermark\n );\n }\n inp.className = cssClass || this.fltCssClass;\n Event.add(inp, 'focus', this.Evt.onInpFocus.bind(this));\n\n //filter is appended in custom element\n if(externalFltTgtId){\n Dom.id(externalFltTgtId).appendChild(inp);\n this.externalFltEls.push(inp);\n } else {\n container.appendChild(inp);\n }\n\n this.fltIds.push(inp.id);\n\n Event.add(inp, 'keypress', this.Evt.detectKey.bind(this));\n Event.add(inp, 'keydown', this.Evt.onKeyDown.bind(this));\n Event.add(inp, 'keyup', this.Evt.onKeyUp.bind(this));\n Event.add(inp, 'blur', this.Evt.onInpBlur.bind(this));\n }\n\n /**\n * Build submit button\n * @param {Number} colIndex Column index\n * @param {DOMElement} container Container DOM element\n */\n _buildSubmitButton(colIndex, container){\n let externalFltTgtId = this.isExternalFlt ?\n this.externalFltTgtIds[colIndex] : null;\n let btn = Dom.create(this.fltTypeInp,\n ['id', this.prfxValButton+colIndex+'_'+this.id],\n ['type', 'button'], ['value', this.btnText]);\n btn.className = this.btnCssClass;\n\n //filter is appended in custom element\n if(externalFltTgtId){\n Dom.id(externalFltTgtId).appendChild(btn);\n } else{\n container.appendChild(btn);\n }\n\n Event.add(btn, 'click', ()=> this.filter());\n }\n\n /**\n * Return a feature instance for a given name\n * @param {String} name Name of the feature\n * @return {Object}\n */\n feature(name){\n return this.Mod[name];\n }\n\n /**\n * Initialise all the extensions defined in the configuration object\n */\n initExtensions(){\n let exts = this.extensions;\n // Set config's publicPath dynamically for Webpack...\n __webpack_public_path__ = this.basePath;\n\n this.emitter.emit('before-loading-extensions', this);\n for(let i=0, len=exts.length; i {\n let inst = new mod.default(this, ext);\n inst.init();\n this.ExtRegistry[name] = inst;\n });\n }\n\n /**\n * Get an extension instance\n * @param {String} name Name of the extension\n * @return {Object} Extension instance\n */\n extension(name){\n return this.ExtRegistry[name];\n }\n\n /**\n * Check passed extension name exists\n * @param {String} name Name of the extension\n * @return {Boolean}\n */\n hasExtension(name){\n return !Types.isEmpty(this.ExtRegistry[name]);\n }\n\n /**\n * Destroy all the extensions defined in the configuration object\n */\n destroyExtensions(){\n let exts = this.extensions;\n\n for(let i=0, len=exts.length; i';\n\n //Paging buttons\n this.btnPrevPageHtml = '';\n this.btnNextPageHtml = '';\n this.btnFirstPageHtml = '';\n this.btnLastPageHtml = '';\n\n //Loader\n this.loader = true;\n this.loaderHtml = '';\n this.loaderText = null;\n\n this.emitter.emit('after-loading-themes', this);\n }\n\n /**\n * Return stylesheet DOM element for a given theme name\n * @return {DOMElement} stylesheet element\n */\n getStylesheet(name='default'){\n return Dom.id(this.prfxTf + name);\n }\n\n /**\n * Destroy filter grid\n */\n destroy(){\n if(!this._hasGrid){\n return;\n }\n let rows = this.tbl.rows,\n Mod = this.Mod,\n emitter = this.emitter;\n\n if(this.isExternalFlt && !this.popupFilters){\n this.removeExternalFlts();\n }\n if(this.infDiv){\n this.removeToolbar();\n }\n if(this.markActiveColumns){\n this.clearActiveColumns();\n emitter.off(['before-filtering'], ()=> this.clearActiveColumns());\n emitter.off(['cell-processed'],\n (tf, colIndex)=> this.markActiveColumn(colIndex));\n }\n if(this.hasExtensions){\n this.destroyExtensions();\n }\n\n this.validateAllRows();\n\n if(this.fltGrid && !this.gridLayout){\n this.fltGridEl = rows[this.filtersRowIndex];\n this.tbl.deleteRow(this.filtersRowIndex);\n }\n\n // broadcast destroy event\n emitter.emit('destroy', this);\n\n // Destroy modules\n // TODO: subcribe modules to destroy event instead\n Object.keys(Mod).forEach(function(key){\n var feature = Mod[key];\n if(feature && Types.isFn(feature.destroy)){\n feature.destroy();\n }\n });\n\n // unsubscribe to events\n if(this.hasVisibleRows){\n emitter.off(['after-filtering'], ()=> this.enforceVisibility());\n }\n if(this.linkedFilters){\n emitter.off(['after-filtering'], ()=> this.linkFilters());\n }\n\n Dom.removeClass(this.tbl, this.prfxTf);\n this.nbHiddenRows = 0;\n this.validRowsIndex = [];\n this.fltIds = [];\n this.activeFlt = null;\n this._hasGrid = false;\n this.initialized = false;\n }\n\n /**\n * Generate container element for paging, reset button, rows counter etc.\n */\n setToolbar(){\n if(this.infDiv){\n return;\n }\n\n /*** container div ***/\n let infdiv = Dom.create('div', ['id', this.prfxInfDiv+this.id]);\n infdiv.className = this.infDivCssClass;\n\n //custom container\n if(this.toolBarTgtId){\n Dom.id(this.toolBarTgtId).appendChild(infdiv);\n }\n //grid-layout\n else if(this.gridLayout){\n let gridLayout = this.Mod.gridLayout;\n gridLayout.tblMainCont.appendChild(infdiv);\n infdiv.className = gridLayout.gridInfDivCssClass;\n }\n //default location: just above the table\n else{\n var cont = Dom.create('caption');\n cont.appendChild(infdiv);\n this.tbl.insertBefore(cont, this.tbl.firstChild);\n }\n this.infDiv = Dom.id(this.prfxInfDiv+this.id);\n\n /*** left div containing rows # displayer ***/\n let ldiv = Dom.create('div', ['id', this.prfxLDiv+this.id]);\n ldiv.className = this.lDivCssClass;\n infdiv.appendChild(ldiv);\n this.lDiv = Dom.id(this.prfxLDiv+this.id);\n\n /*** right div containing reset button\n + nb results per page select ***/\n let rdiv = Dom.create('div', ['id', this.prfxRDiv+this.id]);\n rdiv.className = this.rDivCssClass;\n infdiv.appendChild(rdiv);\n this.rDiv = Dom.id(this.prfxRDiv+this.id);\n\n /*** mid div containing paging elements ***/\n let mdiv = Dom.create('div', ['id', this.prfxMDiv+this.id]);\n mdiv.className = this.mDivCssClass;\n infdiv.appendChild(mdiv);\n this.mDiv = Dom.id(this.prfxMDiv+this.id);\n\n // emit help initialisation only if undefined\n if(Types.isUndef(this.help)){\n this.emitter.emit('init-help', this);\n }\n }\n\n /**\n * Remove toolbar container element\n */\n removeToolbar(){\n if(!this.infDiv){\n return;\n }\n Dom.remove(this.infDiv);\n this.infDiv = null;\n\n let tbl = this.tbl;\n let captions = Dom.tag(tbl, 'caption');\n if(captions.length > 0){\n [].forEach.call(captions, (elm)=> tbl.removeChild(elm));\n }\n }\n\n /**\n * Remove all the external column filters\n */\n removeExternalFlts(){\n if(!this.isExternalFlt){\n return;\n }\n let ids = this.externalFltTgtIds,\n len = ids.length;\n for(let ct=0; ct {\n if(val !== ' '){\n this.setFilterValue(idx, val);\n }\n });\n this.filter();\n }\n\n /**\n * Filter the table by retrieving the data from each cell in every single\n * row and comparing it to the search term for current column. A row is\n * hidden when all the search terms are not found in inspected row.\n */\n filter(){\n if(!this.fltGrid || !this._hasGrid){\n return;\n }\n //invoke onbefore callback\n if(this.onBeforeFilter){\n this.onBeforeFilter.call(null, this);\n }\n this.emitter.emit('before-filtering', this);\n\n let row = this.tbl.rows,\n hiddenrows = 0;\n\n this.validRowsIndex = [];\n // search args re-init\n let searchArgs = this.getFiltersValue();\n\n var numCellData, nbFormat;\n var re_le = new RegExp(this.leOperator),\n re_ge = new RegExp(this.geOperator),\n re_l = new RegExp(this.lwOperator),\n re_g = new RegExp(this.grOperator),\n re_d = new RegExp(this.dfOperator),\n re_lk = new RegExp(Str.rgxEsc(this.lkOperator)),\n re_eq = new RegExp(this.eqOperator),\n re_st = new RegExp(this.stOperator),\n re_en = new RegExp(this.enOperator),\n // re_an = new RegExp(this.anOperator),\n // re_cr = new RegExp(this.curExp),\n re_em = this.emOperator,\n re_nm = this.nmOperator,\n re_re = new RegExp(Str.rgxEsc(this.rgxOperator));\n\n //keyword highlighting\n function highlight(str, ok, cell){\n /*jshint validthis:true */\n if(this.highlightKeywords && ok){\n str = str.replace(re_lk, '');\n str = str.replace(re_eq, '');\n str = str.replace(re_st, '');\n str = str.replace(re_en, '');\n let w = str;\n if(re_le.test(str) || re_ge.test(str) || re_l.test(str) ||\n re_g.test(str) || re_d.test(str)){\n w = Dom.getText(cell);\n }\n if(w !== ''){\n this.emitter.emit('highlight-keyword', this, cell, w);\n }\n }\n }\n\n //looks for search argument in current row\n function hasArg(sA, cellData, j){\n /*jshint validthis:true */\n sA = Str.matchCase(sA, this.caseSensitive);\n\n let occurence,\n removeNbFormat = Helpers.removeNbFormat;\n\n //Search arg operator tests\n let hasLO = re_l.test(sA),\n hasLE = re_le.test(sA),\n hasGR = re_g.test(sA),\n hasGE = re_ge.test(sA),\n hasDF = re_d.test(sA),\n hasEQ = re_eq.test(sA),\n hasLK = re_lk.test(sA),\n // hasAN = re_an.test(sA),\n hasST = re_st.test(sA),\n hasEN = re_en.test(sA),\n hasEM = (re_em === sA),\n hasNM = (re_nm === sA),\n hasRE = re_re.test(sA);\n\n //Search arg dates tests\n let isLDate = hasLO &&\n DateHelper.isValid(sA.replace(re_l,''), dtType);\n let isLEDate = hasLE &&\n DateHelper.isValid(sA.replace(re_le,''), dtType);\n let isGDate = hasGR &&\n DateHelper.isValid(sA.replace(re_g,''), dtType);\n let isGEDate = hasGE &&\n DateHelper.isValid(sA.replace(re_ge,''), dtType);\n let isDFDate = hasDF &&\n DateHelper.isValid(sA.replace(re_d,''), dtType);\n let isEQDate = hasEQ &&\n DateHelper.isValid(sA.replace(re_eq,''), dtType);\n\n let dte1, dte2;\n //dates\n if(DateHelper.isValid(cellData, dtType)){\n dte1 = DateHelper.format(cellData, dtType);\n // lower date\n if(isLDate){\n dte2 = DateHelper.format(sA.replace(re_l,''), dtType);\n occurence = dte1 < dte2;\n }\n // lower equal date\n else if(isLEDate){\n dte2 = DateHelper.format(sA.replace(re_le,''), dtType);\n occurence = dte1 <= dte2;\n }\n // greater equal date\n else if(isGEDate){\n dte2 = DateHelper.format(sA.replace(re_ge,''), dtType);\n occurence = dte1 >= dte2;\n }\n // greater date\n else if(isGDate){\n dte2 = DateHelper.format(sA.replace(re_g,''), dtType);\n occurence = dte1 > dte2;\n }\n // different date\n else if(isDFDate){\n dte2 = DateHelper.format(sA.replace(re_d,''), dtType);\n occurence = dte1.toString() != dte2.toString();\n }\n // equal date\n else if(isEQDate){\n dte2 = DateHelper.format(sA.replace(re_eq,''), dtType);\n occurence = dte1.toString() == dte2.toString();\n }\n // searched keyword with * operator doesn't have to be a date\n else if(re_lk.test(sA)){// like date\n occurence = Str.contains(sA.replace(re_lk,''), cellData,\n false, this.caseSensitive);\n }\n else if(DateHelper.isValid(sA,dtType)){\n dte2 = DateHelper.format(sA,dtType);\n occurence = dte1.toString() === dte2.toString();\n }\n //empty\n else if(hasEM){\n occurence = Str.isEmpty(cellData);\n }\n //non-empty\n else if(hasNM){\n occurence = !Str.isEmpty(cellData);\n } else {\n occurence = Str.contains(sA, cellData, this.isExactMatch(j),\n this.caseSensitive);\n }\n }\n\n else{\n //first numbers need to be formated\n if(this.hasColNbFormat && this.colNbFormat[j]){\n numCellData = removeNbFormat(\n cellData, this.colNbFormat[j]);\n nbFormat = this.colNbFormat[j];\n } else {\n if(this.thousandsSeparator === ',' &&\n this.decimalSeparator === '.'){\n numCellData = removeNbFormat(cellData, 'us');\n nbFormat = 'us';\n } else {\n numCellData = removeNbFormat(cellData, 'eu');\n nbFormat = 'eu';\n }\n }\n\n // first checks if there is any operator (<,>,<=,>=,!,*,=,{,},\n // rgx:)\n // lower equal\n if(hasLE){\n occurence = numCellData <= removeNbFormat(\n sA.replace(re_le, ''), nbFormat);\n }\n //greater equal\n else if(hasGE){\n occurence = numCellData >= removeNbFormat(\n sA.replace(re_ge, ''), nbFormat);\n }\n //lower\n else if(hasLO){\n occurence = numCellData < removeNbFormat(\n sA.replace(re_l, ''), nbFormat);\n }\n //greater\n else if(hasGR){\n occurence = numCellData > removeNbFormat(\n sA.replace(re_g, ''), nbFormat);\n }\n //different\n else if(hasDF){\n occurence = Str.contains(sA.replace(re_d, ''), cellData,\n false, this.caseSensitive) ? false : true;\n }\n //like\n else if(hasLK){\n occurence = Str.contains(sA.replace(re_lk, ''), cellData,\n false, this.caseSensitive);\n }\n //equal\n else if(hasEQ){\n occurence = Str.contains(sA.replace(re_eq, ''), cellData,\n true, this.caseSensitive);\n }\n //starts with\n else if(hasST){\n occurence = cellData.indexOf(sA.replace(re_st, '')) === 0 ?\n true : false;\n }\n //ends with\n else if(hasEN){\n let searchArg = sA.replace(re_en, '');\n occurence =\n cellData.lastIndexOf(searchArg, cellData.length-1) ===\n (cellData.length-1)-(searchArg.length-1) &&\n cellData.lastIndexOf(\n searchArg, cellData.length-1) > -1 ? true : false;\n }\n //empty\n else if(hasEM){\n occurence = Str.isEmpty(cellData);\n }\n //non-empty\n else if(hasNM){\n occurence = !Str.isEmpty(cellData);\n }\n //regexp\n else if(hasRE){\n //in case regexp fires an exception\n try{\n //operator is removed\n let srchArg = sA.replace(re_re,'');\n let rgx = new RegExp(srchArg);\n occurence = rgx.test(cellData);\n } catch(e) { occurence = false; }\n } else {\n occurence = Str.contains(sA, cellData, this.isExactMatch(j),\n this.caseSensitive);\n }\n\n }//else\n return occurence;\n }//fn\n\n for(let k=this.refRow; k 1,\n //multiple search parameter operator &&\n sAAndSplit = sA.toString().split(this.anOperator),\n //multiple search && parameter boolean\n hasMultiAndSA = sAAndSplit.length > 1;\n\n //detect operators or array query\n if(Types.isArray(sA) || hasMultiOrSA || hasMultiAndSA){\n let cS,\n s,\n occur = false;\n if(Types.isArray(sA)){\n s = sA;\n } else {\n s = hasMultiOrSA ? sAOrSplit : sAAndSplit;\n }\n // TODO: improve clarity/readability of this block\n for(let w=0, len=s.length; w 0){\n isExludedRow = exclude.indexOf(i) != -1;\n }\n let cell = row[i].cells,\n nchilds = cell.length;\n\n // checks if row has exact cell # and is not excluded\n if(nchilds === this.nbCells && !isExludedRow){\n // this loop retrieves cell data\n for(let j=0; j 0 ? fltValues : '';\n }\n //checklist\n else if(fltColType === this.fltTypeCheckList){\n // TODO: extract a method in checklist module from below\n if(flt.getAttribute('value') !== null){\n fltValues = flt.getAttribute('value');\n //removes last operator ||\n fltValues = fltValues.substr(0, fltValues.length-3);\n //convert || separated values into array\n fltValues = fltValues.split(' ' + this.orOperator + ' ');\n }\n //return empty string if collection is empty\n fltValue = fltValues.length > 0 ? fltValues : '';\n }\n //return an empty string if collection contains a single empty string\n if(Types.isArray(fltValue) && fltValue.length === 1 &&\n fltValue[0] === ''){\n fltValue = '';\n }\n return fltValue;\n }\n\n /**\n * Return the filters' values\n * @return {Array} List of filters' values\n */\n getFiltersValue(){\n if(!this.fltGrid){\n return;\n }\n let searchArgs = [];\n for(let i=0, len=this.fltIds.length; i 0;\n let frag = !tblHasColTag ? doc.createDocumentFragment() : null;\n for(let k=0; k nrows\n if(row <= this.nbRows){\n this.validateRow(row, true);\n }\n }\n }\n\n /**\n * Clear all the filters' values\n */\n clearFilters(){\n if(!this.fltGrid){\n return;\n }\n\n this.emitter.emit('before-clearing-filters', this);\n\n if(this.onBeforeReset){\n this.onBeforeReset.call(null, this, this.getFiltersValue());\n }\n for(let i=0, len=this.fltIds.length; i IE onload event works only for scripts, not for stylesheets\n file.onload = file.onreadystatechange = function(){\n if(!isLoaded &&\n (!this.readyState || this.readyState === 'loaded' ||\n this.readyState === 'complete')){\n isLoaded = true;\n if(typeof callback === 'function'){\n callback.call(null, o);\n }\n }\n };\n file.onerror = function(){\n throw new Error('TF script could not load: ' + filePath);\n };\n head.appendChild(file);\n }\n\n /**\n * Check if table has filters grid\n * @return {Boolean}\n */\n hasGrid(){\n return this._hasGrid;\n }\n\n /**\n * Get list of filter IDs\n * @return {[type]} [description]\n */\n getFiltersId(){\n return this.fltIds || [];\n }\n\n /**\n * Get filtered (valid) rows indexes\n * @param {Boolean} reCalc Force calculation of filtered rows list\n * @return {Array} List of row indexes\n */\n getValidRows(reCalc){\n if(!reCalc){\n return this.validRowsIndex;\n }\n\n this.validRowsIndex = [];\n for(let k=this.refRow; k
- src/array.js | tablefilter v0.1.10 API Document
+ src/array.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/cookie.js.html b/docs/file/src/cookie.js.html
index 125f7600..28b42ecd 100644
--- a/docs/file/src/cookie.js.html
+++ b/docs/file/src/cookie.js.html
@@ -3,7 +3,7 @@
- src/cookie.js | tablefilter v0.1.10 API Document
+ src/cookie.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/date.js.html b/docs/file/src/date.js.html
index 86446164..3215ffc2 100644
--- a/docs/file/src/date.js.html
+++ b/docs/file/src/date.js.html
@@ -3,7 +3,7 @@
- src/date.js | tablefilter v0.1.10 API Document
+ src/date.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/dom.js.html b/docs/file/src/dom.js.html
index c4d4febd..48597bfe 100644
--- a/docs/file/src/dom.js.html
+++ b/docs/file/src/dom.js.html
@@ -3,7 +3,7 @@
- src/dom.js | tablefilter v0.1.10 API Document
+ src/dom.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/emitter.js.html b/docs/file/src/emitter.js.html
index cfa0c54a..a4a7af1a 100644
--- a/docs/file/src/emitter.js.html
+++ b/docs/file/src/emitter.js.html
@@ -3,7 +3,7 @@
- src/emitter.js | tablefilter v0.1.10 API Document
+ src/emitter.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/event.js.html b/docs/file/src/event.js.html
index 03ee9a40..93c56e00 100644
--- a/docs/file/src/event.js.html
+++ b/docs/file/src/event.js.html
@@ -3,7 +3,7 @@
- src/event.js | tablefilter v0.1.10 API Document
+ src/event.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/extensions/advancedGrid/adapterEzEditTable.js.html b/docs/file/src/extensions/advancedGrid/adapterEzEditTable.js.html
index 491ba80d..fab4eb24 100644
--- a/docs/file/src/extensions/advancedGrid/adapterEzEditTable.js.html
+++ b/docs/file/src/extensions/advancedGrid/adapterEzEditTable.js.html
@@ -3,7 +3,7 @@
- src/extensions/advancedGrid/adapterEzEditTable.js | tablefilter v0.1.10 API Document
+ src/extensions/advancedGrid/adapterEzEditTable.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/extensions/advancedGrid/advancedGrid.js.html b/docs/file/src/extensions/advancedGrid/advancedGrid.js.html
index 637bfcfd..b654f085 100644
--- a/docs/file/src/extensions/advancedGrid/advancedGrid.js.html
+++ b/docs/file/src/extensions/advancedGrid/advancedGrid.js.html
@@ -3,7 +3,7 @@
- src/extensions/advancedGrid/advancedGrid.js | tablefilter v0.1.10 API Document
+ src/extensions/advancedGrid/advancedGrid.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/extensions/colOps/colOps.js.html b/docs/file/src/extensions/colOps/colOps.js.html
index 142a4b2d..27f80e0e 100644
--- a/docs/file/src/extensions/colOps/colOps.js.html
+++ b/docs/file/src/extensions/colOps/colOps.js.html
@@ -3,7 +3,7 @@
- src/extensions/colOps/colOps.js | tablefilter v0.1.10 API Document
+ src/extensions/colOps/colOps.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/extensions/colsVisibility/colsVisibility.js.html b/docs/file/src/extensions/colsVisibility/colsVisibility.js.html
index a639fcf3..71778cce 100644
--- a/docs/file/src/extensions/colsVisibility/colsVisibility.js.html
+++ b/docs/file/src/extensions/colsVisibility/colsVisibility.js.html
@@ -3,7 +3,7 @@
- src/extensions/colsVisibility/colsVisibility.js | tablefilter v0.1.10 API Document
+ src/extensions/colsVisibility/colsVisibility.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/extensions/filtersVisibility/filtersVisibility.js.html b/docs/file/src/extensions/filtersVisibility/filtersVisibility.js.html
index 66d26086..fb49ea42 100644
--- a/docs/file/src/extensions/filtersVisibility/filtersVisibility.js.html
+++ b/docs/file/src/extensions/filtersVisibility/filtersVisibility.js.html
@@ -3,7 +3,7 @@
- src/extensions/filtersVisibility/filtersVisibility.js | tablefilter v0.1.10 API Document
+ src/extensions/filtersVisibility/filtersVisibility.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/extensions/sort/adapterSortabletable.js.html b/docs/file/src/extensions/sort/adapterSortabletable.js.html
index a0736330..caf2166e 100644
--- a/docs/file/src/extensions/sort/adapterSortabletable.js.html
+++ b/docs/file/src/extensions/sort/adapterSortabletable.js.html
@@ -3,7 +3,7 @@
- src/extensions/sort/adapterSortabletable.js | tablefilter v0.1.10 API Document
+ src/extensions/sort/adapterSortabletable.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/extensions/sort/sort.js.html b/docs/file/src/extensions/sort/sort.js.html
index fc745f43..02d2ef35 100644
--- a/docs/file/src/extensions/sort/sort.js.html
+++ b/docs/file/src/extensions/sort/sort.js.html
@@ -3,7 +3,7 @@
- src/extensions/sort/sort.js | tablefilter v0.1.10 API Document
+ src/extensions/sort/sort.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/helpers.js.html b/docs/file/src/helpers.js.html
index b7d4a73b..fcaf9b5c 100644
--- a/docs/file/src/helpers.js.html
+++ b/docs/file/src/helpers.js.html
@@ -3,7 +3,7 @@
- src/helpers.js | tablefilter v0.1.10 API Document
+ src/helpers.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/alternateRows.js.html b/docs/file/src/modules/alternateRows.js.html
index 3fba9829..22a7f49c 100644
--- a/docs/file/src/modules/alternateRows.js.html
+++ b/docs/file/src/modules/alternateRows.js.html
@@ -3,7 +3,7 @@
- src/modules/alternateRows.js | tablefilter v0.1.10 API Document
+ src/modules/alternateRows.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/checkList.js.html b/docs/file/src/modules/checkList.js.html
index 8a5506d3..7c35baa2 100644
--- a/docs/file/src/modules/checkList.js.html
+++ b/docs/file/src/modules/checkList.js.html
@@ -3,7 +3,7 @@
- src/modules/checkList.js | tablefilter v0.1.10 API Document
+ src/modules/checkList.js | tablefilter v0.1.11 API Document
@@ -75,6 +75,9 @@ import Str from '../string';
import Sort from '../sort';
import Event from '../event';
+const SORT_ERROR = 'Filter options for column {0} cannot be sorted in ' +
+ '{1} manner.';
+
export class CheckList extends Feature{
/**
@@ -296,42 +299,33 @@ export class CheckList extends Feature{
}
}
//asc sort
- if(tf.sortNumAsc && tf.sortNumAsc.indexOf(colIndex) != -1){
+ if(tf.sortNumAsc.indexOf(colIndex) != -1){
try{
- this.opts.sort(numSortAsc);
+ this.opts.sort(Sort.numSortAsc);
if(this.excludedOpts){
- this.excludedOpts.sort(numSortAsc);
+ this.excludedOpts.sort(Sort.numSortAsc);
}
if(this.isCustom){
- this.optsTxt.sort(numSortAsc);
+ this.optsTxt.sort(Sort.numSortAsc);
}
} catch(e) {
- this.opts.sort();
- if(this.excludedOpts){
- this.excludedOpts.sort();
- }
- if(this.isCustom){
- this.optsTxt.sort();
- }
+ throw new Error(SORT_ERROR.replace('{0}', colIndex)
+ .replace('{1}', 'ascending'));
}//in case there are alphanumeric values
}
//desc sort
- if(tf.sortNumDesc && tf.sortNumDesc.indexOf(colIndex) != -1){
+ if(tf.sortNumDesc.indexOf(colIndex) != -1){
try{
- this.opts.sort(numSortDesc);
+ this.opts.sort(Sort.numSortDesc);
if(this.excludedOpts){
- this.excludedOpts.sort(numSortDesc);
+ this.excludedOpts.sort(Sort.numSortDesc);
}
if(this.isCustom){
- this.optsTxt.sort(numSortDesc);
+ this.optsTxt.sort(Sort.numSortDesc);
}
} catch(e) {
- this.opts.sort();
- if(this.excludedOpts){
- this.excludedOpts.sort(); }
- if(this.isCustom){
- this.optsTxt.sort();
- }
+ throw new Error(SORT_ERROR.replace('{0}', colIndex)
+ .replace('{1}', 'descending'));
}//in case there are alphanumeric values
}
diff --git a/docs/file/src/modules/clearButton.js.html b/docs/file/src/modules/clearButton.js.html
index 1031e3a4..f9133909 100644
--- a/docs/file/src/modules/clearButton.js.html
+++ b/docs/file/src/modules/clearButton.js.html
@@ -3,7 +3,7 @@
- src/modules/clearButton.js | tablefilter v0.1.10 API Document
+ src/modules/clearButton.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/dropdown.js.html b/docs/file/src/modules/dropdown.js.html
index 8620346d..ca494074 100644
--- a/docs/file/src/modules/dropdown.js.html
+++ b/docs/file/src/modules/dropdown.js.html
@@ -3,7 +3,7 @@
- src/modules/dropdown.js | tablefilter v0.1.10 API Document
+ src/modules/dropdown.js | tablefilter v0.1.11 API Document
@@ -75,6 +75,9 @@ import Str from '../string';
import Sort from '../sort';
import Event from '../event';
+const SORT_ERROR = 'Filter options for column {0} cannot be sorted in ' +
+ '{1} manner.';
+
export class Dropdown extends Feature{
/**
@@ -299,43 +302,33 @@ export class Dropdown extends Feature{
}
//asc sort
- if(tf.sortNumAsc && tf.sortNumAsc.indexOf(colIndex) != -1){
+ if(tf.sortNumAsc.indexOf(colIndex) != -1){
try{
- this.opts.sort( numSortAsc );
+ this.opts.sort(Sort.numSortAsc);
if(excludedOpts){
- excludedOpts.sort(numSortAsc);
+ excludedOpts.sort(Sort.numSortAsc);
}
if(this.isCustom){
- this.optsTxt.sort(numSortAsc);
+ this.optsTxt.sort(Sort.numSortAsc);
}
} catch(e) {
- this.opts.sort();
- if(excludedOpts){
- excludedOpts.sort();
- }
- if(this.isCustom){
- this.optsTxt.sort();
- }
+ throw new Error(SORT_ERROR.replace('{0}', colIndex)
+ .replace('{1}', 'ascending'));
}//in case there are alphanumeric values
}
//desc sort
- if(tf.sortNumDesc && tf.sortNumDesc.indexOf(colIndex) != -1){
+ if(tf.sortNumDesc.indexOf(colIndex) != -1){
try{
- this.opts.sort(numSortDesc);
+ this.opts.sort(Sort.numSortDesc);
if(excludedOpts){
- excludedOpts.sort(numSortDesc);
+ excludedOpts.sort(Sort.numSortDesc);
}
if(this.isCustom){
- this.optsTxt.sort(numSortDesc);
+ this.optsTxt.sort(Sort.numSortDesc);
}
} catch(e) {
- this.opts.sort();
- if(excludedOpts){
- excludedOpts.sort();
- }
- if(this.isCustom){
- this.optsTxt.sort();
- }
+ throw new Error(SORT_ERROR.replace('{0}', colIndex)
+ .replace('{1}', 'ascending'));
}//in case there are alphanumeric values
}
diff --git a/docs/file/src/modules/feature.js.html b/docs/file/src/modules/feature.js.html
index 735eb154..b115c749 100644
--- a/docs/file/src/modules/feature.js.html
+++ b/docs/file/src/modules/feature.js.html
@@ -3,7 +3,7 @@
- src/modules/feature.js | tablefilter v0.1.10 API Document
+ src/modules/feature.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/gridLayout.js.html b/docs/file/src/modules/gridLayout.js.html
index f95c6594..ce2aa555 100644
--- a/docs/file/src/modules/gridLayout.js.html
+++ b/docs/file/src/modules/gridLayout.js.html
@@ -3,7 +3,7 @@
- src/modules/gridLayout.js | tablefilter v0.1.10 API Document
+ src/modules/gridLayout.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/help.js.html b/docs/file/src/modules/help.js.html
index b70784b9..9c893649 100644
--- a/docs/file/src/modules/help.js.html
+++ b/docs/file/src/modules/help.js.html
@@ -3,7 +3,7 @@
- src/modules/help.js | tablefilter v0.1.10 API Document
+ src/modules/help.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/highlightKeywords.js.html b/docs/file/src/modules/highlightKeywords.js.html
index bb0ce324..f54166fb 100644
--- a/docs/file/src/modules/highlightKeywords.js.html
+++ b/docs/file/src/modules/highlightKeywords.js.html
@@ -3,7 +3,7 @@
- src/modules/highlightKeywords.js | tablefilter v0.1.10 API Document
+ src/modules/highlightKeywords.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/loader.js.html b/docs/file/src/modules/loader.js.html
index 21041d03..064364b5 100644
--- a/docs/file/src/modules/loader.js.html
+++ b/docs/file/src/modules/loader.js.html
@@ -3,7 +3,7 @@
- src/modules/loader.js | tablefilter v0.1.10 API Document
+ src/modules/loader.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/noResults.js.html b/docs/file/src/modules/noResults.js.html
index 10710fe4..9dee98d7 100644
--- a/docs/file/src/modules/noResults.js.html
+++ b/docs/file/src/modules/noResults.js.html
@@ -3,7 +3,7 @@
- src/modules/noResults.js | tablefilter v0.1.10 API Document
+ src/modules/noResults.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/paging.js.html b/docs/file/src/modules/paging.js.html
index f9b35d8b..2a283c94 100644
--- a/docs/file/src/modules/paging.js.html
+++ b/docs/file/src/modules/paging.js.html
@@ -3,7 +3,7 @@
- src/modules/paging.js | tablefilter v0.1.10 API Document
+ src/modules/paging.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/popupFilter.js.html b/docs/file/src/modules/popupFilter.js.html
index 7ecd9cd0..009fb556 100644
--- a/docs/file/src/modules/popupFilter.js.html
+++ b/docs/file/src/modules/popupFilter.js.html
@@ -3,7 +3,7 @@
- src/modules/popupFilter.js | tablefilter v0.1.10 API Document
+ src/modules/popupFilter.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/rowsCounter.js.html b/docs/file/src/modules/rowsCounter.js.html
index 238a11d9..8f1549c9 100644
--- a/docs/file/src/modules/rowsCounter.js.html
+++ b/docs/file/src/modules/rowsCounter.js.html
@@ -3,7 +3,7 @@
- src/modules/rowsCounter.js | tablefilter v0.1.10 API Document
+ src/modules/rowsCounter.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/statusBar.js.html b/docs/file/src/modules/statusBar.js.html
index 1b887374..76143f11 100644
--- a/docs/file/src/modules/statusBar.js.html
+++ b/docs/file/src/modules/statusBar.js.html
@@ -3,7 +3,7 @@
- src/modules/statusBar.js | tablefilter v0.1.10 API Document
+ src/modules/statusBar.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/modules/store.js.html b/docs/file/src/modules/store.js.html
index 039284b5..d1f20f32 100644
--- a/docs/file/src/modules/store.js.html
+++ b/docs/file/src/modules/store.js.html
@@ -3,7 +3,7 @@
- src/modules/store.js | tablefilter v0.1.10 API Document
+ src/modules/store.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/sort.js.html b/docs/file/src/sort.js.html
index 7bf3cb36..7ae9434f 100644
--- a/docs/file/src/sort.js.html
+++ b/docs/file/src/sort.js.html
@@ -3,7 +3,7 @@
- src/sort.js | tablefilter v0.1.10 API Document
+ src/sort.js | tablefilter v0.1.11 API Document
@@ -75,6 +75,12 @@ export default {
let x = Str.lower(a);
let y = Str.lower(b);
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ },
+ numSortAsc(a, b){
+ return (a - b);
+ },
+ numSortDesc(a, b){
+ return (b - a);
}
};
diff --git a/docs/file/src/string.js.html b/docs/file/src/string.js.html
index cc24acef..ddd4fc62 100644
--- a/docs/file/src/string.js.html
+++ b/docs/file/src/string.js.html
@@ -3,7 +3,7 @@
- src/string.js | tablefilter v0.1.10 API Document
+ src/string.js | tablefilter v0.1.11 API Document
diff --git a/docs/file/src/tablefilter.js.html b/docs/file/src/tablefilter.js.html
index 0e069da7..38cdb66b 100644
--- a/docs/file/src/tablefilter.js.html
+++ b/docs/file/src/tablefilter.js.html
@@ -3,7 +3,7 @@
- src/tablefilter.js | tablefilter v0.1.10 API Document
+ src/tablefilter.js | tablefilter v0.1.11 API Document
@@ -322,10 +322,10 @@ export class TableFilter {
this.sortSlc = f.sort_select===false ? false : true;
//enables/disables ascending numeric options sorting
this.isSortNumAsc = Boolean(f.sort_num_asc);
- this.sortNumAsc = this.isSortNumAsc ? f.sort_num_asc : null;
+ this.sortNumAsc = this.isSortNumAsc ? f.sort_num_asc : [];
//enables/disables descending numeric options sorting
this.isSortNumDesc = Boolean(f.sort_num_desc);
- this.sortNumDesc = this.isSortNumDesc ? f.sort_num_desc : null;
+ this.sortNumDesc = this.isSortNumDesc ? f.sort_num_desc : [];
//Select filters are populated on demand
this.loadFltOnDemand = Boolean(f.load_filters_on_demand);
this.hasCustomOptions = Types.isObj(f.custom_options);
diff --git a/docs/file/src/types.js.html b/docs/file/src/types.js.html
index 51389468..b65a71c7 100644
--- a/docs/file/src/types.js.html
+++ b/docs/file/src/types.js.html
@@ -3,7 +3,7 @@
- src/types.js | tablefilter v0.1.10 API Document
+ src/types.js | tablefilter v0.1.11 API Document
diff --git a/docs/identifiers.html b/docs/identifiers.html
index 4a3f721f..89abd1f7 100644
--- a/docs/identifiers.html
+++ b/docs/identifiers.html
@@ -3,7 +3,7 @@
- Index | tablefilter v0.1.10 API Document
+ Index | tablefilter v0.1.11 API Document
diff --git a/docs/index.html b/docs/index.html
index 3d9b10fa..16163e03 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -3,7 +3,7 @@
- tablefilter v0.1.10 API Document
+ tablefilter v0.1.11 API Document
diff --git a/docs/source.html b/docs/source.html
index 7beaf1e8..2c177fa7 100644
--- a/docs/source.html
+++ b/docs/source.html
@@ -3,7 +3,7 @@
- Source | tablefilter v0.1.10 API Document
+ Source | tablefilter v0.1.11 API Document
@@ -90,7 +90,7 @@
- |
379 byte |
17 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/cookie.js |
@@ -98,7 +98,7 @@
- |
1455 byte |
58 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/date.js |
@@ -106,7 +106,7 @@
- |
5711 byte |
172 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/dom.js |
@@ -114,7 +114,7 @@
- |
4442 byte |
165 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/emitter.js |
@@ -122,7 +122,7 @@
83 %5/6 |
1263 byte |
50 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/event.js |
@@ -130,7 +130,7 @@
- |
1299 byte |
53 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/extensions/advancedGrid/adapterEzEditTable.js |
@@ -138,7 +138,7 @@
29 %5/17 |
16634 byte |
415 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/extensions/advancedGrid/advancedGrid.js |
@@ -146,7 +146,7 @@
- |
90 byte |
2 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/extensions/colOps/colOps.js |
@@ -154,7 +154,7 @@
22 %2/9 |
12372 byte |
321 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/extensions/colsVisibility/colsVisibility.js |
@@ -162,7 +162,7 @@
17 %10/58 |
17262 byte |
520 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/extensions/filtersVisibility/filtersVisibility.js |
@@ -170,7 +170,7 @@
15 %5/33 |
5733 byte |
184 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/extensions/sort/adapterSortabletable.js |
@@ -178,7 +178,7 @@
10 %3/28 |
13392 byte |
413 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/extensions/sort/sort.js |
@@ -186,7 +186,7 @@
- |
198 byte |
8 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/helpers.js |
@@ -194,7 +194,7 @@
- |
433 byte |
23 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/alternateRows.js |
@@ -202,15 +202,15 @@
54 %6/11 |
3361 byte |
128 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/checkList.js |
CheckList |
26 %7/26 |
- 16743 byte |
- 480 |
- 2016-02-02 07:18:31 (UTC) |
+ 16625 byte |
+ 474 |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/clearButton.js |
@@ -218,15 +218,15 @@
25 %3/12 |
2613 byte |
94 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/dropdown.js |
Dropdown |
30 %6/20 |
- 13754 byte |
- 407 |
- 2016-02-02 07:18:31 (UTC) |
+ 13637 byte |
+ 400 |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/feature.js |
@@ -234,7 +234,7 @@
0 %0/14 |
649 byte |
38 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/gridLayout.js |
@@ -242,7 +242,7 @@
10 %3/28 |
11802 byte |
340 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/help.js |
@@ -250,7 +250,7 @@
15 %3/19 |
5370 byte |
155 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/highlightKeywords.js |
@@ -258,7 +258,7 @@
36 %4/11 |
4631 byte |
138 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/loader.js |
@@ -266,7 +266,7 @@
6 %1/15 |
4792 byte |
161 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/noResults.js |
@@ -274,7 +274,7 @@
5 %1/20 |
3673 byte |
135 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/paging.js |
@@ -282,7 +282,7 @@
25 %16/63 |
26310 byte |
770 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/popupFilter.js |
@@ -290,7 +290,7 @@
35 %10/28 |
9005 byte |
276 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/rowsCounter.js |
@@ -298,7 +298,7 @@
5 %1/18 |
4925 byte |
148 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/statusBar.js |
@@ -306,7 +306,7 @@
3 %1/29 |
7710 byte |
224 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/modules/store.js |
@@ -314,15 +314,15 @@
57 %8/14 |
3327 byte |
137 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/sort.js |
- |
- |
- 187 byte |
- 9 |
- 2016-02-02 07:18:31 (UTC) |
+ 294 byte |
+ 15 |
+ 2016-02-03 07:32:35 (UTC) |
| src/string.js |
@@ -330,15 +330,15 @@
- |
1495 byte |
61 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/tablefilter.js |
TableFilter |
33 %75/224 |
- 79618 byte |
+ 79614 byte |
2318 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |
| src/types.js |
@@ -346,7 +346,7 @@
- |
1432 byte |
71 |
- 2016-02-02 07:18:31 (UTC) |
+ 2016-02-03 07:32:35 (UTC) |