/* * FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome. * @version 3.1.4 * @link http://fooplugins.com * @copyright Steven Usher & Brad Vincent 2015 * @license Released under the GPLv3 license. */ (function(F){ F.Filter = F.Class.extend(/** @lends FooTable.Filter */{ /** * The filter object contains the query to filter by and the columns to apply it to. * @constructs * @extends FooTable.Class * @param {string} name - The name for the filter. * @param {(string|FooTable.Query)} query - The query for the filter. * @param {Array.} columns - The columns to apply the query to. * @param {string} [space="AND"] - How the query treats space chars. * @param {boolean} [connectors=true] - Whether or not to replace phrase connectors (+.-_) with spaces. * @param {boolean} [ignoreCase=true] - Whether or not ignore case when matching. * @param {boolean} [hidden=true] - Whether or not this is a hidden filter. * @returns {FooTable.Filter} */ construct: function(name, query, columns, space, connectors, ignoreCase, hidden){ /** * The name of the filter. * @instance * @type {string} */ this.name = name; /** * A string specifying how the filter treats space characters. Can be either "OR" or "AND". * @instance * @type {string} */ this.space = F.is.string(space) && (space == 'OR' || space == 'AND') ? space : 'AND'; /** * Whether or not to replace phrase connectors (+.-_) with spaces before executing the query. * @instance * @type {boolean} */ this.connectors = F.is.boolean(connectors) ? connectors : true; /** * Whether or not ignore case when matching. * @instance * @type {boolean} */ this.ignoreCase = F.is.boolean(ignoreCase) ? ignoreCase : true; /** * Whether or not this is a hidden filter. * @instance * @type {boolean} */ this.hidden = F.is.boolean(hidden) ? hidden : false; /** * The query for the filter. * @instance * @type {(string|FooTable.Query)} */ this.query = query instanceof F.Query ? query : new F.Query(query, this.space, this.connectors, this.ignoreCase); /** * The columns to apply the query to. * @instance * @type {Array.} */ this.columns = columns; }, /** * Checks if the current filter matches the supplied string. * If the current query property is a string it will be auto converted to a {@link FooTable.Query} object to perform the match. * @instance * @param {string} str - The string to check. * @returns {boolean} */ match: function(str){ if (!F.is.string(str)) return false; if (F.is.string(this.query)){ this.query = new F.Query(this.query, this.space, this.connectors, this.ignoreCase); } return this.query instanceof F.Query ? this.query.match(str) : false; }, /** * Checks if the current filter matches the supplied {@link FooTable.Row}. * @instance * @param {FooTable.Row} row - The row to check. * @returns {boolean} */ matchRow: function(row){ var self = this, text = F.arr.map(row.cells, function(cell){ return F.arr.contains(self.columns, cell.column) ? cell.filterValue : null; }).join(' '); return self.match(text); } }); })(FooTable); (function ($, F) { F.Filtering = F.Component.extend(/** @lends FooTable.Filtering */{ /** * The filtering component adds a search input and column selector dropdown to the table allowing users to filter the using space delimited queries. * @constructs * @extends FooTable.Component * @param {FooTable.Table} table - The parent {@link FooTable.Table} object for the component. * @returns {FooTable.Filtering} */ construct: function (table) { // call the constructor of the base class this._super(table, table.o.filtering.enabled); /* PUBLIC */ /** * The filters to apply to the current {@link FooTable.Rows#array}. * @instance * @type {Array.} */ this.filters = table.o.filtering.filters; /** * The delay in milliseconds before the query is auto applied after a change. * @instance * @type {number} */ this.delay = table.o.filtering.delay; /** * The minimum number of characters allowed in the search input before it is auto applied. * @instance * @type {number} */ this.min = table.o.filtering.min; /** * Specifies how whitespace in a filter query is handled. * @instance * @type {string} */ this.space = table.o.filtering.space; /** * Whether or not to replace phrase connectors (+.-_) with spaces before executing the query. * @instance * @type {boolean} */ this.connectors = table.o.filtering.connectors; /** * Whether or not ignore case when matching. * @instance * @type {boolean} */ this.ignoreCase = table.o.filtering.ignoreCase; /** * Whether or not search queries are treated as phrases when matching. * @instance * @type {boolean} */ this.exactMatch = table.o.filtering.exactMatch; /** * The placeholder text to display within the search $input. * @instance * @type {string} */ this.placeholder = table.o.filtering.placeholder; /** * The title to display at the top of the search input column select. * @type {string} */ this.dropdownTitle = table.o.filtering.dropdownTitle; /** * The position of the $search input within the filtering rows cell. * @type {string} */ this.position = table.o.filtering.position; /** * The jQuery row object that contains all the filtering specific elements. * @instance * @type {jQuery} */ this.$row = null; /** * The jQuery cell object that contains the search input and column selector. * @instance * @type {jQuery} */ this.$cell = null; /** * The jQuery object of the column selector dropdown. * @instance * @type {jQuery} */ this.$dropdown = null; /** * The jQuery object of the search input. * @instance * @type {jQuery} */ this.$input = null; /** * The jQuery object of the search button. * @instance * @type {jQuery} */ this.$button = null; /* PRIVATE */ /** * The timeout ID for the filter changed event. * @instance * @private * @type {?number} */ this._filterTimeout = null; /** * The regular expression used to check for encapsulating quotations. * @instance * @private * @type {RegExp} */ this._exactRegExp = /^"(.*?)"$/; }, /* PROTECTED */ /** * Checks the supplied data and options for the filtering component. * @instance * @protected * @param {object} data - The jQuery data object from the parent table. * @fires FooTable.Filtering#"preinit.ft.filtering" */ preinit: function(data){ var self = this; /** * The preinit.ft.filtering event is raised before the UI is created and provides the tables jQuery data object for additional options parsing. * Calling preventDefault on this event will disable the component. * @event FooTable.Filtering#"preinit.ft.filtering" * @param {jQuery.Event} e - The jQuery.Event object for the event. * @param {FooTable.Table} ft - The instance of the plugin raising the event. * @param {object} data - The jQuery data object of the table raising the event. */ return self.ft.raise('preinit.ft.filtering').then(function(){ // first check if filtering is enabled via the class being applied if (self.ft.$el.hasClass('footable-filtering')) self.enabled = true; // then check if the data-filtering-enabled attribute has been set self.enabled = F.is.boolean(data.filtering) ? data.filtering : self.enabled; // if filtering is not enabled exit early as we don't need to do anything else if (!self.enabled) return; self.space = F.is.string(data.filterSpace) ? data.filterSpace : self.space; self.min = F.is.number(data.filterMin) ? data.filterMin : self.min; self.connectors = F.is.boolean(data.filterConnectors) ? data.filterConnectors : self.connectors; self.ignoreCase = F.is.boolean(data.filterIgnoreCase) ? data.filterIgnoreCase : self.ignoreCase; self.exactMatch = F.is.boolean(data.filterExactMatch) ? data.filterExactMatch : self.exactMatch; self.delay = F.is.number(data.filterDelay) ? data.filterDelay : self.delay; self.placeholder = F.is.string(data.filterPlaceholder) ? data.filterPlaceholder : self.placeholder; self.dropdownTitle = F.is.string(data.filterDropdownTitle) ? data.filterDropdownTitle : self.dropdownTitle; self.filters = F.is.array(data.filterFilters) ? self.ensure(data.filterFilters) : self.ensure(self.filters); if (self.ft.$el.hasClass('footable-filtering-left')) self.position = 'left'; if (self.ft.$el.hasClass('footable-filtering-center')) self.position = 'center'; if (self.ft.$el.hasClass('footable-filtering-right')) self.position = 'right'; self.position = F.is.string(data.filterPosition) ? data.filterPosition : self.position; },function(){ self.enabled = false; }); }, /** * Initializes the filtering component for the plugin. * @instance * @protected * @fires FooTable.Filtering#"init.ft.filtering" */ init: function () { var self = this; /** * The init.ft.filtering event is raised before its UI is generated. * Calling preventDefault on this event will disable the component. * @event FooTable.Filtering#"init.ft.filtering" * @param {jQuery.Event} e - The jQuery.Event object for the event. * @param {FooTable.Table} ft - The instance of the plugin raising the event. */ return self.ft.raise('init.ft.filtering').then(function(){ self.$create(); }, function(){ self.enabled = false; }); }, /** * Destroys the filtering component removing any UI from the table. * @instance * @protected * @fires FooTable.Filtering#"destroy.ft.filtering" */ destroy: function () { /** * The destroy.ft.filtering event is raised before its UI is removed. * Calling preventDefault on this event will prevent the component from being destroyed. * @event FooTable.Filtering#"destroy.ft.filtering" * @param {jQuery.Event} e - The jQuery.Event object for the event. * @param {FooTable.Table} ft - The instance of the plugin raising the event. */ var self = this; return self.ft.raise('destroy.ft.filtering').then(function(){ self.ft.$el.removeClass('footable-filtering') .find('thead > tr.footable-filtering').remove(); }); }, /** * Creates the filtering UI from the current options setting the various jQuery properties of this component. * @instance * @protected * @this FooTable.Filtering */ $create: function () { var self = this; // generate the cell that actually contains all the UI. var $form_grp = $('
', {'class': 'form-group footable-filtering-search'}) .append($('