Index: misc/tablefilter.js
===================================================================
RCS file: misc/tablefilter.js
diff -N misc/tablefilter.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/tablefilter.js	30 Nov 2009 10:09:53 -0000
@@ -0,0 +1,174 @@
+// $Id$
+
+(function ($) {
+
+// Create an object on which each instance of the tableFilter object will be applied to.
+Drupal.tablefilters = {};
+
+/**
+ * The tableFilter object.
+ */
+Drupal.tableFilter = function (container, settings) {
+  this.settings = settings;
+  this.container = (container.is('form') ? container.children('div') : container);
+
+  // Create the filter textfield.
+  this.createTextfield();
+};
+
+
+/**
+ * Creates an input textfield inside the container.
+ */
+Drupal.tableFilter.prototype.createTextfield = function () {
+  var self = this;
+  this.container.prepend(Drupal.theme('textfield', this.settings));
+  this.textfield = $('#edit-' + this.settings.name, this.container).bind('click keyup', function () {
+    self.filter(self.container, $.trim($(this).val().toLowerCase()));
+  });
+
+  if (this.textfield[0]) {
+    this.textfield[0].type = 'search';
+    this.textfield.attr('results', 5);
+  };
+};
+
+/**
+ * Adds a DOM element after the textfield element and displays a 'no results' message.
+ */
+Drupal.tableFilter.prototype.addPlaceholder = function () {
+  if (!this.container.find('.tablefilter-no-results').length) {
+    this.textfield.closest('.form-item').after($('<p class="tablefilter-no-results"></p>').text(this.settings.empty));
+  };
+};
+
+/**
+ * Removes the 'no results' message.
+ */
+Drupal.tableFilter.prototype.removePlaceholder = function () {
+  this.container.find('.tablefilter-no-results').remove();
+};
+
+/**
+ * Filters all affected table rows for the given string.
+ * All table row containing the string will stay visible,
+ * while other rows are hidden.
+ */
+Drupal.tableFilter.prototype.filter = function (container, string) {
+
+  // Keep track of whether or not we'll find any results.
+  var results = false;
+
+  // Walk through each tbody inside the container element.
+  container.find('tbody').each(function () {
+    var num_trs = $('tr', this).size();
+    var zebra = 'even';
+
+    // Walk through each tr inside the current tbody element.
+    $(this).find('tr').each(function () {
+      str_exists = false;
+
+      // Walk through each td inside the current tr element.
+      $(this).find('td').each(function () {
+        // Check whether or not the string exists in the current td.
+        if ($(this).text().toLowerCase().indexOf(string) > -1) {
+          // The string is found.
+          str_exists = true;
+          results = true;
+        };
+      });
+       // If the variable string_exists returns true, the string exists in the current tr.
+      if (!str_exists) {
+        num_trs--;
+        $(this).removeClass('tablefilter-match').addClass('tablefilter-irrelevant').hide();
+      }
+      else {
+        num_trs++;
+        zebra = (zebra == 'odd' ? 'even' : 'odd');
+        $(this).removeClass('tablefilter-irrelevant odd even').addClass('tablefilter-match ' + (zebra)).show();
+      };
+    });
+    // If the matched tr's equals 0, hide its parent container.
+    if (num_trs == 0) {
+      $(this).parents('table, .tablefilter-group').hide();
+    }
+    else {
+      $(this).parents('table, .tablefilter-group').show();
+    };
+  });
+
+  // If any results are found, remove the 'no results' message.
+  // Otherwise dipslay the 'no results message.
+  if (results) {
+    this.removePlaceholder();
+  }
+  else {
+    this.addPlaceholder();
+  };
+
+  // Allow other scripts to interact with this event.
+  container.trigger('tablefilter');
+};
+
+/**
+ * Attaches the tablefilter bahavior to Drupal behaviours.
+ */
+Drupal.behaviors.tablefilter = {
+  attach: function (context) {
+
+    // Avoid the behavior being attached more than once to this dom element.
+    $('.tablefilter', context).once('tablefilter-processed', function () {
+
+      // Create an unique identifier for the new tablefilter instance.
+      window.table_filter_index = (window.table_filter_index == undefined ? 0 : window.table_filter_index + 1);
+
+      // Specify which element is the container of the table(s) on which to apply the behavior.
+      // This can either be the parent element of an table or a parent element with classname 'tablefilter-container'.
+      var container = ($(this).parents('.tablefilter-container').size() > 0 ? $(this).parents('.tablefilter-container') : $(this).parent());
+
+      // If the container hasn't got an ID, create one
+      if (!container.attr('id')) {
+        container.attr('id', 'tablefilter-' + window.table_filter_index);
+      };
+
+      // Create a default setting object.
+      var settings = {
+        'label': Drupal.t('Filter'),
+        'description': Drupal.t('Enter text to filter the table below.'),
+        'empty': Drupal.t('There were no results.'),
+        'name': 'tablefilter-' + window.table_filter_index
+      };
+
+      // Allow other scripts to overwrite the settings object.
+      if (Drupal.settings && Drupal.settings.tablefilter && Drupal.settings.tablefilter[settings.id]) {
+        for (var i in Drupal.settings.tablefilter[settings.id]) {
+          settings[i] = Drupal.settings.tablefilter[settings.id][i];
+        };
+      };
+
+      // Create a new instance of the tableFilter object and initialize the instance.
+      if (!Drupal.tablefilters[settings.id]) {
+        Drupal.tablefilters[settings.id] =  new Drupal.tableFilter(container, settings);
+      };
+    });
+  }
+};
+
+/**
+ * Theme an input textfield
+ */
+Drupal.theme.textfield = function (element) {
+  var output = '';
+  if (element.label) {
+    output += '<label for="' + (element.id || 'edit-' + element.name) + '">' + element.label + '</label>';
+  };
+  output += '<input type="text" maxlength="' + (element.maxlength || 128) + '" name="' + (element.name) + '" id="' + (element.id || 'edit-' + element.name) + '" size="' + (element.size || 30) + '" value="' + (element.value || '') + '" class="form-text' + (element['class'] ? ' ' + element['class'] : '') + '" />';
+
+  if (element.description) {
+    output += '<div class="description">' + element.description + '</div>';
+  };
+
+  return '<div class="form-item form-type-textfield">' + output + '</div>';
+};
+
+})(jQuery);
