!function($) { 'use strict'; // TOOLS DEFINITION // ====================== var rowLabel = function(el) { return typeof el === 'object' ? el.label : el; }; var rowId = function(el) { return typeof el === 'object' ? el.id : el; }; var getOptionData = function($option) { var val = false; var name; var data = {}, cnt = 0; var $chck = $option.find('.filter-enabled'); $(':input', $option).each(function() { var $this = $(this); if ($this.is($chck)) { return; } name = $this.attr('data-name'); if (name) { data[name] = $this.val(); } val = $this.val(); cnt++; }); return $.isEmptyObject(data) ? val : data; }; // FILTER CLASS DEFINITION // ====================== var BootstrapTableFilter = function(el, options) { this.options = options; this.$el = $(el); this.$el_ = this.$el.clone(); this.timeoutId_ = 0; this.filters = {}; this.init(); }; BootstrapTableFilter.DEFAULTS = { filters: [], connectTo: false, onAll: function(name, args) { return false; }, onFilterChanged: function(data) { return false; }, onResetView: function() { return false; }, onAddFilter: function(filter) { return false; }, onRemoveFilter: function(field) { return false; }, onEnableFilter: function(field) { return false; }, onDisableFilter: function(field) { return false; }, onSelectFilterOption: function(field, option, data) { return false; }, onUnselectFilterOption: function(field, option) { return false; }, onDataChanged: function(data) { return false; }, onSubmit: function(data) { return false; }, }; BootstrapTableFilter.EVENTS = { 'all.bs.table.filter': 'onAll', 'reset.bs.table.filter': 'onResetView', 'add-filter.bs.table.filter': 'onAddFilter', 'remove-filter.bs.table.filter': 'onRemoveFilter', 'enable-filter.bs.table.filter': 'onEnableFilter', 'disable-filter.bs.table.filter': 'onDisableFilter', 'select-filter-option.bs.table.filter': 'onSelectFilterOption', 'unselect-filter-option.bs.table.filter': 'onUnselectFilterOption', 'data-changed.bs.table.filter': 'onDataChanged', 'submit.bs.table.filter': 'onSubmit' }; BootstrapTableFilter.FILTER_SOURCES = { range: { search: false, rows: [ {id: 'lte', label: 'Less than '}, {id: 'gte', label: 'More than '}, {id: 'eq', label: 'Equals '} ], check: function(filterData, value) { if (typeof filterData.lte !== 'undefined' && parseInt(value) > parseInt(filterData.lte)) { return false; } if (typeof filterData.gte !== 'undefined' && parseInt(value) < parseInt(filterData.gte)) { return false; } if (typeof filterData.eq !== 'undefined' && parseInt(value) != parseInt(filterData.eq)) { return false; } return true; } }, ajaxSelect: { search: true, rows: [], rowsCallback: function(filter, searchPhrase) { var that = this; $.ajax(filter.source, {dataType: 'json', data: {q: searchPhrase}}) .done(function(data) { that.clearFilterOptions(filter.field); that.fillFilterOptions(filter.field, data); }); } }, select: { search: true, rows: [], rowsCallback: function(filter, searchPhrase) { var vals = filter.values; var label; if (searchPhrase.length) { vals = vals.filter(function(el) { return rowLabel(el).indexOf(searchPhrase) > -1 }); } this.clearFilterOptions(filter.field); this.fillFilterOptions(filter.field, vals.slice(0, 20)); } } }; BootstrapTableFilter.EXTERNALS = []; BootstrapTableFilter.prototype.init = function() { this.initContainer(); this.initMainButton(); this.initFilters(); this.initRefreshButton(); this.initFilterSelector(); this.initExternals(); }; BootstrapTableFilter.prototype.initContainer = function() { var that = this; this.$toolbar = $([ '
', '
', '', '', '
', '
', '
', '
', '', '
', '
' ].join('')); this.$toolbar.appendTo(this.$el); this.$filters = this.$toolbar.find('.btn-group-filters'); this.$toolbar.delegate('.btn-group-filters li', 'click', function (e) { e.stopImmediatePropagation(); }); this.$toolbar.delegate('.btn-group-filters li .filter-enabled', 'click', function(e) { var $chck = $(this); var field = $chck.closest('[data-filter-field]').attr('data-filter-field'); var $option = $chck.closest('[data-val]'); var option = $option.attr('data-val'); if ($chck.prop('checked')) { var data = getOptionData($option); that.selectFilterOption(field, option, data); } else { that.unselectFilterOption(field, option); } e.stopImmediatePropagation(); }); this.$toolbar.delegate('.btn-group-filters li :input:not(.filter-enabled)', 'click change', function(e) { var $inp = $(this); var field = $inp.closest('[data-filter-field]').attr('data-filter-field'); var $option = $inp.closest('[data-val]'); var option = $option.attr('data-val'); var $chck = $option.find('.filter-enabled'); if ($inp.val()) { var data = getOptionData($option); that.selectFilterOption(field, option, data); $chck.prop('checked', true); } else { that.unselectFilterOption(field, option); $chck.prop('checked', false); } e.stopImmediatePropagation(); }); this.$toolbar.delegate('.search-values', 'keyup', function(e) { var $this = $(this); var phrase = $this.val(); var field = $this.closest('[data-filter-field]').attr('data-filter-field'); var filter = that.getFilter(field); var fType = that.getFilterType(filter); if (fType.rowsCallback) { fType.rowsCallback.call(that, filter, phrase); } }); }; BootstrapTableFilter.prototype.initMainButton = function() { this.$button = this.$toolbar.find('.btn-filter'); this.$buttonList = this.$button.parent().find('.dropdown-menu'); this.$button.dropdown(); }; BootstrapTableFilter.prototype.initRefreshButton = function() { var that = this; this.$refreshButton = this.$toolbar.find('.btn-refresh'); this.$refreshButton.click(function(e) { that.trigger('submit', that.getData()); }); }; BootstrapTableFilter.prototype.initFilters = function() { var that = this; this.$buttonList.append('
  • Remove all filters
  • '); this.$buttonList.append('
  • '); $.each(this.options.filters, function(i, filter) { that.addFilter(filter); }); this.$toolbar.delegate('.remove-filters *', 'click', function() { $.each(that.filters, function(i, filter) { that.disableFilter(filter.field) }); }); }; BootstrapTableFilter.prototype.initFilterSelector = function() { var that = this; var applyFilter = function($chck) { var filterField = $chck.closest('[data-filter-field]').attr('data-filter-field'); if ($chck.prop('checked')) { that.enableFilter(filterField); } else { that.disableFilter(filterField); } }; this.$buttonList.delegate('li :input[type=checkbox]', 'click', function(e) { applyFilter($(this)); e.stopImmediatePropagation(); }); this.$buttonList.delegate('li, li a', 'click', function(e) { var $chck = $(':input[type=checkbox]', this); if ($chck.length) { $chck.prop('checked', !$chck.is(':checked')); applyFilter($chck); e.stopImmediatePropagation(); } var $inp = $(':input[type=text]', this); if ($inp.length) { $inp.focus(); } }); }; BootstrapTableFilter.prototype.initExternals = function() { var that = this; $.each(BootstrapTableFilter.EXTERNALS, function(i, ext) { ext.call(that); }); } BootstrapTableFilter.prototype.getFilter = function(field) { if (typeof this.filters[field] === 'undefined') { throw 'Invalid filter ' + field; } return this.filters[field]; }; BootstrapTableFilter.prototype.getFilterType = function(field, type) { if (field) { var filter = typeof field === 'object' ? field : this.getFilter(field); type = filter.type; } if (typeof BootstrapTableFilter.FILTER_SOURCES[type] === 'undefined') { throw 'Invalid filter type ' + type; } var ret = BootstrapTableFilter.FILTER_SOURCES[type]; if (typeof ret.extend !== 'undefined') { ret = $.extend({}, ret, this.getFilterType(null, ret.extend)); } return ret; }; BootstrapTableFilter.prototype.checkFilterTypeValue = function(filterType, filterData, value) { if (typeof filterType.check === 'function') { return filterType.check(filterData, value); } else { if (typeof filterData._values !== 'undefined') { return $.inArray(value, filterData._values) >= 0; } } }; BootstrapTableFilter.prototype.clearFilterOptions = function(field) { var filter = this.getFilter(field); filter.$dropdownList.find('li:not(.static)').remove(); }; BootstrapTableFilter.prototype.fillFilterOptions = function(field, data, cls) { var that = this; var filter = this.getFilter(field); cls = cls || ''; var option, checked; $.each(data, function(i, row) { option = rowId(row); checked = that.isSelected(field, option); filter.$dropdownList.append($('
  • ' + rowLabel(row) + '
  • ')); }); }; BootstrapTableFilter.prototype.trigger = function(name) { var args = Array.prototype.slice.call(arguments, 1); name += '.bs.table.filter'; if (typeof BootstrapTableFilter.EVENTS[name] === 'undefined') { throw 'Unknown event ' + name; } this.options[BootstrapTableFilter.EVENTS[name]].apply(this.options, args); this.$el.trigger($.Event(name), args); this.options.onAll(name, args); this.$el.trigger($.Event('all.bs.table.filter'), [name, args]); }; // PUBLIC FUNCTION DEFINITION // ======================= BootstrapTableFilter.prototype.resetView = function() { this.$el.html(); this.init(); this.trigger('reset'); }; BootstrapTableFilter.prototype.addFilter = function(filter) { this.filters[filter.field] = filter; this.$buttonList.append('
  • ' + filter.label + '
  • '); this.trigger('add-filter', filter); if (typeof filter.enabled !== 'undefined' && filter.enabled) { this.enableFilter(filter.field); } }; BootstrapTableFilter.prototype.removeFilter = function(field) { this.disableFilter(field); this.$buttonList.find('[data-filter-field=' + field + ']').remove(); this.trigger('remove-filter', field); }; BootstrapTableFilter.prototype.enableFilter = function(field) { var filter = this.getFilter(field); var $filterDropdown = $([ '
    ', '', '', '
    ' ].join('')); $filterDropdown.appendTo(this.$filters); filter.$dropdown = $filterDropdown; filter.$dropdownList = $filterDropdown.find('.dropdown-menu'); filter.enabled = true; this.$buttonList.find('[data-filter-field=' + field + '] input[type=checkbox]').prop('checked', true); var fType = this.getFilterType(filter); if (fType.search) { filter.$dropdownList.append($('
  • ')); filter.$dropdownList.append($('
  • ')); } if (fType.rows) { this.fillFilterOptions(field, fType.rows, 'static'); } if (fType.rowsCallback) { fType.rowsCallback.call(this, filter, ''); } this.trigger('enable-filter', filter); }; BootstrapTableFilter.prototype.disableFilter = function(field) { var filter = this.getFilter(field); this.$buttonList.find('[data-filter-field=' + field + '] input[type=checkbox]').prop('checked', false); filter.enabled = false; if (filter.$dropdown) { filter.$dropdown.remove(); delete filter.$dropdown; this.trigger('disable-filter', filter); } }; BootstrapTableFilter.prototype.selectFilterOption = function(field, option, data) { var filter = this.getFilter(field); if (typeof filter.selectedOptions === 'undefined') filter.selectedOptions = {}; if (data) { filter.selectedOptions[option] = data; } else { if (typeof filter.selectedOptions._values === 'undefined') { filter.selectedOptions._values = []; } filter.selectedOptions._values.push(option); } this.trigger('select-filter-option', field, option, data); }; BootstrapTableFilter.prototype.unselectFilterOption = function(field, option) { var filter = this.getFilter(field); if (typeof filter.selectedOptions !== 'undefined' && typeof filter.selectedOptions[option] !== 'undefined') { delete filter.selectedOptions[option]; } if (typeof filter.selectedOptions !== 'undefined' && typeof filter.selectedOptions._values !== 'undefined') { filter.selectedOptions._values = filter.selectedOptions._values.filter(function(item) { return item != option }); if (filter.selectedOptions._values.length == 0) { delete filter.selectedOptions._values; } if ($.isEmptyObject(filter.selectedOptions)) { delete filter.selectedOptions; } } this.trigger('unselect-filter-option', field, option); }; BootstrapTableFilter.prototype.isSelected = function(field, option, value) { var filter = this.getFilter(field); if (typeof filter.selectedOptions !== 'undefined') { if (typeof filter.selectedOptions[option] !== 'undefined') { if (value ? (filter.selectedOptions[option] == value) : filter.selectedOptions[option]) { return true } } if (typeof filter.selectedOptions._values !== 'undefined') { if (filter.selectedOptions._values.indexOf(option.toString()) > -1) { return true; } } } return false; }; BootstrapTableFilter.prototype.getData = function() { var that = this; var ret = {}; $.each(that.filters, function(field, filter) { if (filter.enabled) { if (typeof filter.selectedOptions !== 'undefined') { ret[field] = filter.selectedOptions; } } }); return ret; }; // BOOTSTRAP FILTER TABLE PLUGIN DEFINITION // ======================= $.fn.bootstrapTableFilter = function(option, _relatedTarget) { BootstrapTableFilter.externals = this.externals; var allowedMethods = [ 'addFilter', 'removeFilter', 'enableFilter', 'disableFilter', 'selectFilterOption', 'unselectFilterOption', 'getData', 'isSelected', 'resetView' ], value; this.each(function() { var $this = $(this), data = $this.data('bootstrap.tableFilter'), options = $.extend( {}, BootstrapTableFilter.DEFAULTS, $this.data(), typeof option === 'object' && option ); if (typeof option === 'string') { if ($.inArray(option, allowedMethods) < 0) { throw "Unknown method: " + option; } if (!data) { return; } value = data[option](_relatedTarget); if (option === 'destroy') { $this.removeData('bootstrap.tableFilter'); } } if (!data) { $this.data('bootstrap.tableFilter', (data = new BootstrapTableFilter(this, options))); } }); return typeof value === 'undefined' ? this : value; }; $.fn.bootstrapTableFilter.Constructor = BootstrapTableFilter; $.fn.bootstrapTableFilter.defaults = BootstrapTableFilter.DEFAULTS; $.fn.bootstrapTableFilter.columnDefaults = BootstrapTableFilter.COLUMN_DEFAULTS; $.fn.bootstrapTableFilter.externals = BootstrapTableFilter.EXTERNALS; // BOOTSTRAP TABLE FILTER INIT // ======================= $(function() { $('[data-toggle="tableFilter"]').bootstrapTableFilter(); }); }(jQuery);