├── .babelrc
├── .editorconfig
├── .gitignore
├── LICENSE
├── README.adoc
├── dist
├── example.html
├── excel-bootstrap-table-filter-bundle.js
├── excel-bootstrap-table-filter-bundle.js.map
├── excel-bootstrap-table-filter-bundle.min.js
├── excel-bootstrap-table-filter-bundle.min.js.map
└── excel-bootstrap-table-filter-style.css
├── excel-table-filter-example.PNG
├── karma.conf.js
├── package.json
├── rollup.config.js
├── src
├── FilterCollection.ts
├── FilterMenu.ts
├── MenuItem.interface.ts
├── Options.interface.ts
├── example.html
├── excel-bootstrap-table-filter-style.css
└── excel-bootstrap-table-filter.ts
└── tsconfig.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "es2015",
5 | {
6 | "modules": false
7 | }
8 | ]
9 | ],
10 | "plugins": [
11 | "external-helpers"
12 | ]
13 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*.{ts,js,html}]
4 | indent_style = space
5 | indent_size = 2
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [*.json]
11 | indent_style = space
12 | indent_size = 2
13 | charset = utf-8
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 | coverage/
3 | node_modules/
4 | !dist/excel-bootstrap-table-filter-style.css
5 | !dist/excel-bootstrap-table-filter-bundle.js
6 | !dist/excel-bootstrap-table-filter-bundle.js.map
7 | !dist/excel-bootstrap-table-filter-bundle.min.js
8 | !dist/excel-bootstrap-table-filter-bundle.min.js.map
9 | !dist/example.html
10 | dist/**
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Chester Carmer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | = Excel Bootstrap Table Filter jQuery Plugin
2 |
3 | A jQuery plugin to generate an excel-flavored table-filter.
4 |
5 | [[img-calendar]]
6 | .Excel Table Filter Example
7 | image::excel-table-filter-example.PNG[Calendar, 900, 450, link="https://github.com/chestercharles/excel-bootstrap-table-filter/blob/master/excel-bootstarp-table-filter-example.PNG"]
8 |
9 | == Usage
10 |
11 | . Install the dependencies by running: `npm install`.
12 | . Build the project by running: `npm run build`.
13 | . Add `dist/checkbox-dropdown-plugin.min.js` and `dist/checkbox-dropdown-style.css` to you project
14 | . Render the dropdown to a `#table` and pass an (optional) configuration object:
15 |
16 | $('#table').excelTableFilter({
17 | columnSelector: '.apply-filter', // (optional) if present, will only select
with specified class
18 | sort: true, // (optional) default true
19 | search: true // (optional) default true
20 | captions: Object // (optional) default { a_to_z: 'A to Z', z_to_a: 'Z to A', search: 'Search', select_all: 'Select All' }
21 | });
22 | . Add 'no-sort', 'no-filter' or 'no-search' to
element to customize its dropdown.
23 |
24 | == Support
25 |
26 | This plugin uses some methods like `Array.prototype.map`, `Array.prototype.reduce`, `Array.prototype.indexOf` that may need a polyfill in IE.
27 |
28 |
29 |
--------------------------------------------------------------------------------
/dist/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Excel Bootstrap Table Filter
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
Excel-style Bootstrap Table filter jQuery plugin
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
Table 1
30 |
31 |
32 |
33 |
Animal
34 |
Class
35 |
Collective Noun
36 |
A Number
37 |
38 |
39 |
40 |
41 |
Bear
42 |
Mammal
43 |
Sleuth
44 |
1
45 |
46 |
47 |
Ant
48 |
Insect
49 |
Army
50 |
2
51 |
52 |
53 |
Salamander
54 |
Amphibian
55 |
Congress
56 |
3
57 |
58 |
59 |
Owl
60 |
Bird
61 |
Parliament
62 |
4
63 |
64 |
65 |
Frog
66 |
Amphibian
67 |
Army
68 |
5
69 |
70 |
71 |
Shark
72 |
Fish
73 |
Gam
74 |
6
75 |
76 |
77 |
Kookaburra
78 |
Bird
79 |
Cackle
80 |
7
81 |
82 |
83 |
Crow
84 |
Bird
85 |
Murder
86 |
8
87 |
88 |
89 |
Elephant
90 |
Mammal
91 |
Herd
92 |
9
93 |
94 |
95 |
Barracude
96 |
Fish
97 |
Grist
98 |
10
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
Table 2
107 |
108 |
109 |
110 |
Animal
111 |
Class
112 |
Collective Noun
113 |
A Number
114 |
115 |
116 |
117 |
118 |
Bear
119 |
Mammal
120 |
Sleuth
121 |
1
122 |
123 |
124 |
Ant
125 |
Insect
126 |
Army
127 |
2
128 |
129 |
130 |
Salamander
131 |
Amphibian
132 |
Congress
133 |
3
134 |
135 |
136 |
Owl
137 |
Bird
138 |
Parliament
139 |
4
140 |
141 |
142 |
Frog
143 |
Amphibian
144 |
Army
145 |
5
146 |
147 |
148 |
Shark
149 |
Fish
150 |
Gam
151 |
6
152 |
153 |
154 |
Kookaburra
155 |
Bird
156 |
Cackle
157 |
7
158 |
159 |
160 |
Crow
161 |
Bird
162 |
Murder
163 |
8
164 |
165 |
166 |
Elephant
167 |
Mammal
168 |
Herd
169 |
9
170 |
171 |
172 |
Barracude
173 |
Fish
174 |
Grist
175 |
10
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
Table 3
184 |
185 |
186 |
187 |
Company
188 |
Contact
189 |
Country
190 |
191 |
192 |
193 |
194 |
Alfreds Futterkiste
195 |
Maria Anders
196 |
Germany
197 |
198 |
199 |
Centro comercial Moctezuma
200 |
Francisco Chang
201 |
Mexico
202 |
203 |
204 |
Ernst Handel
205 |
Roland Mendel
206 |
Austria
207 |
208 |
209 |
Island Trading
210 |
Helen Bennett
211 |
UK
212 |
213 |
214 |
Laughing Bacchus Winecellars
215 |
Yoshi Tannamuri
216 |
Canada
217 |
218 |
219 |
Magazzini Alimentari Riuniti
220 |
Giovanni Rovelli
221 |
Italy
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
239 |
240 |
241 |
242 |
243 |
--------------------------------------------------------------------------------
/dist/excel-bootstrap-table-filter-bundle.js:
--------------------------------------------------------------------------------
1 | (function ($$1) {
2 | 'use strict';
3 |
4 | $$1 = 'default' in $$1 ? $$1['default'] : $$1;
5 |
6 | var FilterMenu = function () {
7 | function FilterMenu(target, th, column, index, options) {
8 | this.options = options;
9 | this.th = th;
10 | this.column = column;
11 | this.index = index;
12 | this.tds = target.find('tbody tr td:nth-child(' + (this.column + 1) + ')').toArray();
13 | }
14 | FilterMenu.prototype.initialize = function () {
15 | this.menu = this.dropdownFilterDropdown();
16 | this.th.appendChild(this.menu);
17 | var $trigger = $(this.menu.children[0]);
18 | var $content = $(this.menu.children[1]);
19 | var $menu = $(this.menu);
20 | $trigger.click(function () {
21 | return $content.toggle();
22 | });
23 | $(document).click(function (el) {
24 | if (!$menu.is(el.target) && $menu.has(el.target).length === 0) {
25 | $content.hide();
26 | }
27 | });
28 | };
29 | FilterMenu.prototype.searchToggle = function (value) {
30 | if (this.selectAllCheckbox instanceof HTMLInputElement) this.selectAllCheckbox.checked = false;
31 | if (value.length === 0) {
32 | this.toggleAll(true);
33 | if (this.selectAllCheckbox instanceof HTMLInputElement) this.selectAllCheckbox.checked = true;
34 | return;
35 | }
36 | this.toggleAll(false);
37 | this.inputs.filter(function (input) {
38 | return input.value.toLowerCase().indexOf(value.toLowerCase()) > -1;
39 | }).forEach(function (input) {
40 | input.checked = true;
41 | });
42 | };
43 | FilterMenu.prototype.updateSelectAll = function () {
44 | if (this.selectAllCheckbox instanceof HTMLInputElement) {
45 | $(this.searchFilter).val('');
46 | this.selectAllCheckbox.checked = this.inputs.length === this.inputs.filter(function (input) {
47 | return input.checked;
48 | }).length;
49 | }
50 | };
51 | FilterMenu.prototype.selectAllUpdate = function (checked) {
52 | $(this.searchFilter).val('');
53 | this.toggleAll(checked);
54 | };
55 | FilterMenu.prototype.toggleAll = function (checked) {
56 | for (var i = 0; i < this.inputs.length; i++) {
57 | var input = this.inputs[i];
58 | if (input instanceof HTMLInputElement) input.checked = checked;
59 | }
60 | };
61 | FilterMenu.prototype.dropdownFilterItem = function (td, self) {
62 | var value = td.innerText;
63 | var dropdownFilterItem = document.createElement('div');
64 | dropdownFilterItem.className = 'dropdown-filter-item';
65 | var input = document.createElement('input');
66 | input.type = 'checkbox';
67 | input.value = value.trim().replace(/ +(?= )/g, '');
68 | input.setAttribute('checked', 'checked');
69 | input.className = 'dropdown-filter-menu-item item';
70 | input.setAttribute('data-column', self.column.toString());
71 | input.setAttribute('data-index', self.index.toString());
72 | dropdownFilterItem.appendChild(input);
73 | dropdownFilterItem.innerHTML = dropdownFilterItem.innerHTML.trim() + ' ' + value;
74 | return dropdownFilterItem;
75 | };
76 | FilterMenu.prototype.dropdownFilterItemSelectAll = function () {
77 | var value = this.options.captions.select_all;
78 | var dropdownFilterItemSelectAll = document.createElement('div');
79 | dropdownFilterItemSelectAll.className = 'dropdown-filter-item';
80 | var input = document.createElement('input');
81 | input.type = 'checkbox';
82 | input.value = this.options.captions.select_all;
83 | input.setAttribute('checked', 'checked');
84 | input.className = 'dropdown-filter-menu-item select-all';
85 | input.setAttribute('data-column', this.column.toString());
86 | input.setAttribute('data-index', this.index.toString());
87 | dropdownFilterItemSelectAll.appendChild(input);
88 | dropdownFilterItemSelectAll.innerHTML = dropdownFilterItemSelectAll.innerHTML + ' ' + value;
89 | return dropdownFilterItemSelectAll;
90 | };
91 | FilterMenu.prototype.dropdownFilterSearch = function () {
92 | var dropdownFilterItem = document.createElement('div');
93 | dropdownFilterItem.className = 'dropdown-filter-search';
94 | var input = document.createElement('input');
95 | input.type = 'text';
96 | input.className = 'dropdown-filter-menu-search form-control';
97 | input.setAttribute('data-column', this.column.toString());
98 | input.setAttribute('data-index', this.index.toString());
99 | input.setAttribute('placeholder', this.options.captions.search);
100 | dropdownFilterItem.appendChild(input);
101 | return dropdownFilterItem;
102 | };
103 | FilterMenu.prototype.dropdownFilterSort = function (direction) {
104 | var dropdownFilterItem = document.createElement('div');
105 | dropdownFilterItem.className = 'dropdown-filter-sort';
106 | var span = document.createElement('span');
107 | span.className = direction.toLowerCase().split(' ').join('-');
108 | span.setAttribute('data-column', this.column.toString());
109 | span.setAttribute('data-index', this.index.toString());
110 | span.innerText = direction;
111 | dropdownFilterItem.appendChild(span);
112 | return dropdownFilterItem;
113 | };
114 | FilterMenu.prototype.dropdownFilterContent = function () {
115 | var _this = this;
116 | var self = this;
117 | var dropdownFilterContent = document.createElement('div');
118 | dropdownFilterContent.className = 'dropdown-filter-content';
119 | var innerDivs = this.tds.reduce(function (arr, el) {
120 | var values = arr.map(function (el) {
121 | return el.innerText.trim();
122 | });
123 | if (values.indexOf(el.innerText.trim()) < 0) arr.push(el);
124 | return arr;
125 | }, []).sort(function (a, b) {
126 | var A = a.innerText.toLowerCase();
127 | var B = b.innerText.toLowerCase();
128 | if (!isNaN(Number(A)) && !isNaN(Number(B))) {
129 | if (Number(A) < Number(B)) return -1;
130 | if (Number(A) > Number(B)) return 1;
131 | } else {
132 | if (A < B) return -1;
133 | if (A > B) return 1;
134 | }
135 | return 0;
136 | }).map(function (td) {
137 | return _this.dropdownFilterItem(td, self);
138 | });
139 | this.inputs = innerDivs.map(function (div) {
140 | return div.firstElementChild;
141 | });
142 | var selectAllCheckboxDiv = this.dropdownFilterItemSelectAll();
143 | this.selectAllCheckbox = selectAllCheckboxDiv.firstElementChild;
144 | innerDivs.unshift(selectAllCheckboxDiv);
145 | var searchFilterDiv = this.dropdownFilterSearch();
146 | this.searchFilter = searchFilterDiv.firstElementChild;
147 | var outerDiv = innerDivs.reduce(function (outerDiv, innerDiv) {
148 | outerDiv.appendChild(innerDiv);
149 | return outerDiv;
150 | }, document.createElement('div'));
151 | outerDiv.className = 'checkbox-container';
152 | var elements = [];
153 | if (this.options.sort) elements = elements.concat([this.dropdownFilterSort(this.options.captions.a_to_z), this.dropdownFilterSort(this.options.captions.z_to_a)]);
154 | if (this.options.search) elements.push(searchFilterDiv);
155 | return elements.concat(outerDiv).reduce(function (html, el) {
156 | html.appendChild(el);
157 | return html;
158 | }, dropdownFilterContent);
159 | };
160 | FilterMenu.prototype.dropdownFilterDropdown = function () {
161 | var dropdownFilterDropdown = document.createElement('div');
162 | dropdownFilterDropdown.className = 'dropdown-filter-dropdown';
163 | var arrow = document.createElement('span');
164 | arrow.className = 'glyphicon glyphicon-arrow-down dropdown-filter-icon';
165 | var icon = document.createElement('i');
166 | icon.className = 'arrow-down';
167 | arrow.appendChild(icon);
168 | dropdownFilterDropdown.appendChild(arrow);
169 | dropdownFilterDropdown.appendChild(this.dropdownFilterContent());
170 | if ($(this.th).hasClass('no-sort')) {
171 | $(dropdownFilterDropdown).find('.dropdown-filter-sort').remove();
172 | }
173 | if ($(this.th).hasClass('no-filter')) {
174 | $(dropdownFilterDropdown).find('.checkbox-container').remove();
175 | }
176 | if ($(this.th).hasClass('no-search')) {
177 | $(dropdownFilterDropdown).find('.dropdown-filter-search').remove();
178 | }
179 | return dropdownFilterDropdown;
180 | };
181 | return FilterMenu;
182 | }();
183 |
184 | var FilterCollection = function () {
185 | function FilterCollection(target, options) {
186 | this.target = target;
187 | this.options = options;
188 | this.ths = target.find('th' + options.columnSelector).toArray();
189 | this.filterMenus = this.ths.map(function (th, index) {
190 | var column = $(th).index();
191 | return new FilterMenu(target, th, column, index, options);
192 | });
193 | this.rows = target.find('tbody').find('tr').toArray();
194 | this.table = target.get(0);
195 | }
196 | FilterCollection.prototype.initialize = function () {
197 | this.filterMenus.forEach(function (filterMenu) {
198 | filterMenu.initialize();
199 | });
200 | this.bindCheckboxes();
201 | this.bindSelectAllCheckboxes();
202 | this.bindSort();
203 | this.bindSearch();
204 | };
205 | FilterCollection.prototype.bindCheckboxes = function () {
206 | var filterMenus = this.filterMenus;
207 | var rows = this.rows;
208 | var ths = this.ths;
209 | var updateRowVisibility = this.updateRowVisibility;
210 | this.target.find('.dropdown-filter-menu-item.item').change(function () {
211 | var index = $(this).data('index');
212 | var value = $(this).val();
213 | filterMenus[index].updateSelectAll();
214 | updateRowVisibility(filterMenus, rows, ths);
215 | });
216 | };
217 | FilterCollection.prototype.bindSelectAllCheckboxes = function () {
218 | var filterMenus = this.filterMenus;
219 | var rows = this.rows;
220 | var ths = this.ths;
221 | var updateRowVisibility = this.updateRowVisibility;
222 | this.target.find('.dropdown-filter-menu-item.select-all').change(function () {
223 | var index = $(this).data('index');
224 | var value = this.checked;
225 | filterMenus[index].selectAllUpdate(value);
226 | updateRowVisibility(filterMenus, rows, ths);
227 | });
228 | };
229 | FilterCollection.prototype.bindSort = function () {
230 | var filterMenus = this.filterMenus;
231 | var rows = this.rows;
232 | var ths = this.ths;
233 | var sort = this.sort;
234 | var table = this.table;
235 | var options = this.options;
236 | var updateRowVisibility = this.updateRowVisibility;
237 | this.target.find('.dropdown-filter-sort').click(function () {
238 | var $sortElement = $(this).find('span');
239 | var column = $sortElement.data('column');
240 | var order = $sortElement.attr('class');
241 | sort(column, order, table, options);
242 | updateRowVisibility(filterMenus, rows, ths);
243 | });
244 | };
245 | FilterCollection.prototype.bindSearch = function () {
246 | var filterMenus = this.filterMenus;
247 | var rows = this.rows;
248 | var ths = this.ths;
249 | var updateRowVisibility = this.updateRowVisibility;
250 | this.target.find('.dropdown-filter-search').keyup(function () {
251 | var $input = $(this).find('input');
252 | var index = $input.data('index');
253 | var value = $input.val();
254 | filterMenus[index].searchToggle(value);
255 | updateRowVisibility(filterMenus, rows, ths);
256 | });
257 | };
258 | FilterCollection.prototype.updateRowVisibility = function (filterMenus, rows, ths) {
259 | var showRows = rows;
260 | var hideRows = [];
261 | var selectedLists = filterMenus.map(function (filterMenu) {
262 | return {
263 | column: filterMenu.column,
264 | selected: filterMenu.inputs.filter(function (input) {
265 | return input.checked;
266 | }).map(function (input) {
267 | return input.value.trim().replace(/ +(?= )/g, '');
268 | })
269 | };
270 | });
271 | for (var i = 0; i < rows.length; i++) {
272 | var tds = rows[i].children;
273 | for (var j = 0; j < selectedLists.length; j++) {
274 | var content = tds[selectedLists[j].column].innerText.trim().replace(/ +(?= )/g, '');
275 | if (selectedLists[j].selected.indexOf(content) === -1) {
276 | $(rows[i]).hide();
277 | break;
278 | }
279 | $(rows[i]).show();
280 | }
281 | }
282 | };
283 | FilterCollection.prototype.sort = function (column, order, table, options) {
284 | var flip = 1;
285 | if (order === options.captions.z_to_a.toLowerCase().split(' ').join('-')) flip = -1;
286 | var tbody = $(table).find('tbody').get(0);
287 | var rows = $(tbody).find('tr').get();
288 | rows.sort(function (a, b) {
289 | var A = a.children[column].innerText.toUpperCase();
290 | var B = b.children[column].innerText.toUpperCase();
291 | if (!isNaN(Number(A)) && !isNaN(Number(B))) {
292 | if (Number(A) < Number(B)) return -1 * flip;
293 | if (Number(A) > Number(B)) return 1 * flip;
294 | } else {
295 | if (A < B) return -1 * flip;
296 | if (A > B) return 1 * flip;
297 | }
298 | return 0;
299 | });
300 | for (var i = 0; i < rows.length; i++) {
301 | tbody.appendChild(rows[i]);
302 | }
303 | };
304 | return FilterCollection;
305 | }();
306 |
307 | $$1.fn.excelTableFilter = function (options) {
308 | var target = this;
309 | options = $$1.extend({}, $$1.fn.excelTableFilter.options, options);
310 | if (typeof options.columnSelector === 'undefined') options.columnSelector = '';
311 | if (typeof options.sort === 'undefined') options.sort = true;
312 | if (typeof options.search === 'undefined') options.search = true;
313 | if (typeof options.captions === 'undefined') options.captions = {
314 | a_to_z: 'A to Z',
315 | z_to_a: 'Z to A',
316 | search: 'Search',
317 | select_all: 'Select All'
318 | };
319 | var filterCollection = new FilterCollection(target, options);
320 | filterCollection.initialize();
321 | return target;
322 | };
323 | $$1.fn.excelTableFilter.options = {};
324 |
325 | }(jQuery));
326 | //# sourceMappingURL=excel-bootstrap-table-filter-bundle.js.map
327 |
--------------------------------------------------------------------------------
/dist/excel-bootstrap-table-filter-bundle.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"excel-bootstrap-table-filter-bundle.js","sources":["../src/FilterMenu.ts","../src/FilterCollection.ts","../src/excel-bootstrap-table-filter.ts"],"sourcesContent":["export class FilterMenu {\n\n th: HTMLElement;\n tds: Array;\n column: number;\n index: number;\n menu: HTMLElement;\n inputs: Array;\n selectAllCheckbox: Element;\n searchFilter: Element;\n options: Options;\n target: JQuery;\n\n constructor (target: JQuery, th: HTMLElement, column: number, index: number, options: Options) {\n this.options = options;\n this.th = th;\n this.column = column;\n this.index = index;\n this.tds = target.find('tbody tr td:nth-child(' + (this.column + 1) + ')').toArray();\n }\n\n public initialize(): void {\n this.menu = this.dropdownFilterDropdown();\n this.th.appendChild(this.menu);\n\n // variables for click handlers\n let $trigger = $(this.menu.children[0]);\n let $content = $(this.menu.children[1]);\n let $menu = $(this.menu);\n\n // toggle hide/show when the trigger is clicked\n $trigger.click(() => $content.toggle());\n\n $(document).click(function(el) {\n // hide the content if the user clicks outside of the menu\n if (!$menu.is(el.target) && $menu.has(el.target).length === 0) {\n $content.hide();\n }\n });\n }\n\n public searchToggle(value: string): void {\n if (this.selectAllCheckbox instanceof HTMLInputElement) this.selectAllCheckbox.checked = false;\n if (value.length === 0){\n this.toggleAll(true);\n if (this.selectAllCheckbox instanceof HTMLInputElement) this.selectAllCheckbox.checked = true;\n return;\n }\n // deselect all checkboxes initially\n this.toggleAll(false);\n // select checkboxes that match the search parameter\n this.inputs.filter(function(input: HTMLInputElement) {\n return input.value.toLowerCase().indexOf(value.toLowerCase()) > -1;\n }).forEach(function(input: HTMLInputElement) {\n input.checked = true;\n });\n }\n\n\n public updateSelectAll(): void {\n if (this.selectAllCheckbox instanceof HTMLInputElement) {\n // clear search parameters, if any\n $(this.searchFilter).val('');\n // Check if all inputs are selected\n this.selectAllCheckbox.checked = (this.inputs.length === this.inputs.filter(function(input: HTMLInputElement) {\n return input.checked;\n }).length);\n }\n }\n\n public selectAllUpdate(checked: boolean): void {\n // clear search parameters, if any\n $(this.searchFilter).val('');\n this.toggleAll(checked);\n }\n\n private toggleAll(checked: boolean): void {\n // loop through all inputs and check or uncheck each\n for (var i=0; i < this.inputs.length; i++) {\n let input = this.inputs[i];\n if (input instanceof HTMLInputElement) input.checked = checked;\n }\n }\n\n private dropdownFilterItem(td: HTMLElement, self: any): HTMLElement {\n // build holder div\n let value = td.innerText;\n let dropdownFilterItem = document.createElement('div');\n dropdownFilterItem.className = 'dropdown-filter-item';\n // build input\n let input = document.createElement('input');\n input.type = 'checkbox';\n input.value = value.trim().replace(/ +(?= )/g,'');\n input.setAttribute('checked','checked');\n input.className = 'dropdown-filter-menu-item item';\n // get index of td element\n input.setAttribute('data-column', self.column.toString());\n input.setAttribute('data-index', self.index.toString());\n // append input to holding div\n dropdownFilterItem.appendChild(input);\n dropdownFilterItem.innerHTML = dropdownFilterItem.innerHTML.trim() + ' ' + value;\n return dropdownFilterItem;\n }\n\n private dropdownFilterItemSelectAll(): HTMLElement {\n // build holder div\n let value = this.options.captions.select_all;\n let dropdownFilterItemSelectAll = document.createElement('div');\n dropdownFilterItemSelectAll.className = 'dropdown-filter-item';\n // build input\n let input = document.createElement('input');\n input.type = 'checkbox';\n input.value = this.options.captions.select_all;\n input.setAttribute('checked','checked');\n input.className = 'dropdown-filter-menu-item select-all';\n input.setAttribute('data-column', this.column.toString());\n input.setAttribute('data-index', this.index.toString());\n // append input to holding div\n dropdownFilterItemSelectAll.appendChild(input);\n dropdownFilterItemSelectAll.innerHTML = dropdownFilterItemSelectAll.innerHTML + ' ' + value;\n return dropdownFilterItemSelectAll;\n }\n\n private dropdownFilterSearch(): HTMLElement {\n // build holder div\n let dropdownFilterItem = document.createElement('div');\n dropdownFilterItem.className = 'dropdown-filter-search';\n // build input\n let input = document.createElement('input');\n input.type = 'text';\n input.className = 'dropdown-filter-menu-search form-control';\n input.setAttribute('data-column', this.column.toString());\n input.setAttribute('data-index', this.index.toString());\n input.setAttribute('placeholder', this.options.captions.search);\n // append input to holding div\n dropdownFilterItem.appendChild(input);\n return dropdownFilterItem;\n }\n\n private dropdownFilterSort(direction: string): HTMLElement {\n // build holder div\n let dropdownFilterItem = document.createElement('div');\n dropdownFilterItem.className = 'dropdown-filter-sort';\n // build span\n let span = document.createElement('span');\n span.className = direction.toLowerCase().split(' ').join('-');\n span.setAttribute('data-column', this.column.toString());\n span.setAttribute('data-index', this.index.toString());\n span.innerText = direction;\n // append input to holding div\n dropdownFilterItem.appendChild(span);\n return dropdownFilterItem;\n }\n\n private dropdownFilterContent(): HTMLElement {\n let self = this;\n // build holder div\n let dropdownFilterContent = document.createElement('div');\n dropdownFilterContent.className = 'dropdown-filter-content';\n\n let innerDivs = this.tds.reduce(function(arr, el) {\n // get unique values in column\n let values = arr.map((el) => el.innerText.trim());\n if (values.indexOf(el.innerText.trim()) < 0) arr.push(el);\n // return unique values\n return arr;\n }, [])\n .sort(function(a, b) {\n // sort values for display in dropdown\n var A = a.innerText.toLowerCase();\n var B = b.innerText.toLowerCase();\n\n if (!isNaN(Number(A)) && !isNaN(Number(B))) {\n\n // handle numbers\n if(Number(A) < Number(B)) return -1;\n if(Number(A) > Number(B)) return 1;\n\n } else {\n\n // handle strings\n if(A < B) return -1;\n if(A > B) return 1;\n\n }\n //return a.innerText.toLowerCase() > b.innerText.toLowerCase() ? 1 : -1;\n return 0;\n })\n // create dropdown filter items out of each value\n .map( (td) => {\n return this.dropdownFilterItem(td, self);\n })\n\n // map inputs to instance, we will need these later\n this.inputs = innerDivs.map((div) => div.firstElementChild);\n\n // add a select all checkbox\n let selectAllCheckboxDiv = this.dropdownFilterItemSelectAll();\n // map the select all checkbox to the instance, we will need it later\n this.selectAllCheckbox = selectAllCheckboxDiv.firstElementChild;\n // the checkbox will precede the other inputs\n innerDivs.unshift(selectAllCheckboxDiv);\n\n let searchFilterDiv = this.dropdownFilterSearch();\n this.searchFilter = searchFilterDiv.firstElementChild;\n\n // create outer div, and place all inner divs within it\n let outerDiv = innerDivs.reduce(function(outerDiv, innerDiv) {\n outerDiv.appendChild(innerDiv);\n return outerDiv;\n }, document.createElement('div'));\n outerDiv.className = 'checkbox-container';\n\n let elements: Array = [];\n if (this.options.sort ) elements= elements.concat([\n this.dropdownFilterSort(this.options.captions.a_to_z),\n this.dropdownFilterSort(this.options.captions.z_to_a)\n ]);\n if (this.options.search) elements.push(searchFilterDiv);\n\n return elements.concat(outerDiv).reduce(function(html, el) {\n html.appendChild(el);\n return html;\n }, dropdownFilterContent);\n }\n\n private dropdownFilterDropdown(): HTMLElement {\n // build holder div\n let dropdownFilterDropdown = document.createElement('div');\n dropdownFilterDropdown.className = 'dropdown-filter-dropdown';\n let arrow = document.createElement('span');\n arrow.className = 'glyphicon glyphicon-arrow-down dropdown-filter-icon';\n let icon = document.createElement('i');\n icon.className = 'arrow-down';\n arrow.appendChild(icon);\n dropdownFilterDropdown.appendChild(arrow);\n dropdownFilterDropdown.appendChild(this.dropdownFilterContent());\n\n if ($(this.th).hasClass('no-sort')) {\n $(dropdownFilterDropdown).find('.dropdown-filter-sort').remove();\n }\n if ($(this.th).hasClass('no-filter')) {\n $(dropdownFilterDropdown).find('.checkbox-container').remove();\n }\n if ($(this.th).hasClass('no-search')) {\n $(dropdownFilterDropdown).find('.dropdown-filter-search').remove();\n }\n return dropdownFilterDropdown;\n }\n\n}\n","import { FilterMenu } from './FilterMenu'\n\nexport class FilterCollection {\n\n filterMenus: Array;\n rows: Array;\n ths: Array;\n table: HTMLElement;\n options: Options;\n target: JQuery;\n\n constructor (target: JQuery, options: Options) {\n this.target = target;\n this.options = options;\n this.ths = target.find('th' + options.columnSelector).toArray()\n this.filterMenus = this.ths.map(function(th: HTMLElement, index: number) {\n let column = $(th).index();\n return new FilterMenu(target, th, column, index, options);\n });\n this.rows = target.find('tbody').find('tr').toArray();\n this.table = target.get(0);\n }\n\n public initialize(): void {\n this.filterMenus.forEach(function(filterMenu) {\n filterMenu.initialize();\n });\n this.bindCheckboxes();\n this.bindSelectAllCheckboxes();\n this.bindSort();\n this.bindSearch();\n }\n\n private bindCheckboxes(): void {\n let filterMenus = this.filterMenus;\n let rows = this.rows;\n let ths = this.ths;\n let updateRowVisibility = this.updateRowVisibility;\n this.target.find('.dropdown-filter-menu-item.item').change(function() {\n let index = $(this).data('index');\n let value = $(this).val();\n filterMenus[index].updateSelectAll();\n updateRowVisibility(filterMenus, rows, ths);\n });\n }\n\n private bindSelectAllCheckboxes(): void {\n let filterMenus = this.filterMenus;\n let rows = this.rows;\n let ths = this.ths;\n let updateRowVisibility = this.updateRowVisibility;\n this.target.find('.dropdown-filter-menu-item.select-all').change(function() {\n let index = $(this).data('index');\n let value = this.checked;\n filterMenus[index].selectAllUpdate(value);\n updateRowVisibility(filterMenus, rows, ths);\n });\n }\n\n private bindSort(): void {\n let filterMenus = this.filterMenus;\n let rows = this.rows;\n let ths = this.ths;\n let sort = this.sort;\n let table = this.table;\n let options = this.options;\n let updateRowVisibility = this.updateRowVisibility;\n this.target.find('.dropdown-filter-sort').click(function() {\n let $sortElement = $(this).find('span');\n let column = $sortElement.data('column');\n let order = $sortElement.attr('class');\n sort(column, order, table, options);\n updateRowVisibility(filterMenus, rows, ths);\n });\n }\n\n private bindSearch(): void {\n let filterMenus = this.filterMenus;\n let rows = this.rows;\n let ths = this.ths;\n let updateRowVisibility = this.updateRowVisibility;\n this.target.find('.dropdown-filter-search').keyup(function() {\n let $input = $(this).find('input');\n let index = $input.data('index');\n let value = $input.val();\n filterMenus[index].searchToggle(value);\n updateRowVisibility(filterMenus, rows, ths);\n });\n }\n\n private updateRowVisibility(filterMenus: Array, rows: Array, ths: Array): void {\n let showRows = rows;\n let hideRows: Array = [];\n let selectedLists = filterMenus.map(function(filterMenu) {\n return {\n column: filterMenu.column,\n selected: filterMenu.inputs\n .filter(function(input: HTMLInputElement) {\n return input.checked\n }).map(function(input: HTMLInputElement) {\n return input.value.trim().replace(/ +(?= )/g,'');\n })\n };\n });\n for (let i=0; i < rows.length; i++) {\n let tds = rows[i].children;\n for (let j=0; j < selectedLists.length; j++) {\n let content = (tds[selectedLists[j].column] as HTMLElement).innerText.trim().replace(/ +(?= )/g,'')\n if (selectedLists[j].selected.indexOf(content) === -1 ) {\n $(rows[i]).hide();\n break;\n }\n $(rows[i]).show();\n }\n }\n }\n\n private sort(column: number, order: string, table: HTMLElement, options: Options): void {\n let flip = 1;\n if (order === options.captions.z_to_a.toLowerCase().split(' ').join('-')) flip = -1;\n let tbody = $(table).find('tbody').get(0);\n let rows = $(tbody).find('tr').get();\n\n rows.sort(function(a, b) {\n var A = (a.children[column] as HTMLElement).innerText.toUpperCase();\n var B = (b.children[column] as HTMLElement).innerText.toUpperCase();\n\n if (!isNaN(Number(A)) && !isNaN(Number(B))) {\n // handle numbers\n if(Number(A) < Number(B)) return -1*flip;\n if(Number(A) > Number(B)) return 1*flip;\n } else {\n // handle strings\n if(A < B) return -1*flip;\n if(A > B) return 1*flip;\n }\n return 0;\n });\n\n for (var i=0; i < rows.length; i++) {\n tbody.appendChild(rows[i]);\n }\n }\n\n\n}\n","import $ from 'jquery';\nimport { FilterCollection } from './FilterCollection'\n\n// Define the plugin function on the jQuery extension point.\n($.fn as any).excelTableFilter = function (this: JQuery, options: Options) {\n let target = this;\n // Merge the global options with the per-call options.\n options = $.extend({}, ($.fn as any).excelTableFilter.options, options);\n\n if (typeof options.columnSelector === 'undefined') options.columnSelector = '';\n if (typeof options.sort === 'undefined') options.sort = true;\n if (typeof options.search === 'undefined') options.search = true;\n\n if (typeof options.captions === 'undefined') options.captions = {\n a_to_z: 'A to Z',\n z_to_a: 'Z to A',\n search: 'Search',\n select_all: 'Select All'\n }\n\n let filterCollection = new FilterCollection(target, options);\n filterCollection.initialize();\n\n // Return the jQuery object for chaining.\n return target;\n};\n\n// Define the plugin's global default options.\n($.fn as any).excelTableFilter.options = {};\n"],"names":["target","th","column","index","options","tds","find","toArray","menu","dropdownFilterDropdown","appendChild","$trigger","$","children","$content","$menu","click","toggle","document","el","is","has","length","hide","value","selectAllCheckbox","HTMLInputElement","checked","toggleAll","inputs","filter","input","toLowerCase","indexOf","forEach","searchFilter","val","i","td","self","innerText","dropdownFilterItem","createElement","className","type","trim","replace","setAttribute","toString","innerHTML","captions","select_all","dropdownFilterItemSelectAll","search","direction","span","split","join","dropdownFilterContent","innerDivs","reduce","arr","values","map","push","sort","a","b","A","B","isNaN","Number","_this","div","firstElementChild","selectAllCheckboxDiv","unshift","searchFilterDiv","dropdownFilterSearch","outerDiv","innerDiv","elements","concat","dropdownFilterSort","a_to_z","z_to_a","html","arrow","icon","hasClass","remove","ths","columnSelector","filterMenus","FilterMenu","rows","table","get","filterMenu","initialize","bindCheckboxes","bindSelectAllCheckboxes","bindSort","bindSearch","updateRowVisibility","change","data","updateSelectAll","selectAllUpdate","$sortElement","order","attr","keyup","$input","searchToggle","showRows","hideRows","selectedLists","j","content","selected","show","flip","tbody","toUpperCase","fn","excelTableFilter","extend","filterCollection","FilterCollection"],"mappings":"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"}
--------------------------------------------------------------------------------
/dist/excel-bootstrap-table-filter-bundle.min.js:
--------------------------------------------------------------------------------
1 | (function($$1){"use strict";$$1="default"in $$1?$$1["default"]:$$1;var FilterMenu=function(){function FilterMenu(target,th,column,index,options){this.options=options;this.th=th;this.column=column;this.index=index;this.tds=target.find("tbody tr td:nth-child("+(this.column+1)+")").toArray()}FilterMenu.prototype.initialize=function(){this.menu=this.dropdownFilterDropdown();this.th.appendChild(this.menu);var $trigger=$(this.menu.children[0]);var $content=$(this.menu.children[1]);var $menu=$(this.menu);$trigger.click(function(){return $content.toggle()});$(document).click(function(el){if(!$menu.is(el.target)&&$menu.has(el.target).length===0){$content.hide()}})};FilterMenu.prototype.searchToggle=function(value){if(this.selectAllCheckbox instanceof HTMLInputElement)this.selectAllCheckbox.checked=false;if(value.length===0){this.toggleAll(true);if(this.selectAllCheckbox instanceof HTMLInputElement)this.selectAllCheckbox.checked=true;return}this.toggleAll(false);this.inputs.filter(function(input){return input.value.toLowerCase().indexOf(value.toLowerCase())>-1}).forEach(function(input){input.checked=true})};FilterMenu.prototype.updateSelectAll=function(){if(this.selectAllCheckbox instanceof HTMLInputElement){$(this.searchFilter).val("");this.selectAllCheckbox.checked=this.inputs.length===this.inputs.filter(function(input){return input.checked}).length}};FilterMenu.prototype.selectAllUpdate=function(checked){$(this.searchFilter).val("");this.toggleAll(checked)};FilterMenu.prototype.toggleAll=function(checked){for(var i=0;iNumber(B))return 1}else{if(AB)return 1}return 0}).map(function(td){return _this.dropdownFilterItem(td,self)});this.inputs=innerDivs.map(function(div){return div.firstElementChild});var selectAllCheckboxDiv=this.dropdownFilterItemSelectAll();this.selectAllCheckbox=selectAllCheckboxDiv.firstElementChild;innerDivs.unshift(selectAllCheckboxDiv);var searchFilterDiv=this.dropdownFilterSearch();this.searchFilter=searchFilterDiv.firstElementChild;var outerDiv=innerDivs.reduce(function(outerDiv,innerDiv){outerDiv.appendChild(innerDiv);return outerDiv},document.createElement("div"));outerDiv.className="checkbox-container";var elements=[];if(this.options.sort)elements=elements.concat([this.dropdownFilterSort(this.options.captions.a_to_z),this.dropdownFilterSort(this.options.captions.z_to_a)]);if(this.options.search)elements.push(searchFilterDiv);return elements.concat(outerDiv).reduce(function(html,el){html.appendChild(el);return html},dropdownFilterContent)};FilterMenu.prototype.dropdownFilterDropdown=function(){var dropdownFilterDropdown=document.createElement("div");dropdownFilterDropdown.className="dropdown-filter-dropdown";var arrow=document.createElement("span");arrow.className="glyphicon glyphicon-arrow-down dropdown-filter-icon";var icon=document.createElement("i");icon.className="arrow-down";arrow.appendChild(icon);dropdownFilterDropdown.appendChild(arrow);dropdownFilterDropdown.appendChild(this.dropdownFilterContent());if($(this.th).hasClass("no-sort")){$(dropdownFilterDropdown).find(".dropdown-filter-sort").remove()}if($(this.th).hasClass("no-filter")){$(dropdownFilterDropdown).find(".checkbox-container").remove()}if($(this.th).hasClass("no-search")){$(dropdownFilterDropdown).find(".dropdown-filter-search").remove()}return dropdownFilterDropdown};return FilterMenu}();var FilterCollection=function(){function FilterCollection(target,options){this.target=target;this.options=options;this.ths=target.find("th"+options.columnSelector).toArray();this.filterMenus=this.ths.map(function(th,index){var column=$(th).index();return new FilterMenu(target,th,column,index,options)});this.rows=target.find("tbody").find("tr").toArray();this.table=target.get(0)}FilterCollection.prototype.initialize=function(){this.filterMenus.forEach(function(filterMenu){filterMenu.initialize()});this.bindCheckboxes();this.bindSelectAllCheckboxes();this.bindSort();this.bindSearch()};FilterCollection.prototype.bindCheckboxes=function(){var filterMenus=this.filterMenus;var rows=this.rows;var ths=this.ths;var updateRowVisibility=this.updateRowVisibility;this.target.find(".dropdown-filter-menu-item.item").change(function(){var index=$(this).data("index");var value=$(this).val();filterMenus[index].updateSelectAll();updateRowVisibility(filterMenus,rows,ths)})};FilterCollection.prototype.bindSelectAllCheckboxes=function(){var filterMenus=this.filterMenus;var rows=this.rows;var ths=this.ths;var updateRowVisibility=this.updateRowVisibility;this.target.find(".dropdown-filter-menu-item.select-all").change(function(){var index=$(this).data("index");var value=this.checked;filterMenus[index].selectAllUpdate(value);updateRowVisibility(filterMenus,rows,ths)})};FilterCollection.prototype.bindSort=function(){var filterMenus=this.filterMenus;var rows=this.rows;var ths=this.ths;var sort=this.sort;var table=this.table;var options=this.options;var updateRowVisibility=this.updateRowVisibility;this.target.find(".dropdown-filter-sort").click(function(){var $sortElement=$(this).find("span");var column=$sortElement.data("column");var order=$sortElement.attr("class");sort(column,order,table,options);updateRowVisibility(filterMenus,rows,ths)})};FilterCollection.prototype.bindSearch=function(){var filterMenus=this.filterMenus;var rows=this.rows;var ths=this.ths;var updateRowVisibility=this.updateRowVisibility;this.target.find(".dropdown-filter-search").keyup(function(){var $input=$(this).find("input");var index=$input.data("index");var value=$input.val();filterMenus[index].searchToggle(value);updateRowVisibility(filterMenus,rows,ths)})};FilterCollection.prototype.updateRowVisibility=function(filterMenus,rows,ths){var showRows=rows;var hideRows=[];var selectedLists=filterMenus.map(function(filterMenu){return{column:filterMenu.column,selected:filterMenu.inputs.filter(function(input){return input.checked}).map(function(input){return input.value.trim().replace(/ +(?= )/g,"")})}});for(var i=0;iNumber(B))return 1*flip}else{if(AB)return 1*flip}return 0});for(var i=0;i;\n column: number;\n index: number;\n menu: HTMLElement;\n inputs: Array;\n selectAllCheckbox: Element;\n searchFilter: Element;\n options: Options;\n target: JQuery;\n\n constructor (target: JQuery, th: HTMLElement, column: number, index: number, options: Options) {\n this.options = options;\n this.th = th;\n this.column = column;\n this.index = index;\n this.tds = target.find('tbody tr td:nth-child(' + (this.column + 1) + ')').toArray();\n }\n\n public initialize(): void {\n this.menu = this.dropdownFilterDropdown();\n this.th.appendChild(this.menu);\n\n // variables for click handlers\n let $trigger = $(this.menu.children[0]);\n let $content = $(this.menu.children[1]);\n let $menu = $(this.menu);\n\n // toggle hide/show when the trigger is clicked\n $trigger.click(() => $content.toggle());\n\n $(document).click(function(el) {\n // hide the content if the user clicks outside of the menu\n if (!$menu.is(el.target) && $menu.has(el.target).length === 0) {\n $content.hide();\n }\n });\n }\n\n public searchToggle(value: string): void {\n if (this.selectAllCheckbox instanceof HTMLInputElement) this.selectAllCheckbox.checked = false;\n if (value.length === 0){\n this.toggleAll(true);\n if (this.selectAllCheckbox instanceof HTMLInputElement) this.selectAllCheckbox.checked = true;\n return;\n }\n // deselect all checkboxes initially\n this.toggleAll(false);\n // select checkboxes that match the search parameter\n this.inputs.filter(function(input: HTMLInputElement) {\n return input.value.toLowerCase().indexOf(value.toLowerCase()) > -1;\n }).forEach(function(input: HTMLInputElement) {\n input.checked = true;\n });\n }\n\n\n public updateSelectAll(): void {\n if (this.selectAllCheckbox instanceof HTMLInputElement) {\n // clear search parameters, if any\n $(this.searchFilter).val('');\n // Check if all inputs are selected\n this.selectAllCheckbox.checked = (this.inputs.length === this.inputs.filter(function(input: HTMLInputElement) {\n return input.checked;\n }).length);\n }\n }\n\n public selectAllUpdate(checked: boolean): void {\n // clear search parameters, if any\n $(this.searchFilter).val('');\n this.toggleAll(checked);\n }\n\n private toggleAll(checked: boolean): void {\n // loop through all inputs and check or uncheck each\n for (var i=0; i < this.inputs.length; i++) {\n let input = this.inputs[i];\n if (input instanceof HTMLInputElement) input.checked = checked;\n }\n }\n\n private dropdownFilterItem(td: HTMLElement, self: any): HTMLElement {\n // build holder div\n let value = td.innerText;\n let dropdownFilterItem = document.createElement('div');\n dropdownFilterItem.className = 'dropdown-filter-item';\n // build input\n let input = document.createElement('input');\n input.type = 'checkbox';\n input.value = value.trim().replace(/ +(?= )/g,'');\n input.setAttribute('checked','checked');\n input.className = 'dropdown-filter-menu-item item';\n // get index of td element\n input.setAttribute('data-column', self.column.toString());\n input.setAttribute('data-index', self.index.toString());\n // append input to holding div\n dropdownFilterItem.appendChild(input);\n dropdownFilterItem.innerHTML = dropdownFilterItem.innerHTML.trim() + ' ' + value;\n return dropdownFilterItem;\n }\n\n private dropdownFilterItemSelectAll(): HTMLElement {\n // build holder div\n let value = this.options.captions.select_all;\n let dropdownFilterItemSelectAll = document.createElement('div');\n dropdownFilterItemSelectAll.className = 'dropdown-filter-item';\n // build input\n let input = document.createElement('input');\n input.type = 'checkbox';\n input.value = this.options.captions.select_all;\n input.setAttribute('checked','checked');\n input.className = 'dropdown-filter-menu-item select-all';\n input.setAttribute('data-column', this.column.toString());\n input.setAttribute('data-index', this.index.toString());\n // append input to holding div\n dropdownFilterItemSelectAll.appendChild(input);\n dropdownFilterItemSelectAll.innerHTML = dropdownFilterItemSelectAll.innerHTML + ' ' + value;\n return dropdownFilterItemSelectAll;\n }\n\n private dropdownFilterSearch(): HTMLElement {\n // build holder div\n let dropdownFilterItem = document.createElement('div');\n dropdownFilterItem.className = 'dropdown-filter-search';\n // build input\n let input = document.createElement('input');\n input.type = 'text';\n input.className = 'dropdown-filter-menu-search form-control';\n input.setAttribute('data-column', this.column.toString());\n input.setAttribute('data-index', this.index.toString());\n input.setAttribute('placeholder', this.options.captions.search);\n // append input to holding div\n dropdownFilterItem.appendChild(input);\n return dropdownFilterItem;\n }\n\n private dropdownFilterSort(direction: string): HTMLElement {\n // build holder div\n let dropdownFilterItem = document.createElement('div');\n dropdownFilterItem.className = 'dropdown-filter-sort';\n // build span\n let span = document.createElement('span');\n span.className = direction.toLowerCase().split(' ').join('-');\n span.setAttribute('data-column', this.column.toString());\n span.setAttribute('data-index', this.index.toString());\n span.innerText = direction;\n // append input to holding div\n dropdownFilterItem.appendChild(span);\n return dropdownFilterItem;\n }\n\n private dropdownFilterContent(): HTMLElement {\n let self = this;\n // build holder div\n let dropdownFilterContent = document.createElement('div');\n dropdownFilterContent.className = 'dropdown-filter-content';\n\n let innerDivs = this.tds.reduce(function(arr, el) {\n // get unique values in column\n let values = arr.map((el) => el.innerText.trim());\n if (values.indexOf(el.innerText.trim()) < 0) arr.push(el);\n // return unique values\n return arr;\n }, [])\n .sort(function(a, b) {\n // sort values for display in dropdown\n var A = a.innerText.toLowerCase();\n var B = b.innerText.toLowerCase();\n\n if (!isNaN(Number(A)) && !isNaN(Number(B))) {\n\n // handle numbers\n if(Number(A) < Number(B)) return -1;\n if(Number(A) > Number(B)) return 1;\n\n } else {\n\n // handle strings\n if(A < B) return -1;\n if(A > B) return 1;\n\n }\n //return a.innerText.toLowerCase() > b.innerText.toLowerCase() ? 1 : -1;\n return 0;\n })\n // create dropdown filter items out of each value\n .map( (td) => {\n return this.dropdownFilterItem(td, self);\n })\n\n // map inputs to instance, we will need these later\n this.inputs = innerDivs.map((div) => div.firstElementChild);\n\n // add a select all checkbox\n let selectAllCheckboxDiv = this.dropdownFilterItemSelectAll();\n // map the select all checkbox to the instance, we will need it later\n this.selectAllCheckbox = selectAllCheckboxDiv.firstElementChild;\n // the checkbox will precede the other inputs\n innerDivs.unshift(selectAllCheckboxDiv);\n\n let searchFilterDiv = this.dropdownFilterSearch();\n this.searchFilter = searchFilterDiv.firstElementChild;\n\n // create outer div, and place all inner divs within it\n let outerDiv = innerDivs.reduce(function(outerDiv, innerDiv) {\n outerDiv.appendChild(innerDiv);\n return outerDiv;\n }, document.createElement('div'));\n outerDiv.className = 'checkbox-container';\n\n let elements: Array = [];\n if (this.options.sort ) elements= elements.concat([\n this.dropdownFilterSort(this.options.captions.a_to_z),\n this.dropdownFilterSort(this.options.captions.z_to_a)\n ]);\n if (this.options.search) elements.push(searchFilterDiv);\n\n return elements.concat(outerDiv).reduce(function(html, el) {\n html.appendChild(el);\n return html;\n }, dropdownFilterContent);\n }\n\n private dropdownFilterDropdown(): HTMLElement {\n // build holder div\n let dropdownFilterDropdown = document.createElement('div');\n dropdownFilterDropdown.className = 'dropdown-filter-dropdown';\n let arrow = document.createElement('span');\n arrow.className = 'glyphicon glyphicon-arrow-down dropdown-filter-icon';\n let icon = document.createElement('i');\n icon.className = 'arrow-down';\n arrow.appendChild(icon);\n dropdownFilterDropdown.appendChild(arrow);\n dropdownFilterDropdown.appendChild(this.dropdownFilterContent());\n\n if ($(this.th).hasClass('no-sort')) {\n $(dropdownFilterDropdown).find('.dropdown-filter-sort').remove();\n }\n if ($(this.th).hasClass('no-filter')) {\n $(dropdownFilterDropdown).find('.checkbox-container').remove();\n }\n if ($(this.th).hasClass('no-search')) {\n $(dropdownFilterDropdown).find('.dropdown-filter-search').remove();\n }\n return dropdownFilterDropdown;\n }\n\n}\n","import { FilterMenu } from './FilterMenu'\n\nexport class FilterCollection {\n\n filterMenus: Array;\n rows: Array;\n ths: Array;\n table: HTMLElement;\n options: Options;\n target: JQuery;\n\n constructor (target: JQuery, options: Options) {\n this.target = target;\n this.options = options;\n this.ths = target.find('th' + options.columnSelector).toArray()\n this.filterMenus = this.ths.map(function(th: HTMLElement, index: number) {\n let column = $(th).index();\n return new FilterMenu(target, th, column, index, options);\n });\n this.rows = target.find('tbody').find('tr').toArray();\n this.table = target.get(0);\n }\n\n public initialize(): void {\n this.filterMenus.forEach(function(filterMenu) {\n filterMenu.initialize();\n });\n this.bindCheckboxes();\n this.bindSelectAllCheckboxes();\n this.bindSort();\n this.bindSearch();\n }\n\n private bindCheckboxes(): void {\n let filterMenus = this.filterMenus;\n let rows = this.rows;\n let ths = this.ths;\n let updateRowVisibility = this.updateRowVisibility;\n this.target.find('.dropdown-filter-menu-item.item').change(function() {\n let index = $(this).data('index');\n let value = $(this).val();\n filterMenus[index].updateSelectAll();\n updateRowVisibility(filterMenus, rows, ths);\n });\n }\n\n private bindSelectAllCheckboxes(): void {\n let filterMenus = this.filterMenus;\n let rows = this.rows;\n let ths = this.ths;\n let updateRowVisibility = this.updateRowVisibility;\n this.target.find('.dropdown-filter-menu-item.select-all').change(function() {\n let index = $(this).data('index');\n let value = this.checked;\n filterMenus[index].selectAllUpdate(value);\n updateRowVisibility(filterMenus, rows, ths);\n });\n }\n\n private bindSort(): void {\n let filterMenus = this.filterMenus;\n let rows = this.rows;\n let ths = this.ths;\n let sort = this.sort;\n let table = this.table;\n let options = this.options;\n let updateRowVisibility = this.updateRowVisibility;\n this.target.find('.dropdown-filter-sort').click(function() {\n let $sortElement = $(this).find('span');\n let column = $sortElement.data('column');\n let order = $sortElement.attr('class');\n sort(column, order, table, options);\n updateRowVisibility(filterMenus, rows, ths);\n });\n }\n\n private bindSearch(): void {\n let filterMenus = this.filterMenus;\n let rows = this.rows;\n let ths = this.ths;\n let updateRowVisibility = this.updateRowVisibility;\n this.target.find('.dropdown-filter-search').keyup(function() {\n let $input = $(this).find('input');\n let index = $input.data('index');\n let value = $input.val();\n filterMenus[index].searchToggle(value);\n updateRowVisibility(filterMenus, rows, ths);\n });\n }\n\n private updateRowVisibility(filterMenus: Array, rows: Array, ths: Array): void {\n let showRows = rows;\n let hideRows: Array = [];\n let selectedLists = filterMenus.map(function(filterMenu) {\n return {\n column: filterMenu.column,\n selected: filterMenu.inputs\n .filter(function(input: HTMLInputElement) {\n return input.checked\n }).map(function(input: HTMLInputElement) {\n return input.value.trim().replace(/ +(?= )/g,'');\n })\n };\n });\n for (let i=0; i < rows.length; i++) {\n let tds = rows[i].children;\n for (let j=0; j < selectedLists.length; j++) {\n let content = (tds[selectedLists[j].column] as HTMLElement).innerText.trim().replace(/ +(?= )/g,'')\n if (selectedLists[j].selected.indexOf(content) === -1 ) {\n $(rows[i]).hide();\n break;\n }\n $(rows[i]).show();\n }\n }\n }\n\n private sort(column: number, order: string, table: HTMLElement, options: Options): void {\n let flip = 1;\n if (order === options.captions.z_to_a.toLowerCase().split(' ').join('-')) flip = -1;\n let tbody = $(table).find('tbody').get(0);\n let rows = $(tbody).find('tr').get();\n\n rows.sort(function(a, b) {\n var A = (a.children[column] as HTMLElement).innerText.toUpperCase();\n var B = (b.children[column] as HTMLElement).innerText.toUpperCase();\n\n if (!isNaN(Number(A)) && !isNaN(Number(B))) {\n // handle numbers\n if(Number(A) < Number(B)) return -1*flip;\n if(Number(A) > Number(B)) return 1*flip;\n } else {\n // handle strings\n if(A < B) return -1*flip;\n if(A > B) return 1*flip;\n }\n return 0;\n });\n\n for (var i=0; i < rows.length; i++) {\n tbody.appendChild(rows[i]);\n }\n }\n\n\n}\n","import $ from 'jquery';\nimport { FilterCollection } from './FilterCollection'\n\n// Define the plugin function on the jQuery extension point.\n($.fn as any).excelTableFilter = function (this: JQuery, options: Options) {\n let target = this;\n // Merge the global options with the per-call options.\n options = $.extend({}, ($.fn as any).excelTableFilter.options, options);\n\n if (typeof options.columnSelector === 'undefined') options.columnSelector = '';\n if (typeof options.sort === 'undefined') options.sort = true;\n if (typeof options.search === 'undefined') options.search = true;\n\n if (typeof options.captions === 'undefined') options.captions = {\n a_to_z: 'A to Z',\n z_to_a: 'Z to A',\n search: 'Search',\n select_all: 'Select All'\n }\n\n let filterCollection = new FilterCollection(target, options);\n filterCollection.initialize();\n\n // Return the jQuery object for chaining.\n return target;\n};\n\n// Define the plugin's global default options.\n($.fn as any).excelTableFilter.options = {};\n"]}
--------------------------------------------------------------------------------
/dist/excel-bootstrap-table-filter-style.css:
--------------------------------------------------------------------------------
1 | .dropdown-filter-dropdown {
2 | position:relative;
3 | display:inline-block;
4 | }
5 |
6 | .dropdown-filter-icon {
7 | margin-left:5px;
8 | line-height:1.3;
9 | border:1px solid black;
10 | }
11 |
12 |
13 | .dropdown-filter-icon:hover {
14 | cursor:pointer;
15 | }
16 |
17 | .checkbox-container {
18 | max-height: 400px;
19 | overflow-y: scroll;
20 | }
21 | .dropdown-filter-content {
22 | display: none;
23 | position: absolute;
24 | background-color: #f9f9f9;
25 | min-width: 200px;
26 | box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
27 | z-index: 1;
28 | padding-bottom:5px;
29 | padding-top:5px;
30 | padding-right:5px;
31 | padding-left:5px;
32 | }
33 |
34 | .dropdown-filter-content div {
35 | margin-top:5px;
36 | margin-left:5px;
37 | margin-right:5px;
38 | margin-bottom:5px;
39 | }
40 |
41 | .dropdown-filter-content div.dropdown-filter-search {
42 | margin-bottom:10px;
43 | margin-top:10px;
44 | }
45 |
46 |
47 | .dropdown-filter-content div.dropdown-filter-sort {
48 | padding-top:5px;
49 | padding-bottom:5px;
50 | }
51 |
52 | .dropdown-filter-content div.dropdown-filter-sort:hover {
53 | background-color:#e1e5e7;
54 | cursor:pointer;
55 | }
56 |
57 | .dropdown-filter-content div.dropdown-filter-sort span {
58 | margin-right:5px;
59 | margin-left:5px;
60 | margin-top:5px;
61 | margin-bottom:5px;
62 | color:#000000;
63 | }
64 |
65 | .arrow-down {
66 | border: solid black;
67 | border-width: 0 3px 3px 0;
68 | display: inline-block;
69 | padding: 3px;
70 | margin-right:5px;
71 | margin-left:5px;
72 | transform: rotate(45deg);
73 | -webkit-transform: rotate(45deg);
74 | }
75 |
--------------------------------------------------------------------------------
/excel-table-filter-example.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chestercharles/excel-bootstrap-table-filter/4a88f70bb6857131d6b048cd4ff78da327064532/excel-table-filter-example.PNG
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function (config) {
2 | config.set({
3 | basePath: '',
4 | browsers: ['PhantomJS'],
5 | frameworks: ['jasmine', 'karma-typescript'],
6 | files: [
7 | { pattern: "src/**/*.ts" }
8 | ],
9 | preprocessors: {
10 | '**/*.ts': ['karma-typescript']
11 | },
12 | karmaTypescriptConfig: {
13 | compilerOptions: {
14 | noImplicitAny: true,
15 | noImplicitReturns: true,
16 | noImplicitThis: true,
17 | allowSyntheticDefaultImports: true
18 | }
19 | },
20 | reporters: ['progress', 'karma-typescript'],
21 | port: 9876,
22 | colors: true,
23 | logLevel: config.LOG_INFO,
24 | autoWatch: false,
25 | singleRun: true,
26 | concurrency: Infinity
27 | })
28 | }
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "excel-bootstrap-table-filter",
3 | "version": "1.0.0",
4 | "description": "jQuery plugin to generate a checkbox drop-down table-filter",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/chetsercharles/excel-bootstrap-table-filter"
8 | },
9 | "scripts": {
10 | "clean": "rimraf dist && rimraf coverage",
11 | "build": "npm run compile && npm run copy:html && npm run bundle && npm run minify",
12 | "compile": "tsc",
13 | "copy:html": "cpx 'src/**.{html,css}' dist",
14 | "test": "karma start",
15 | "bundle": "rollup -c",
16 | "minify": "uglifyjs dist/excel-bootstrap-table-filter-bundle.js --output dist/excel-bootstrap-table-filter-bundle.min.js --source-map dist/excel-bootstrap-table-filter-bundle.min.js.map --source-map-url excel-bootstrap-table-filter-bundle.min.js.map --in-source-map dist/excel-bootstrap-table-filter-bundle.js.map"
17 | },
18 | "author": {
19 | "name": "Chester Carmer",
20 | "email": "chestercarmer@icloud.com"
21 | },
22 | "license": "MIT",
23 | "dependencies": {
24 | "jquery": "~3.1.1"
25 | },
26 | "devDependencies": {
27 | "@types/jasmine": "~2.5.43",
28 | "@types/jquery": "~2.0.40",
29 | "babel-plugin-external-helpers": "~6.22.0",
30 | "babel-preset-es2015": "~6.22.0",
31 | "cpx": "^1.5.0",
32 | "jasmine-core": "~2.5.2",
33 | "karma": "~1.5.0",
34 | "karma-jasmine": "~1.1.0",
35 | "karma-phantomjs-launcher": "~1.0.2",
36 | "karma-typescript": "~2.1.7",
37 | "rimraf": "~2.6.1",
38 | "rollup": "~0.41.4",
39 | "rollup-plugin-babel": "~2.7.1",
40 | "rollup-plugin-sourcemaps": "~0.4.1",
41 | "typescript": "~2.1.6",
42 | "uglify-js": "~2.7.5"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import sourcemaps from 'rollup-plugin-sourcemaps';
3 |
4 | export default {
5 | entry: 'dist/excel-bootstrap-table-filter.js',
6 | dest: 'dist/excel-bootstrap-table-filter-bundle.js',
7 | format: 'iife',
8 | external: [
9 | 'jquery'
10 | ],
11 | globals: {
12 | jquery: 'jQuery'
13 | },
14 | sourceMap: true,
15 | plugins: [
16 | babel({
17 | exclude: 'node_modules/**',
18 | }),
19 | sourcemaps()
20 | ]
21 | };
22 |
--------------------------------------------------------------------------------
/src/FilterCollection.ts:
--------------------------------------------------------------------------------
1 | import { FilterMenu } from './FilterMenu'
2 |
3 | export class FilterCollection {
4 |
5 | filterMenus: Array;
6 | rows: Array;
7 | ths: Array;
8 | table: HTMLElement;
9 | options: Options;
10 | target: JQuery;
11 |
12 | constructor (target: JQuery, options: Options) {
13 | this.target = target;
14 | this.options = options;
15 | this.ths = target.find('th' + options.columnSelector).toArray()
16 | this.filterMenus = this.ths.map(function(th: HTMLElement, index: number) {
17 | let column = $(th).index();
18 | return new FilterMenu(target, th, column, index, options);
19 | });
20 | this.rows = target.find('tbody').find('tr').toArray();
21 | this.table = target.get(0);
22 | }
23 |
24 | public initialize(): void {
25 | this.filterMenus.forEach(function(filterMenu) {
26 | filterMenu.initialize();
27 | });
28 | this.bindCheckboxes();
29 | this.bindSelectAllCheckboxes();
30 | this.bindSort();
31 | this.bindSearch();
32 | }
33 |
34 | private bindCheckboxes(): void {
35 | let filterMenus = this.filterMenus;
36 | let rows = this.rows;
37 | let ths = this.ths;
38 | let updateRowVisibility = this.updateRowVisibility;
39 | this.target.find('.dropdown-filter-menu-item.item').change(function() {
40 | let index = $(this).data('index');
41 | let value = $(this).val();
42 | filterMenus[index].updateSelectAll();
43 | updateRowVisibility(filterMenus, rows, ths);
44 | });
45 | }
46 |
47 | private bindSelectAllCheckboxes(): void {
48 | let filterMenus = this.filterMenus;
49 | let rows = this.rows;
50 | let ths = this.ths;
51 | let updateRowVisibility = this.updateRowVisibility;
52 | this.target.find('.dropdown-filter-menu-item.select-all').change(function() {
53 | let index = $(this).data('index');
54 | let value = this.checked;
55 | filterMenus[index].selectAllUpdate(value);
56 | updateRowVisibility(filterMenus, rows, ths);
57 | });
58 | }
59 |
60 | private bindSort(): void {
61 | let filterMenus = this.filterMenus;
62 | let rows = this.rows;
63 | let ths = this.ths;
64 | let sort = this.sort;
65 | let table = this.table;
66 | let options = this.options;
67 | let updateRowVisibility = this.updateRowVisibility;
68 | this.target.find('.dropdown-filter-sort').click(function() {
69 | let $sortElement = $(this).find('span');
70 | let column = $sortElement.data('column');
71 | let order = $sortElement.attr('class');
72 | sort(column, order, table, options);
73 | updateRowVisibility(filterMenus, rows, ths);
74 | });
75 | }
76 |
77 | private bindSearch(): void {
78 | let filterMenus = this.filterMenus;
79 | let rows = this.rows;
80 | let ths = this.ths;
81 | let updateRowVisibility = this.updateRowVisibility;
82 | this.target.find('.dropdown-filter-search').keyup(function() {
83 | let $input = $(this).find('input');
84 | let index = $input.data('index');
85 | let value = $input.val();
86 | filterMenus[index].searchToggle(value);
87 | updateRowVisibility(filterMenus, rows, ths);
88 | });
89 | }
90 |
91 | private updateRowVisibility(filterMenus: Array, rows: Array, ths: Array): void {
92 | let showRows = rows;
93 | let hideRows: Array = [];
94 | let selectedLists = filterMenus.map(function(filterMenu) {
95 | return {
96 | column: filterMenu.column,
97 | selected: filterMenu.inputs
98 | .filter(function(input: HTMLInputElement) {
99 | return input.checked
100 | }).map(function(input: HTMLInputElement) {
101 | return input.value.trim().replace(/ +(?= )/g,'');
102 | })
103 | };
104 | });
105 | for (let i=0; i < rows.length; i++) {
106 | let tds = rows[i].children;
107 | for (let j=0; j < selectedLists.length; j++) {
108 | let content = (tds[selectedLists[j].column] as HTMLElement).innerText.trim().replace(/ +(?= )/g,'')
109 | if (selectedLists[j].selected.indexOf(content) === -1 ) {
110 | $(rows[i]).hide();
111 | break;
112 | }
113 | $(rows[i]).show();
114 | }
115 | }
116 | }
117 |
118 | private sort(column: number, order: string, table: HTMLElement, options: Options): void {
119 | let flip = 1;
120 | if (order === options.captions.z_to_a.toLowerCase().split(' ').join('-')) flip = -1;
121 | let tbody = $(table).find('tbody').get(0);
122 | let rows = $(tbody).find('tr').get();
123 |
124 | rows.sort(function(a, b) {
125 | var A = (a.children[column] as HTMLElement).innerText.toUpperCase();
126 | var B = (b.children[column] as HTMLElement).innerText.toUpperCase();
127 |
128 | if (!isNaN(Number(A)) && !isNaN(Number(B))) {
129 | // handle numbers
130 | if(Number(A) < Number(B)) return -1*flip;
131 | if(Number(A) > Number(B)) return 1*flip;
132 | } else {
133 | // handle strings
134 | if(A < B) return -1*flip;
135 | if(A > B) return 1*flip;
136 | }
137 | return 0;
138 | });
139 |
140 | for (var i=0; i < rows.length; i++) {
141 | tbody.appendChild(rows[i]);
142 | }
143 | }
144 |
145 |
146 | }
147 |
--------------------------------------------------------------------------------
/src/FilterMenu.ts:
--------------------------------------------------------------------------------
1 | export class FilterMenu {
2 |
3 | th: HTMLElement;
4 | tds: Array;
5 | column: number;
6 | index: number;
7 | menu: HTMLElement;
8 | inputs: Array;
9 | selectAllCheckbox: Element;
10 | searchFilter: Element;
11 | options: Options;
12 | target: JQuery;
13 |
14 | constructor (target: JQuery, th: HTMLElement, column: number, index: number, options: Options) {
15 | this.options = options;
16 | this.th = th;
17 | this.column = column;
18 | this.index = index;
19 | this.tds = target.find('tbody tr td:nth-child(' + (this.column + 1) + ')').toArray();
20 | }
21 |
22 | public initialize(): void {
23 | this.menu = this.dropdownFilterDropdown();
24 | this.th.appendChild(this.menu);
25 |
26 | // variables for click handlers
27 | let $trigger = $(this.menu.children[0]);
28 | let $content = $(this.menu.children[1]);
29 | let $menu = $(this.menu);
30 |
31 | // toggle hide/show when the trigger is clicked
32 | $trigger.click(() => $content.toggle());
33 |
34 | $(document).click(function(el) {
35 | // hide the content if the user clicks outside of the menu
36 | if (!$menu.is(el.target) && $menu.has(el.target).length === 0) {
37 | $content.hide();
38 | }
39 | });
40 | }
41 |
42 | public searchToggle(value: string): void {
43 | if (this.selectAllCheckbox instanceof HTMLInputElement) this.selectAllCheckbox.checked = false;
44 | if (value.length === 0){
45 | this.toggleAll(true);
46 | if (this.selectAllCheckbox instanceof HTMLInputElement) this.selectAllCheckbox.checked = true;
47 | return;
48 | }
49 | // deselect all checkboxes initially
50 | this.toggleAll(false);
51 | // select checkboxes that match the search parameter
52 | this.inputs.filter(function(input: HTMLInputElement) {
53 | return input.value.toLowerCase().indexOf(value.toLowerCase()) > -1;
54 | }).forEach(function(input: HTMLInputElement) {
55 | input.checked = true;
56 | });
57 | }
58 |
59 |
60 | public updateSelectAll(): void {
61 | if (this.selectAllCheckbox instanceof HTMLInputElement) {
62 | // clear search parameters, if any
63 | $(this.searchFilter).val('');
64 | // Check if all inputs are selected
65 | this.selectAllCheckbox.checked = (this.inputs.length === this.inputs.filter(function(input: HTMLInputElement) {
66 | return input.checked;
67 | }).length);
68 | }
69 | }
70 |
71 | public selectAllUpdate(checked: boolean): void {
72 | // clear search parameters, if any
73 | $(this.searchFilter).val('');
74 | this.toggleAll(checked);
75 | }
76 |
77 | private toggleAll(checked: boolean): void {
78 | // loop through all inputs and check or uncheck each
79 | for (var i=0; i < this.inputs.length; i++) {
80 | let input = this.inputs[i];
81 | if (input instanceof HTMLInputElement) input.checked = checked;
82 | }
83 | }
84 |
85 | private dropdownFilterItem(td: HTMLElement, self: any): HTMLElement {
86 | // build holder div
87 | let value = td.innerText;
88 | let dropdownFilterItem = document.createElement('div');
89 | dropdownFilterItem.className = 'dropdown-filter-item';
90 | // build input
91 | let input = document.createElement('input');
92 | input.type = 'checkbox';
93 | input.value = value.trim().replace(/ +(?= )/g,'');
94 | input.setAttribute('checked','checked');
95 | input.className = 'dropdown-filter-menu-item item';
96 | // get index of td element
97 | input.setAttribute('data-column', self.column.toString());
98 | input.setAttribute('data-index', self.index.toString());
99 | // append input to holding div
100 | dropdownFilterItem.appendChild(input);
101 | dropdownFilterItem.innerHTML = dropdownFilterItem.innerHTML.trim() + ' ' + value;
102 | return dropdownFilterItem;
103 | }
104 |
105 | private dropdownFilterItemSelectAll(): HTMLElement {
106 | // build holder div
107 | let value = this.options.captions.select_all;
108 | let dropdownFilterItemSelectAll = document.createElement('div');
109 | dropdownFilterItemSelectAll.className = 'dropdown-filter-item';
110 | // build input
111 | let input = document.createElement('input');
112 | input.type = 'checkbox';
113 | input.value = this.options.captions.select_all;
114 | input.setAttribute('checked','checked');
115 | input.className = 'dropdown-filter-menu-item select-all';
116 | input.setAttribute('data-column', this.column.toString());
117 | input.setAttribute('data-index', this.index.toString());
118 | // append input to holding div
119 | dropdownFilterItemSelectAll.appendChild(input);
120 | dropdownFilterItemSelectAll.innerHTML = dropdownFilterItemSelectAll.innerHTML + ' ' + value;
121 | return dropdownFilterItemSelectAll;
122 | }
123 |
124 | private dropdownFilterSearch(): HTMLElement {
125 | // build holder div
126 | let dropdownFilterItem = document.createElement('div');
127 | dropdownFilterItem.className = 'dropdown-filter-search';
128 | // build input
129 | let input = document.createElement('input');
130 | input.type = 'text';
131 | input.className = 'dropdown-filter-menu-search form-control';
132 | input.setAttribute('data-column', this.column.toString());
133 | input.setAttribute('data-index', this.index.toString());
134 | input.setAttribute('placeholder', this.options.captions.search);
135 | // append input to holding div
136 | dropdownFilterItem.appendChild(input);
137 | return dropdownFilterItem;
138 | }
139 |
140 | private dropdownFilterSort(direction: string): HTMLElement {
141 | // build holder div
142 | let dropdownFilterItem = document.createElement('div');
143 | dropdownFilterItem.className = 'dropdown-filter-sort';
144 | // build span
145 | let span = document.createElement('span');
146 | span.className = direction.toLowerCase().split(' ').join('-');
147 | span.setAttribute('data-column', this.column.toString());
148 | span.setAttribute('data-index', this.index.toString());
149 | span.innerText = direction;
150 | // append input to holding div
151 | dropdownFilterItem.appendChild(span);
152 | return dropdownFilterItem;
153 | }
154 |
155 | private dropdownFilterContent(): HTMLElement {
156 | let self = this;
157 | // build holder div
158 | let dropdownFilterContent = document.createElement('div');
159 | dropdownFilterContent.className = 'dropdown-filter-content';
160 |
161 | let innerDivs = this.tds.reduce(function(arr, el) {
162 | // get unique values in column
163 | let values = arr.map((el) => el.innerText.trim());
164 | if (values.indexOf(el.innerText.trim()) < 0) arr.push(el);
165 | // return unique values
166 | return arr;
167 | }, [])
168 | .sort(function(a, b) {
169 | // sort values for display in dropdown
170 | var A = a.innerText.toLowerCase();
171 | var B = b.innerText.toLowerCase();
172 |
173 | if (!isNaN(Number(A)) && !isNaN(Number(B))) {
174 |
175 | // handle numbers
176 | if(Number(A) < Number(B)) return -1;
177 | if(Number(A) > Number(B)) return 1;
178 |
179 | } else {
180 |
181 | // handle strings
182 | if(A < B) return -1;
183 | if(A > B) return 1;
184 |
185 | }
186 | //return a.innerText.toLowerCase() > b.innerText.toLowerCase() ? 1 : -1;
187 | return 0;
188 | })
189 | // create dropdown filter items out of each value
190 | .map( (td) => {
191 | return this.dropdownFilterItem(td, self);
192 | })
193 |
194 | // map inputs to instance, we will need these later
195 | this.inputs = innerDivs.map((div) => div.firstElementChild);
196 |
197 | // add a select all checkbox
198 | let selectAllCheckboxDiv = this.dropdownFilterItemSelectAll();
199 | // map the select all checkbox to the instance, we will need it later
200 | this.selectAllCheckbox = selectAllCheckboxDiv.firstElementChild;
201 | // the checkbox will precede the other inputs
202 | innerDivs.unshift(selectAllCheckboxDiv);
203 |
204 | let searchFilterDiv = this.dropdownFilterSearch();
205 | this.searchFilter = searchFilterDiv.firstElementChild;
206 |
207 | // create outer div, and place all inner divs within it
208 | let outerDiv = innerDivs.reduce(function(outerDiv, innerDiv) {
209 | outerDiv.appendChild(innerDiv);
210 | return outerDiv;
211 | }, document.createElement('div'));
212 | outerDiv.className = 'checkbox-container';
213 |
214 | let elements: Array = [];
215 | if (this.options.sort ) elements= elements.concat([
216 | this.dropdownFilterSort(this.options.captions.a_to_z),
217 | this.dropdownFilterSort(this.options.captions.z_to_a)
218 | ]);
219 | if (this.options.search) elements.push(searchFilterDiv);
220 |
221 | return elements.concat(outerDiv).reduce(function(html, el) {
222 | html.appendChild(el);
223 | return html;
224 | }, dropdownFilterContent);
225 | }
226 |
227 | private dropdownFilterDropdown(): HTMLElement {
228 | // build holder div
229 | let dropdownFilterDropdown = document.createElement('div');
230 | dropdownFilterDropdown.className = 'dropdown-filter-dropdown';
231 | let arrow = document.createElement('span');
232 | arrow.className = 'glyphicon glyphicon-arrow-down dropdown-filter-icon';
233 | let icon = document.createElement('i');
234 | icon.className = 'arrow-down';
235 | arrow.appendChild(icon);
236 | dropdownFilterDropdown.appendChild(arrow);
237 | dropdownFilterDropdown.appendChild(this.dropdownFilterContent());
238 |
239 | if ($(this.th).hasClass('no-sort')) {
240 | $(dropdownFilterDropdown).find('.dropdown-filter-sort').remove();
241 | }
242 | if ($(this.th).hasClass('no-filter')) {
243 | $(dropdownFilterDropdown).find('.checkbox-container').remove();
244 | }
245 | if ($(this.th).hasClass('no-search')) {
246 | $(dropdownFilterDropdown).find('.dropdown-filter-search').remove();
247 | }
248 | return dropdownFilterDropdown;
249 | }
250 |
251 | }
252 |
--------------------------------------------------------------------------------
/src/MenuItem.interface.ts:
--------------------------------------------------------------------------------
1 | interface MenuItem {
2 | column: number;
3 | row: number;
4 | value: string;
5 | selected: boolean;
6 | }
7 |
--------------------------------------------------------------------------------
/src/Options.interface.ts:
--------------------------------------------------------------------------------
1 | /** Plugin Options */
2 | interface Options {
3 | columnSelector: string,
4 | sort: boolean,
5 | search: boolean,
6 | captions: {
7 | a_to_z: string,
8 | z_to_a: string,
9 | search: string,
10 | select_all: string
11 | }
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/src/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Excel Bootstrap Table Filter
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |