﻿/*
Filterable Table jQuery Plugin
Description: Makes a table filterable by adding textboxes to column headers.
Requirements:
    jquery.1.3.2.js
    jquery.timer.js
    jquery.cookie.js
*/

jQuery.fn.filterable = function (options) {

    // Array for storing headers
    var headers = [];
    var values = {};
    // Variable to store the root object
    var root = $(this);

    // Munge settings with default values
    var settings = jQuery.extend({
        // Default to have no styling attached to the text boxes.
        textBoxStyle: ""
        // Cookie name is unique for the page, override if more than one table
        // is made filterable on a page.
        , cookieName: "jQuery.filterable[" + escape(window.location) + "]"
        // override to completely disable the use of cookies for storing field values
        , useCookies: true
        // override to enable the hiding of the text fields until the user hovers
        // over the table cell.
        , autoHide: false
    }, options);

    var getValue = function (name) {
        if (!settings.useCookies) { return ""; }

        var fullCookie = $.cookie(settings.cookieName);
        if (fullCookie == null || fullCookie.length == 0) {
            return "";
        }
        var items = fullCookie.split('&');
        for (var i = 0; i < items.length; i++) {
            var pair = items[i].split('=');
            var key = unescape(pair[0]);
            var value = unescape(pair[1]);
            if (key == name) {
                return value;
            }
        }
        return "";
    };

    var filter = function () {

        root.find("tbody tr").each(function () {
            var show = true;
            var i = 0;
            $(this).find("td").each(function () {
                // first, find the appropriate header's name
                var query = values[headers[i]];
                // Increment now because we have "return" statements lower down
                i++;

                // Bail out if we fail to find the requested label
                if (typeof query == 'undefined' || query.length == 0) { return; }
                // Finally, check the contents of the field for the search
                // string, setting show to false if it is not found.
                if ($(this).text().search(new RegExp(query, "i")) < 0) {
                    show = false;
                }
            });
            if (show) { $(this).show(); } else { $(this).hide(); }

            // Set the cookie to save the state of the fields
            if (!settings.useCookies) { return; }
            var fullValue = "";
            root.find("thead tr th input").each(function () {
                fullValue += escape($(this).attr("name")) + "=" + escape($(this).val()) + "&";
            });
            $.cookie(settings.cookieName, fullValue);
        });

        // Call the custom callback, if it exists.
        if (settings.filterRun != null) {
            settings.filterRun(event);
        }
    }
    var textEntered = function (event) {


        // Process the keypress and filter the columns.
        // TAB key is a non-event
        if (event.keyCode == 9) { return; }
        // ESC key clears the contents of the field
        if (event.keyCode == 27) { $(this).val(""); }
        values[$(this).attr("name")] = $(this).val();
        // Cancel the current timer.
        $(this).stopTime();
        // Queue up a new timer to execute the call to filter. This will
        // prevent evaluation of the filters until typing stops.
        $(this).oneTime(500, function () {
            filter();
        });

    };

    // Collect the headers into an array for future reference.
    root.find("thead tr th").each(function () {
        var name = $(this).text().replace(/ /gi, "");
        if ($.trim(name).length == 0 || $.trim(name) == " ") { return; }
        headers.push(name);
    });

    // Create a second header row for the filter fields
    var inputRow = $("<tr>");
    root.find("thead tr").after(inputRow);
    for (var i = 0; i < headers.length; i++) {
        var name = headers[i];
        // Add a line break after the label
        inputRow.append(
            $("<td>")
                .attr("id", name)
        // Add the input text field, set its class, its attributes, and
        // its keyup event.
                .append($("<input>")
                    .attr({
                        type: "text",
                        name: name,
                        id: name,
                        style: settings.textBoxStyle,
                        value: getValue(name)
                    })
                    .keyup(textEntered)
                )
            );
        // If turned on, enable the hiding of fields until hovering over the header
        if (!settings.autoHide) { continue; }
        $(this).find("span #" + name).hide();
        $(this).hover(function () {
            $(this).find("span #" + name).fadeIn("fast");
        }, function () {
            $(this).find("span #" + name).fadeOut("fast");
        });
    }

    filter();
}
