Source: facetfilter.js

/**
 * jQuery enabled facet filter
 *
 * @module jQuery#facetfilter
 */
;(function ($) {
  'use strict';

  /**
   * Facetfilter method
   * $.constructor
   */
  $.facetfilter = function( element, options ) {
    var settings, facets, $element, init;

    /**
     * Default plugin settings
     */
    settings = {
      'filters': null, // Selection of filters that can be applied
      'anti_filters': null, // Deselection filters
      'active_filters': {}, // Current object of active filters
      'single_filters': [], // Define a list of filters that are single use
      'exclude_params': [],
      'ajax_url': null, // Ajax request URL
      'url_options': {}, // Extra options to pass to the URL object (ex. is_ajax: 1)
      'onsuccess': null, // Success callback
      'oncomplete': null, // Complete callback
      'onerror': null, // Error callback
      'callback': null, // Generic callback
      'type': 'html' // Specify the data type returned
    };

    /**
     * Internal object reference
     */
    facets = this;

    // Current plugin version
    facets.version = '1.0.5';

    /**
     * Empty settings for now
     */
    facets.settings = {};

    /**
     * Internal element representation
     */
    $element = $(element),
      element = element;

    /**
     * Set up the plugin options
     */
    init = function() {
      var key, val;

      facets.settings = $.extend({}, settings, options);

      $element.on('change', facets.settings.filters, facets.select);
      $element.on('click', facets.settings.anti_filters, facets.deselect);

      for(key in facets.settings.exclude_params) {
        val = facets.settings.exclude_params[key];
        facets.addFacet(val.name, val.val);
      }
    };

    /**
     * Set up a request
     */
    facets.request = function(type) {
      var key, facet_data;

      if( !facets.settings.ajax_url ) {
        throw new Error('You must supply an ajax URL, bailing');
      } else {
        if( type === void 0 ) {
          type = 'GET';
        } else {
          type = type.toUpperCase();
        }

        facet_data = facets.settings.active_filters;

        for( key in facets.settings.url_options ) {
          facet_data[key] = facets.settings.url_options[key];
        }

        $.ajax({
          url: facets.settings.ajax_url,
          type: type,
          data: facet_data,
          dataType: facets.settings.type,
          success: (facets.settings.onsuccess !== void 0 ? facets.settings.onsuccess : function () {}),
          complete: (facets.settings.oncomplete !== void 0 ? facets.settings.oncomplete : function () {}),
          error: (facets.settings.onerror !== void 0 ? facets.settings.onerror : function () {})
        });
      }
    };

    /**
     * Add a facet to the filters
     */
    facets.addFacet = function(facet, value) {
      if( typeof facets.settings.active_filters[facet] === 'undefined' ) {
        if( value === null ) {
          value = 1;
        }

        facets.settings.active_filters[facet] = {};
      }

      if( facets.isSingleFilter(facet) ) {
        facets.settings.active_filters[facet] = value;
      } else {
        facets.settings.active_filters[facet][value] = value;
      }
    };

    /**
     * Remove facets from the filters
     */
    facets.removeFacet = function(facet, value) {
      var key, facet_count;

      if( value !== void 0 ) {
        if( !this.isSingleFilter(facet) && typeof facets.settings.active_filters[facet][value] !== 'undefined' ) {
          delete facets.settings.active_filters[facet][value];
        } else if( this.isSingleFilter(facet) && typeof facets.settings.active_filters[facet] !== 'undefined' ) {
          delete facets.settings.active_filters[facet];
        }
      } else {
        if( typeof facets.settings.active_filters[facet] !== 'undefined' ) {
          delete facets.settings.active_filters[facet];
        }
      }

      facet_count = 0;
      for( key in facets.settings.active_filters[facet] ) {
        facet_count++;
      }

      if( facet_count === 0 ) {
        delete facets.settings.active_filters[facet];
      }

    };

    /**
     * Select a facet
     */
    facets.select = function(e) {
      var facet_name;

      facet_name = $(this).parent().parent().attr('id');
      facets.addFacet( facet_name, $(this).val() );

      if( facets.settings.callback !== null ) {
        facets.settings.callback.apply(facets, ['addFacet', facet_name, $(this).val()]);
      }

      facets.request();
    };

    /**
     * Deselect a facet
     */
    facets.deselect = function(e) {
      var facet_name;

      facet_name = $(this).attr('name').replace(/\[(.*)\]/, '');
      facets.removeFacet( facet_name, $(this).val() );

      if( facets.settings.callback !== null ) {
        facets.settings.callback.apply(facets, ['removeFacet', facet_name]);
      }

      facets.request();
    };

    /**
     * URI Encode active facets
     */
    facets.serialize = function(obj, prefix) {
      var str, p, k, v;

      str = [];
      if( obj === undefined ) {
        obj = facets.settings.active_filters;
      }
      for( p in obj ) {
        k = prefix ? prefix + '[' + p + ']' : p, v = obj[p];
        str.push(typeof v == 'object' ? facets.serialize(v, k) : encodeURIComponent(k) + '=' + encodeURIComponent(v));
      }
      return str.join('&');
    };

    /**
     * Get the index of an array, or add it if it doesn't exist
     */
    facets.isSingleFilter = function(filter) {
      if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
          if (this === null) {
            throw new TypeError();
          }
          var t = Object(this);
          var len = t.length >>> 0;
          if (len === 0) {
            return -1;
          }
          var n = 0;
          if (arguments.length > 1) {
            n = Number(arguments[1]);
            if (n != n) {
              n = 0;
            } else if (n !== 0 && n != Infinity && n != -Infinity) {
              n = (n > 0 || -1) * Math.floor(Math.abs(n));
            }
          }
          if (n >= len) {
            return -1;
          }
          var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
          for (; k < len; k++) {
            if (k in t && t[k] === searchElement) {
              return k;
            }
          }
          return -1;
        };
      }

      if( facets.settings.single_filters.indexOf(filter) !== -1 ) {
        return true;
      } else {
        return false;
      }
    };

    facets.activeFilters = function() {
      return facets.settings.active_filters;
    };

    /**
     * Call the init private method
     */
    init();
  };

  /**
   * Facetfilter jQuery exposed method for elements
   */
  $.fn.facetfilter = function(options) {
    var facetfilter, ident;

    ident = 'facetfilter';
    return this.each(function() {
      if( undefined === $(this).data(ident) ) {
        facetfilter = new $.facetfilter(this, options);

        $(this).data(ident, facetfilter);
      }
    });
  };

})(jQuery);