- /**
- * jquery.filterTable
- *
- * This plugin will add a search filter to tables. When typing in the filter,
- * any rows that do not contain the filter will be hidden.
- *
- * Utilizes bindWithDelay() if available. https://github.com/bgrins/bindWithDelay
- *
- * @version v1.5.7
- * @author Sunny Walker, swalker@hawaii.edu
- * @license MIT
- */
- (function ($) {
- var jversion = $.fn.jquery.split('.'),
- jmajor = parseFloat(jversion[0]),
- jminor = parseFloat(jversion[1]);
- // build the pseudo selector for jQuery < 1.8
- if (jmajor < 2 && jminor < 8) {
- // build the case insensitive filtering functionality as a pseudo-selector expression
- $.expr[':'].filterTableFind = function (a, i, m) {
- return $(a).text().toUpperCase().indexOf(m[3].toUpperCase().replace(/"""/g, '"').replace(/"\\"/g, "\\")) >= 0;
- };
- // build the case insensitive all-words filtering functionality as a pseudo-selector expression
- $.expr[':'].filterTableFindAny = function (a, i, m) {
- // build an array of each non-falsey value passed
- var raw_args = m[3].split(/[\s,]/),
- args = [];
- $.each(raw_args, function (j, v) {
- var t = v.replace(/^\s+|\s$/g, '');
- if (t) {
- args.push(t);
- }
- });
- // if there aren't any non-falsey values to search for, abort
- if (!args.length) {
- return false;
- }
- return function (a) {
- var found = false;
- $.each(args, function (j, v) {
- if ($(a).text().toUpperCase().indexOf(v.toUpperCase().replace(/"""/g, '"').replace(/"\\"/g, "\\")) >= 0) {
- found = true;
- return false;
- }
- });
- return found;
- };
- };
- // build the case insensitive all-words filtering functionality as a pseudo-selector expression
- $.expr[':'].filterTableFindAll = function (a, i, m) {
- // build an array of each non-falsey value passed
- var raw_args = m[3].split(/[\s,]/),
- args = [];
- $.each(raw_args, function (j, v) {
- var t = v.replace(/^\s+|\s$/g, '');
- if (t) {
- args.push(t);
- }
- });
- // if there aren't any non-falsey values to search for, abort
- if (!args.length) {
- return false;
- }
- return function (a) {
- // how many terms were found?
- var found = 0;
- $.each(args, function (j, v) {
- if ($(a).text().toUpperCase().indexOf(v.toUpperCase().replace(/"""/g, '"').replace(/"\\"/g, "\\")) >= 0) {
- // found another term
- found++;
- }
- });
- return found === args.length; // did we find all of them in this cell?
- };
- };
- } else {
- // build the pseudo selector for jQuery >= 1.8
- $.expr[':'].filterTableFind = jQuery.expr.createPseudo(function (arg) {
- return function (el) {
- return $(el).text().toUpperCase().indexOf(arg.toUpperCase().replace(/"""/g, '"').replace(/"\\"/g, "\\")) >= 0;
- };
- });
- $.expr[':'].filterTableFindAny = jQuery.expr.createPseudo(function (arg) {
- // build an array of each non-falsey value passed
- var raw_args = arg.split(/[\s,]/),
- args = [];
- $.each(raw_args, function (i, v) {
- // trim the string
- var t = v.replace(/^\s+|\s$/g, '');
- if (t) {
- args.push(t);
- }
- });
- // if there aren't any non-falsey values to search for, abort
- if (!args.length) {
- return false;
- }
- return function (el) {
- var found = false;
- $.each(args, function (i, v) {
- if ($(el).text().toUpperCase().indexOf(v.toUpperCase().replace(/"""/g, '"').replace(/"\\"/g, "\\")) >= 0) {
- found = true;
- // short-circuit the searching since this cell has one of the terms
- return false;
- }
- });
- return found;
- };
- });
- $.expr[':'].filterTableFindAll = jQuery.expr.createPseudo(function (arg) {
- // build an array of each non-falsey value passed
- var raw_args = arg.split(/[\s,]/),
- args = [];
- $.each(raw_args, function (i, v) {
- // trim the string
- var t = v.replace(/^\s+|\s$/g, '');
- if (t) {
- args.push(t);
- }
- });
- // if there aren't any non-falsey values to search for, abort
- if (!args.length) {
- return false;
- }
- return function (el) {
- // how many terms were found?
- var found = 0;
- $.each(args, function (i, v) {
- if ($(el).text().toUpperCase().indexOf(v.toUpperCase().replace(/"""/g, '"').replace(/"\\"/g, "\\")) >= 0) {
- // found another term
- found++;
- }
- });
- // did we find all of them in this cell?
- return found === args.length;
- };
- });
- }
- // define the filterTable plugin
- $.fn.filterTable = function (options) {
- // start off with some default settings
- var defaults = {
- // make the filter input field autofocused (not recommended for accessibility)
- autofocus: false,
-
- // callback function: function (term, table){}
- callback: null,
-
- // class to apply to the container
- containerClass: 'filter-table',
-
- // tag name of the container
- containerTag: 'p',
-
- // jQuery expression method to use for filtering
- filterExpression: 'filterTableFind',
-
- // if true, the table's tfoot(s) will be hidden when the table is filtered
- hideTFootOnFilter: false,
-
- // class applied to cells containing the filter term
- highlightClass: 'alt',
-
- // don't filter the contents of cells with this class
- ignoreClass: '',
-
- // don't filter the contents of these columns
- ignoreColumns: [],
-
- // use the element with this selector for the filter input field instead of creating one
- inputSelector: null,
-
- // name of filter input field
- inputName: '',
-
- // tag name of the filter input tag
- inputType: 'search',
-
- // text to precede the filter input tag
- label: 'Filter:',
-
- // filter only when at least this number of characters are in the filter input field
- minChars: 1,
-
- // don't show the filter on tables with at least this number of rows
- minRows: 8,
-
- // HTML5 placeholder text for the filter field
- placeholder: 'search this table',
-
- // prevent the return key in the filter input field from trigger form submits
- preventReturnKey: true,
-
- // list of phrases to quick fill the search
- quickList: [],
-
- // class of each quick list item
- quickListClass: 'quick',
-
- // quick list item label to clear the filter (e.g., '× Clear filter')
- quickListClear: '',
-
- // tag surrounding quick list items (e.g., ul)
- quickListGroupTag: '',
-
- // tag type of each quick list item (e.g., a or li)
- quickListTag: 'a',
-
- // class applied to visible rows
- visibleClass: 'visible'
- },
- // mimic PHP's htmlspecialchars() function
- hsc = function (text) {
- return text.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
- },
- // merge the user's settings into the defaults
- settings = $.extend({}, defaults, options);
-
- // handle the actual table filtering
- var doFiltering = function (table, q) {
- // cache the tbody element
- var tbody = table.find('tbody');
- // if the filtering query is blank or the number of chars is less than the minChars option
- if (q === '' || q.length < settings.minChars) {
- // show all rows
- tbody.find('tr').show().addClass(settings.visibleClass);
- // remove the row highlight from all cells
- tbody.find('td').removeClass(settings.highlightClass);
- // show footer if the setting was specified
- if (settings.hideTFootOnFilter) {
- table.find('tfoot').show();
- }
- } else {
- // if the filter query is not blank
- var all_tds = tbody.find('td');
- // hide all rows, assuming none were found
- tbody.find('tr').hide().removeClass(settings.visibleClass);
- // remove previous highlights
- all_tds.removeClass(settings.highlightClass);
- // hide footer if the setting was specified
- if (settings.hideTFootOnFilter) {
- table.find('tfoot').hide();
- }
- if (settings.ignoreColumns.length) {
- var tds = [];
- if (settings.ignoreClass) {
- all_tds = all_tds.not('.' + settings.ignoreClass);
- }
- tds = all_tds.filter(':' + settings.filterExpression + '("' + q + '")');
- tds.each(function () {
- var t = $(this),
- col = t.parent().children().index(t);
- if ($.inArray(col, settings.ignoreColumns) === -1) {
- t.addClass(settings.highlightClass).closest('tr').show().addClass(settings.visibleClass);
- }
- });
- } else {
- if (settings.ignoreClass) {
- all_tds = all_tds.not('.' + settings.ignoreClass);
- }
- // highlight (class=alt) only the cells that match the query and show their rows
- all_tds.filter(':' + settings.filterExpression + '("' + q + '")').addClass(settings.highlightClass).closest('tr').show().addClass(settings.visibleClass);
- }
- }
- // call the callback function
- if (settings.callback) {
- settings.callback(q, table);
- }
- }; // doFiltering()
-
- return this.each(function () {
- // cache the table
- var t = $(this),
- // cache the tbody
- tbody = t.find('tbody'),
- // placeholder for the filter field container DOM node
- container = null,
- // placeholder for the quick list items
- quicks = null,
- // placeholder for the field field DOM node
- filter = null,
- // was the filter created or chosen from an existing element?
- created_filter = true;
-
- // only if object is a table and there's a tbody and at least minRows trs and hasn't already had a filter added
- if (t[0].nodeName === 'TABLE' && tbody.length > 0 && (settings.minRows === 0 || (settings.minRows > 0 && tbody.find('tr').length >= settings.minRows)) && !t.prev().hasClass(settings.containerClass)) {
- // use a single existing field as the filter input field
- if (settings.inputSelector && $(settings.inputSelector).length === 1) {
- filter = $(settings.inputSelector);
- // container to hold the quick list options
- container = filter.parent();
- created_filter = false;
- } else {
- // create the filter input field (and container)
- // build the container tag for the filter field
- container = $('<' + settings.containerTag + ' />');
- // add any classes that need to be added
- if (settings.containerClass !== '') {
- container.addClass(settings.containerClass);
- }
- // add the label for the filter field
- container.prepend(settings.label + ' ');
- // build the filter field
- filter = $('<input type="' + settings.inputType + '" placeholder="' + settings.placeholder + '" name="' + settings.inputName + '" />');
- // prevent return in the filter field from submitting any forms
- if (settings.preventReturnKey) {
- filter.on('keydown', function (ev) {
- if ((ev.keyCode || ev.which) === 13) {
- ev.preventDefault();
- return false;
- }
- });
- }
- }
-
- // add the autofocus attribute if requested
- if (settings.autofocus) {
- filter.attr('autofocus', true);
- }
-
- // does bindWithDelay() exist?
- if ($.fn.bindWithDelay) {
- // bind doFiltering() to keyup (delayed)
- filter.bindWithDelay('keyup', function () {
- doFiltering(t, $(this).val());
- }, 200);
- } else {
- // just bind to onKeyUp
- // bind doFiltering() to keyup
- filter.bind('keyup', function () {
- doFiltering(t, $(this).val());
- });
- }
-
- // bind doFiltering() to additional events
- filter.bind('click search input paste blur', function () {
- doFiltering(t, $(this).val());
- });
-
- // add the filter field to the container if it was created by the plugin
- if (created_filter) {
- container.append(filter);
- }
-
- // are there any quick list items to add?
- if (settings.quickList.length > 0 || settings.quickListClear) {
- quicks = settings.quickListGroupTag ? $('<' + settings.quickListGroupTag + ' />') : container;
- // for each quick list item...
- $.each(settings.quickList, function (index, value) {
- // build the quick list item link
- var q = $('<' + settings.quickListTag + ' class="' + settings.quickListClass + '" />');
- // add the item's text
- q.text(hsc(value));
- if (q[0].nodeName === 'A') {
- // add a (worthless) href to the item if it's an anchor tag so that it gets the browser's link treatment
- q.attr('href', '#');
- }
- // bind the click event to it
- q.bind('click', function (e) {
- // stop the normal anchor tag behavior from happening
- e.preventDefault();
- // send the quick list value over to the filter field and trigger the event
- filter.val(value).focus().trigger('click');
- });
- // add the quick list link to the quick list groups container
- quicks.append(q);
- });
-
- // add the quick list clear item if a label has been specified
- if (settings.quickListClear) {
- // build the clear item
- var q = $('<' + settings.quickListTag + ' class="' + settings.quickListClass + '" />');
- // add the label text
- q.html(settings.quickListClear);
- if (q[0].nodeName === 'A') {
- // add a (worthless) href to the item if it's an anchor tag so that it gets the browser's link treatment
- q.attr('href', '#');
- }
- // bind the click event to it
- q.bind('click', function (e) {
- e.preventDefault();
- // clear the quick list value and trigger the event
- filter.val('').focus().trigger('click');
- });
- // add the clear item to the quick list groups container
- quicks.append(q);
- }
-
- // add the quick list groups container to the DOM if it isn't already there
- if (quicks !== container) {
- container.append(quicks);
- }
- }
-
- // add the filter field and quick list container to just before the table if it was created by the plugin
- if (created_filter) {
- t.before(container);
- }
- }
- }); // return this.each
- }; // $.fn.filterTable
- })(jQuery);