diff --git a/js/jquery/jquery.uitablefilter.js b/js/jquery/jquery.uitablefilter.js
new file mode 100644
index 0000000000..9184d77227
--- /dev/null
+++ b/js/jquery/jquery.uitablefilter.js
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2008 Greg Weber greg at gregweber.info
+ * Dual licensed under the MIT and GPLv2 licenses just as jQuery is:
+ * http://jquery.org/license
+ *
+ * Multi-columns fork by natinusala
+ *
+ * documentation at http://gregweber.info/projects/uitablefilter
+ * https://github.com/natinusala/jquery-uitablefilter
+ *
+ * allows table rows to be filtered (made invisible)
+ *
+ * t = $('table')
+ * $.uiTableFilter( t, phrase )
+ *
+ * arguments:
+ * jQuery object containing table rows
+ * phrase to search for
+ * optional arguments:
+ * array of columns to limit search too (the column title in the table header)
+ * ifHidden - callback to execute if one or more elements was hidden
+ */
+(function($) {
+ $.uiTableFilter = function(jq, phrase, column, ifHidden){
+ var new_hidden = false;
+ if( this.last_phrase === phrase ) return false;
+
+ var phrase_length = phrase.length;
+ var words = phrase.toLowerCase().split(" ");
+
+ // these function pointers may change
+ var matches = function(elem) { elem.show() }
+ var noMatch = function(elem) { elem.hide(); new_hidden = true }
+ var getText = function(elem) { return elem.text() }
+
+ if( column )
+ {
+ if (!$.isArray(column))
+ {
+ column = new Array(column);
+ }
+
+ var index = new Array();
+
+ jq.find("thead > tr:last > th").each(function(i)
+ {
+ for (var j = 0; j < column.length; j++)
+ {
+ if ($.trim($(this).text()) == column[j])
+ {
+ index[j] = i;
+ break;
+ }
+ }
+
+ });
+
+ getText = function(elem) {
+ var selector = "";
+ for (var i = 0; i < index.length; i++)
+ {
+ if (i != 0) {selector += ",";}
+ selector += "td:eq(" + index[i] + ")";
+ }
+ return $(elem.find((selector))).text();
+ }
+ }
+
+ // if added one letter to last time,
+ // just check newest word and only need to hide
+ if( (words.size > 1) && (phrase.substr(0, phrase_length - 1) ===
+ this.last_phrase) ) {
+
+ if( phrase[-1] === " " )
+ { this.last_phrase = phrase; return false; }
+
+ var words = words[-1]; // just search for the newest word
+
+ // only hide visible rows
+ matches = function(elem) {;}
+ var elems = jq.find("tbody:first > tr:visible")
+ }
+ else {
+ new_hidden = true;
+ var elems = jq.find("tbody:first > tr")
+ }
+
+ elems.each(function(){
+ var elem = $(this);
+ $.uiTableFilter.has_words( getText(elem), words, false ) ?
+ matches(elem) : noMatch(elem);
+ });
+
+ last_phrase = phrase;
+ if( ifHidden && new_hidden ) ifHidden();
+ return jq;
+ };
+
+ // caching for speedup
+ $.uiTableFilter.last_phrase = ""
+
+ // not jQuery dependent
+ // "" [""] -> Boolean
+ // "" [""] Boolean -> Boolean
+ $.uiTableFilter.has_words = function( str, words, caseSensitive )
+ {
+ var text = caseSensitive ? str : str.toLowerCase();
+ for (var i=0; i < words.length; i++) {
+ if (text.indexOf(words[i]) === -1) return false;
+ }
+ return true;
+ }
+}) (jQuery);
diff --git a/js/sql.js b/js/sql.js
index e50c28bf14..a5cc359ba5 100644
--- a/js/sql.js
+++ b/js/sql.js
@@ -84,6 +84,7 @@ AJAX.registerTeardown('sql.js', function () {
$('th.column_heading.pointer').die('hover');
$('th.column_heading.marker').die('click');
$(window).unbind('scroll');
+ $(".filter_rows").die("keyup");
});
/**
@@ -396,6 +397,30 @@ AJAX.registerOnload('sql.js', function () {
PMA_init_slider();
}); // end $.post()
}); //end displayOptionsForm handler
+
+ // Filter row handling. --STARTS--
+ $(".filter_rows").live("keyup", function () {
+ var $target_table = $("#table_results");
+ var $header_cells = $target_table.find("th[data-column]");
+ var target_columns = Array();
+ // To handle colspan=4, in case of edit,copy etc options.
+ var dummy_th = ($(".edit_row_anchor").length !== 0 ?
+ '
'
+ : '');
+ // Selecting columns that will be considered for filtering and searching.
+ $header_cells.each(function () {
+ target_columns.push($.trim($(this).text()));
+ });
+
+ var phrase = $(this).val();
+ // Set same value to both Filter rows fields.
+ $(".filter_rows").val(phrase);
+ // Handle colspan.
+ $target_table.find("thead > tr").prepend(dummy_th);
+ $.uiTableFilter($target_table, phrase, target_columns);
+ $target_table.find("th.dummy_th").remove();
+ });
+ // Filter row handling. --ENDS--
}); // end $()
/**
diff --git a/libraries/DisplayResults.class.php b/libraries/DisplayResults.class.php
index 1fa4c7701e..76b4c340be 100644
--- a/libraries/DisplayResults.class.php
+++ b/libraries/DisplayResults.class.php
@@ -789,6 +789,12 @@ class PMA_DisplayResults
);
$table_navigation_html .= ''
+ . ''
+ . '
'
+ . '
'
+ . '' . __('Filter rows') . ':'
+ . ''
. '
'
. '
'
. ''
@@ -1835,7 +1841,7 @@ class PMA_DisplayResults
* @access private
*
* @see _getTableHeaders()
- */
+ */
private function _getOrderLinkAndSortedHeaderHtml(
$fields_meta, $sort_expression, $sort_expression_nodirection,
$column_index, $unsorted_sql_query, $session_max_rows, $direction,
@@ -1859,7 +1865,7 @@ class PMA_DisplayResults
$name_to_use_in_sort = $fields_meta->name;
- // Generates the orderby clause part of the query which is part
+ // Generates the orderby clause part of the query which is part
// of URL
list($sort_order, $order_img) = $this->_makeUrl(
$sort_expression, $sort_expression_nodirection, $sort_tbl,
@@ -1922,48 +1928,48 @@ class PMA_DisplayResults
private function _makeUrl(
$sort_expression, $sort_expression_nodirection, $sort_tbl,
$name_to_use_in_sort, $sort_direction, $fields_meta, $column_index
- ) {
+ ) {
$sort_order = "";
// Check if the current column is in the order by clause
$is_in_sort = $this->_isInSorted(
$sort_expression, $sort_expression_nodirection,
$sort_tbl, $name_to_use_in_sort
- );
- $current_name = $name_to_use_in_sort;
+ );
+ $current_name = $name_to_use_in_sort;
if ($sort_expression_nodirection[0] == '' || !$is_in_sort) {
- $special_index = $sort_expression_nodirection[0] == ''
- ? 0
+ $special_index = $sort_expression_nodirection[0] == ''
+ ? 0
: count($sort_expression_nodirection);
$sort_expression_nodirection[$special_index]
= PMA_Util::backquote(
$current_name
- );
+ );
$sort_direction[$special_index] = (preg_match(
'@time|date@i',
$fields_meta->type
)) ? self::DESCENDING_SORT_DIR : self::ASCENDING_SORT_DIR;
-
+
}
- $sort_expression_nodirection = array_filter($sort_expression_nodirection);
- foreach ($sort_expression_nodirection as $index=>$expression) {
+ $sort_expression_nodirection = array_filter($sort_expression_nodirection);
+ foreach ($sort_expression_nodirection as $index=>$expression) {
// check if this is the first clause,
- // if it is then we have to add "order by"
- $is_first_clause = ($index == 0);
- $name_to_use_in_sort = $expression;
+ // if it is then we have to add "order by"
+ $is_first_clause = ($index == 0);
+ $name_to_use_in_sort = $expression;
$sort_tbl_new = $sort_tbl;
// Test to detect if the column name is a standard name
// Standard name has the table name prefixed to the column name
$is_standard_name = false;
if (strpos($name_to_use_in_sort, '.') !== false) {
$matches = explode('.', $name_to_use_in_sort);
- // Matches[0] has the table name
+ // Matches[0] has the table name
// Matches[1] has the column name
- $name_to_use_in_sort = $matches[1];
- $sort_tbl_new = $matches[0];
+ $name_to_use_in_sort = $matches[1];
+ $sort_tbl_new = $matches[0];
$is_standard_name = true;
- }
-
-
+ }
+
+
// $name_to_use_in_sort might contain a space due to
// formatting of function expressions like "COUNT(name )"
// so we remove the space in this situation
@@ -1972,8 +1978,8 @@ class PMA_DisplayResults
// If this the first column name in the order by clause add
// order by clause to the column name
- $query_head = $is_first_clause ? "\nORDER BY " : "";
- $tbl = $is_standard_name ? $sort_tbl_new : $sort_tbl;
+ $query_head = $is_first_clause ? "\nORDER BY " : "";
+ $tbl = $is_standard_name ? $sort_tbl_new : $sort_tbl;
// Again a check to see if the given column is a aggregate column
if (strpos($name_to_use_in_sort, '(') !== false) {
$sort_order .= $query_head . $name_to_use_in_sort . ' ' ;
@@ -1981,28 +1987,28 @@ class PMA_DisplayResults
$sort_order .= $query_head . $sort_tbl_new . "."
. PMA_Util::backquote(
$name_to_use_in_sort
- ) . ' ' ;
- }
+ ) . ' ' ;
+ }
// For a special case where the code generates two dots between
// column name and table name.
$sort_order = preg_replace("/\.\./", ".", $sort_order);
// Incase the current column name is in the order by clause
- // We need to generate the arrow button and related html
+ // We need to generate the arrow button and related html
if ($current_name == $name_to_use_in_sort && $is_in_sort) {
list($sort_order, $order_img) = $this->_getSortingUrlParams(
$sort_direction, $sort_order, $column_index, $index
- );
+ );
} else {
$sort_order .= strtoupper($sort_direction[$index]);
}
// Separte columns by a comma
- $sort_order .= ", ";
- unset($name_to_use_in_sort);
+ $sort_order .= ", ";
+ unset($name_to_use_in_sort);
}
// remove the comma from the last column name in the newly
// constructed clause
- $sort_order = substr($sort_order, 0, strlen($sort_order)-2);
+ $sort_order = substr($sort_order, 0, strlen($sort_order)-2);
return array($sort_order, $order_img);
}
@@ -2024,20 +2030,20 @@ class PMA_DisplayResults
$sort_expression, $sort_expression_nodirection, $sort_tbl,
$name_to_use_in_sort
) {
-
+
$index_in_expression = 0;
-
+
foreach ($sort_expression_nodirection as $index => $clause) {
if (strpos($clause, '.') !== false) {
$fragments = explode('.', $clause);
$clause2 = $fragments[0] . "." . str_replace('`', ``, $fragments[1]);
} else {
$clause2 = $sort_tbl . str_replace('`', ``, $clause);
- }
+ }
if ($clause2 === $sort_tbl . $name_to_use_in_sort) {
- $index_in_expression = $index;
+ $index_in_expression = $index;
break;
- }
+ }
}
if (empty($sort_expression[$index_in_expression])) {
$is_in_sort = false;
@@ -2101,7 +2107,7 @@ class PMA_DisplayResults
$index2 = $index + 1;
if (strtoupper(trim($sort_direction[$index])) == self::DESCENDING_SORT_DIR) {
-
+
$sort_number = "".$index2."";
$sort_order .= ' ASC';
$order_img = ' ' . PMA_Util::getImage(
@@ -2112,7 +2118,7 @@ class PMA_DisplayResults
$order_img .= ' ' . PMA_Util::getImage(
's_asc.png', __('Ascending'),
array('class' => "soimg$column_index hide", 'title' => '')
- ) . $sort_number;
+ ) . $sort_number;
} else {
@@ -2126,7 +2132,7 @@ class PMA_DisplayResults
$order_img .= ' ' . PMA_Util::getImage(
's_desc.png', __('Descending'),
array('class' => "soimg$column_index hide", 'title' => '')
- ) . $sort_number;
+ ) . $sort_number;
}
@@ -2154,7 +2160,7 @@ class PMA_DisplayResults
$order_img, $col_index, $direction, $fields_meta, $order_url
) {
- $order_link_params = array();
+ $order_link_params = array();
if (isset($order_img) && ($order_img != '')) {
if (strstr($order_img, 'asc')) {
$order_link_params['onmouseover'] = "$('.soimg$col_index').toggle()";
@@ -4821,15 +4827,15 @@ class PMA_DisplayResults
* @see getTable()
*/
private function _getSortParams($order_by_clause)
- {
+ {
- if (! empty($order_by_clause)) {
+ if (! empty($order_by_clause)) {
// Each order by clause is assumed to be delimited by a comma
// A typical order by clause would be order by column1 asc, column2 desc
// The following line counts the number of columns in order by clause
$matches = explode(',', $order_by_clause);
// Iterate over each column in order by clause
- foreach ($matches as $index=>$order_by_clause2) {
+ foreach ($matches as $index=>$order_by_clause2) {
$sort_expression[$index] = trim(
str_replace(' ', ' ', $order_by_clause2)
@@ -4844,9 +4850,9 @@ class PMA_DisplayResults
$sort_expression_nodirection[$index] = isset($matches[1])
? trim($matches[1])
- : $sort_expression[$index];
+ : $sort_expression[$index];
$sort_direction[$index]
- = isset($matches[2]) ? trim($matches[2]) : '';
+ = isset($matches[2]) ? trim($matches[2]) : '';
}
} else {
$sort_expression[0] = $sort_expression_nodirection[0]
@@ -4856,7 +4862,7 @@ class PMA_DisplayResults
return array($sort_expression, $sort_expression_nodirection,
$sort_direction
);
-
+
} // end of the '_getSortParams()' function
diff --git a/sql.php b/sql.php
index b934d4704d..07a8ca770d 100644
--- a/sql.php
+++ b/sql.php
@@ -23,6 +23,7 @@ $response = PMA_Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('jquery/jquery-ui-timepicker-addon.js');
+$scripts->addFile('jquery/jquery.uitablefilter.js');
$scripts->addFile('tbl_change.js');
$scripts->addFile('indexes.js');
$scripts->addFile('gis_data_editor.js');
diff --git a/tbl_select.php b/tbl_select.php
index f191d592a5..4cbf7593f7 100644
--- a/tbl_select.php
+++ b/tbl_select.php
@@ -25,6 +25,7 @@ $scripts->addFile('sql.js');
$scripts->addFile('tbl_select.js');
$scripts->addFile('tbl_change.js');
$scripts->addFile('jquery/jquery-ui-timepicker-addon.js');
+$scripts->addFile('jquery/jquery.uitablefilter.js');
$scripts->addFile('gis_data_editor.js');
$table_search = new PMA_TableSearch($db, $table, "normal");