Implemented fast filter for databases in the navigation tree

This commit is contained in:
Rouslan Placella 2012-07-21 13:12:20 +01:00
parent 10b48d9e46
commit fa5bdc3e08
7 changed files with 236 additions and 142 deletions

View File

@ -3167,44 +3167,12 @@ AJAX.registerOnload('functions.js', function() {
$('select.pageselector').live('change', function(event) {
event.stopPropagation();
// Check where to load the new content
// For the main page we don't need to do anything,
// but for the navigation we need to manually replace the content
if ($(this).closest("div#pma_navigation").length == 0) {
if ($(this).closest("#pma_navigation").length == 0) {
// For the main page we don't need to do anything,
$(this).closest("form").submit();
} else {
var $this = $(this);
var $msgbox = PMA_ajaxShowMessage();
var isDbSelector = $this.parent().closest('.pageselector').is('.dbselector');
var params = $(this).closest("form").serialize() + '&ajax_request=true';
if (isDbSelector) {
params += '&full=true';
} else {
var $input = $this.closest('.list_container').find('.fast_filter input.searchClause');
if ($input.length && $input.val() != $input[0].defaultValue) {
params += "&searchClause=" + $input.val();
}
}
$.get('navigation.php', params, function (data) {
if (data.success) {
PMA_ajaxRemoveMessage($msgbox);
if (isDbSelector) {
$('#pma_navigation_tree').html(data.message).children('div').show();
} else {
var $parent = $this.closest('.list_container').parent();
var $input = $this.closest('.list_container').find('.fast_filter input.searchClause');
var val = '';
if ($input.length) {
val = $input.val();
}
$this.closest('.list_container').html($(data.message).children().show());
$parent.find('.fast_filter input.searchClause').val(val);
$parent.find('span.pos2_value:first').text($parent.find('span.pos2_value:last').text());
$parent.find('span.pos3_value:first').text($parent.find('span.pos3_value:last').text());
}
} else {
PMA_ajaxShowMessage(data.error);
}
});
// but for the navigation we need to manually replace the content
PMA_navigationTreePagination($(this));
}
});

View File

@ -49,25 +49,8 @@ $(function() {
$icon.hide();
$throbber.insertBefore($icon);
var $filterContainer = $(this).closest('div.list_container');
var $filterInput = $([]);
while (1) {
if ($filterContainer.find('li.fast_filter input.searchClause').length != 0) {
$filterInput = $filterContainer.find('li.fast_filter input.searchClause');
break;
} else if (! $filterContainer.is('div.list_container')) {
break;
}
$filterContainer = $filterContainer
.parent()
.closest('div.list_container');
}
var searchClause = '';
if ($filterInput.length != 0
&& $filterInput.val() != $filterInput[0].defaultValue
) {
searchClause = $filterInput.val();
}
var searchClause = PMA_fastFilter.getSearchClause();
var searchClause2 = PMA_fastFilter.getSearchClause2($(this));
var params = {
aPath: $(this).find('span.aPath').text(),
@ -75,7 +58,8 @@ $(function() {
pos: $(this).find('span.pos').text(),
pos2_name: $(this).find('span.pos2_name').text(),
pos2_value: $(this).find('span.pos2_value').text(),
searchClause: searchClause
searchClause: searchClause,
searchClause2: searchClause2
};
var url = $('#pma_navigation').find('a.navigation_url').attr('href');
$.get(url, params, function (data) {
@ -130,52 +114,7 @@ $(function() {
*/
$('#pma_navigation_tree div.pageselector a.ajax').live('click', function (event) {
event.preventDefault();
var $this = $(this);
var isDbSelector = $this.closest('.pageselector').is('.dbselector');
var $msgbox = PMA_ajaxShowMessage();
var params = {ajax_request: true};
if (isDbSelector) {
params['full'] = true;
} else {
var $input = $this
.closest('div.list_container')
.find('li.fast_filter input.searchClause');
if ($input.length && $input.val() != $input[0].defaultValue) {
params['searchClause'] = $input.val();
}
}
$.get($this.attr('href'), params, function (data) {
PMA_ajaxRemoveMessage($msgbox);
if (data.success) {
if (isDbSelector) {
$('#pma_navigation_tree')
.html(data.message)
.children('div')
.show();
} else {
var $parent = $this.closest('div.list_container').parent();
var $input = $this
.closest('div.list_container')
.find('li.fast_filter input.searchClause');
var val = '';
if ($input.length) {
val = $input.val();
}
$this.closest('div.list_container').html(
$(data.message).children().show()
);
$parent.find('li.fast_filter input.searchClause').val(val);
$parent.find('span.pos2_value:first').text(
$parent.find('span.pos2_value:last').text()
);
$parent.find('span.pos3_value:first').text(
$parent.find('span.pos3_value:last').text()
);
}
} else {
PMA_ajaxShowMessage(data.error);
}
});
PMA_navigationTreePagination($(this));
});
/**
@ -334,6 +273,76 @@ function PMA_reloadNavigation() {
});
};
/**
* Handles any requests to change the page in a branch of a tree
*
* This can be called from link click or select change event handlers
*
* @param object $this A jQuery object that points to the element that
* initiated the action of changing the page
*
* @return void
*/
function PMA_navigationTreePagination($this)
{
var $msgbox = PMA_ajaxShowMessage();
var isDbSelector = $this.closest('div.pageselector').is('.dbselector');
if ($this[0].tagName == 'A') {
var url = $this.attr('href');
var params = 'ajax_request=true';
} else { // tagName == 'SELECT'
var url = 'navigation.php';
var params = $this.closest("form").serialize() + '&ajax_request=true';
}
var searchClause = PMA_fastFilter.getSearchClause();
if (searchClause) {
params += '&searchClause=' + encodeURIComponent(searchClause);
}
if (isDbSelector) {
params += '&full=true';
} else {
var searchClause2 = PMA_fastFilter.getSearchClause2($this);
if (searchClause2) {
params += '&searchClause2=' + encodeURIComponent(searchClause2);
}
}
$.post(url, params, function (data) {
PMA_ajaxRemoveMessage($msgbox);
if (data.success) {
if (isDbSelector) {
var val = PMA_fastFilter.getSearchClause();
$('#pma_navigation_tree')
.html(data.message)
.children('div')
.show();
if (val) {
$('#pma_navigation_tree')
.find('li.fast_filter input.searchClause')
.val(val);
}
} else {
var $parent = $this.closest('div.list_container').parent();
var val = PMA_fastFilter.getSearchClause2($this);
$this.closest('div.list_container').html(
$(data.message).children().show()
);
if (val) {
$parent.find('li.fast_filter input.searchClause').val(val);
}
$parent.find('span.pos2_value:first').text(
$parent.find('span.pos2_value:last').text()
);
$parent.find('span.pos3_value:first').text(
$parent.find('span.pos3_value:last').text()
);
}
} else {
PMA_ajaxShowMessage(data.error);
}
});
};
/**
* @var ScrollHandler Custom object that manages the scrolling of the navigation
*/
@ -658,6 +667,48 @@ var PMA_fastFilter = {
this.request();
}
},
/**
* Gets the query string from the database fast filter form
*
* @return string
*/
getSearchClause: function () {
var retval = '';
var $input = $('#pma_navigation_tree')
.find('li.fast_filter.db_fast_filter input.searchClause');
if ($input.length && $input.val() != $input[0].defaultValue) {
retval = $input.val();
}
return retval;
},
/**
* Gets the query string from a second level item's fast filter form
* The retrieval is done by trasversing the navigation tree backwards
*
* @return string
*/
getSearchClause2: function ($this) {
var $filterContainer = $this.closest('div.list_container');
var $filterInput = $([]);
while (1) {
if ($filterContainer.find('li.fast_filter:not(.db_fast_filter) input.searchClause').length != 0) {
$filterInput = $filterContainer.find('li.fast_filter:not(.db_fast_filter) input.searchClause');
break;
} else if (! $filterContainer.is('div.list_container')) {
break;
}
$filterContainer = $filterContainer
.parent()
.closest('div.list_container');
}
var searchClause2 = '';
if ($filterInput.length != 0
&& $filterInput.first().val() != $filterInput[0].defaultValue
) {
searchClause2 = $filterInput.val();
}
return searchClause2;
},
/**
* @var hash events A list of functions that are further
* down the page bound to DOM events
@ -769,8 +820,14 @@ PMA_fastFilter.filter.prototype.request = function ()
that.xhr.abort();
}
var url = $('#pma_navigation').find('a.navigation_url').attr('href');
var results = that.$this.find('li:visible:not(.fast_filter)').length;
var params = that.$this.find('form.fast_filter').serialize() + "&results=" + results;
var results = that.$this.find('li:not(.hidden):not(.fast_filter):not(.navGroup)').not('[class^=new]').length;
var params = that.$this.find('> ul > li > form.fast_filter').first().serialize() + "&results=" + results;
if (that.$this.find('> ul > li > form.fast_filter:first input[name=searchClause]').length == 0) {
var $input = $('#pma_navigation_tree').find('li.fast_filter.db_fast_filter input.searchClause');
if ($input.length && $input.val() != $input[0].defaultValue) {
params += '&searchClause=' + encodeURIComponent($input.val());
}
}
that.xhr = $.ajax({
url: url,
type: 'post',
@ -791,7 +848,7 @@ PMA_fastFilter.filter.prototype.request = function ()
}
}
});
}, 500);
}, 250);
};
/**
* Replaces the contents of the navigation branch with the search results

View File

@ -32,10 +32,11 @@ class PMA_NavigationHeader
'ajax_request' => true
)
);
$highlight = '';
$class = ' class="list_container';
if ($GLOBALS['cfg']['NavigationTreePointerEnable']) {
$highlight = ' class="highlight"';
$class .= ' highlight';
}
$class .= '"';
$buffer = '<div id="pma_navigation">';
$buffer .= '<div id="pma_navigation_resizer"></div>';
$buffer .= '<div id="pma_navigation_collapser"></div>';
@ -52,7 +53,12 @@ class PMA_NavigationHeader
$buffer .= $this->_links();
$buffer .= $this->_serverChoice();
$buffer .= $this->_recent();
$buffer .= '<div id="pma_navigation_tree"' . $highlight . '>';
$buffer .= $this->_commonFunctions->getImage(
'ajax_clock_small.gif',
__('Loading'),
array('style' => 'visibility: hidden;', 'class' => 'throbber')
);
$buffer .= '<div id="pma_navigation_tree"' . $class . '>';
return $buffer;
}

View File

@ -64,11 +64,19 @@ class PMA_NavigationTree
private $_pos3_value = array();
/**
* @var string The search clause to use in SQL queries for fetching nodes
* @var string The search clause to use in SQL queries for
* fetching databases
* Used by the asynchronous fast filter
*/
private $_searchClause = '';
/**
* @var string The search clause to use in SQL queries for
* fetching nodes
* Used by the asynchronous fast filter
*/
private $_searchClause2 = '';
/**
* @var object A reference to the common functions object
*/
@ -130,6 +138,9 @@ class PMA_NavigationTree
if (isset($_REQUEST['searchClause'])) {
$this->_searchClause = $_REQUEST['searchClause'];
}
if (isset($_REQUEST['searchClause2'])) {
$this->_searchClause2 = $_REQUEST['searchClause2'];
}
// Initialise the tree by creating a root node
$node = new Node('root', Node::CONTAINER);
$this->_tree = $node;
@ -190,7 +201,7 @@ class PMA_NavigationTree
$retval = $this->_tree;
// Add all databases unconditionally
foreach ($this->_tree->getData('', $this->_pos) as $db) {
foreach ($this->_tree->getData('databases', $this->_pos, $this->_searchClause) as $db) {
$node = new Node_Database($db);
$this->_tree->addChild($node);
}
@ -258,7 +269,7 @@ class PMA_NavigationTree
$dbData = $db->getData(
$container->real_name,
$pos2,
$this->_searchClause
$this->_searchClause2
);
foreach ($dbData as $item) {
switch ($container->real_name) {
@ -536,6 +547,7 @@ class PMA_NavigationTree
}
foreach ($prefixes as $key => $value) {
$this->groupNode($groups[$key]);
$groups[$key]->classes = "navGroup";
}
}
}
@ -552,23 +564,9 @@ class PMA_NavigationTree
$node = $this->_buildPath();
$retval = false;
if ($node !== false) {
$retval = PMA_commonFunctions::getInstance()->getListNavigator(
$this->_tree->getPresence(),
$this->_pos,
array('server' => $GLOBALS['server']),
'navigation.php',
'frame_navigation',
$GLOBALS['cfg']['MaxNavigationItems'],
'pos',
array('dbselector')
);
$retval = $this->_fastFilterHtml($this->_tree);
$retval .= $this->_getPageSelector($this->_tree);
$this->groupTree();
$retval .= $this->_commonFunctions->getImage(
'ajax_clock_small.gif',
__('Loading'),
array('style' => 'visibility: hidden;', 'class' => 'throbber')
);
$retval .= "<div><ul>";
$children = $this->_tree->children;
usort($children, array('PMA_NavigationTree', 'sortNode'));
@ -616,11 +614,20 @@ class PMA_NavigationTree
$retval .= "</ul>";
$retval .= "</div>";
}
if (! empty($this->_searchClause)) {
$results = $node->realParent()->getPresence(
$node->real_name,
$this->_searchClause
);
if (! empty($this->_searchClause) || ! empty($this->_searchClause2)) {
if (! empty($this->_searchClause2)) {
$results = $node->realParent()->getPresence(
$node->real_name,
$this->_searchClause2
);
} else {
$results = $this->_tree->getPresence(
'databases',
$this->_searchClause
);
}
$clientResults = 0;
if (! empty($_REQUEST['results'])) {
$clientResults = (int)$_REQUEST['results'];
@ -691,7 +698,7 @@ class PMA_NavigationTree
{
$retval = '';
$paths = $node->getPaths();
if ($node->hasSiblings()) {
if ($node->hasSiblings() || isset($_REQUEST['results'])) {
if ( $node->type == Node::CONTAINER
&& count($node->children) == 0
&& $GLOBALS['is_ajax_request'] != true
@ -879,13 +886,13 @@ class PMA_NavigationTree
$buffer .= $this->_renderNode(
$children[$i],
true,
$node->classes
$children[$i]->classes
);
} else {
$buffer .= $this->_renderNode(
$children[$i],
true,
$node->classes . ' last'
$children[$i]->classes . ' last'
);
}
}
@ -901,7 +908,9 @@ class PMA_NavigationTree
}
}
}
$retval .= "</li>";
if ($node->hasSiblings() || isset($_REQUEST['results'])) {
$retval .= "</li>";
}
return $retval;
}
@ -934,7 +943,23 @@ class PMA_NavigationTree
private function _fastFilterHtml($node)
{
$retval = '';
if (($node->type == Node::CONTAINER
if ($node === $this->_tree
&& $this->_tree->getPresence() >= (int)$GLOBALS['cfg']['NavigationTreeDisplayDbFilterMinimum']
) {
$url_params = array(
'pos' => 0
);
$retval .= "<ul>";
$retval .= "<li class='fast_filter db_fast_filter'>";
$retval .= "<form class='ajax fast_filter'>";
$retval .= PMA_getHiddenFields($url_params);
$retval .= "<input class='searchClause' name='searchClause'";
$retval .= " value='" . __('filter databases by name') . "' />";
$retval .= "<span title='" . __('Clear Fast Filter') . "'>X</span>";
$retval .= "</form>";
$retval .= "</li>";
$retval .= "</ul>";
} else if (($node->type == Node::CONTAINER
&& ( $node->real_name == 'tables'
|| $node->real_name == 'views'
|| $node->real_name == 'functions'
@ -954,8 +979,8 @@ class PMA_NavigationTree
$retval .= "<li class='fast_filter'>";
$retval .= "<form class='ajax fast_filter'>";
$retval .= PMA_getHiddenFields($url_params);
$retval .= "<input class='searchClause' name='searchClause'";
$retval .= " value='" . __('filter tables by name') . "' />";
$retval .= "<input class='searchClause' name='searchClause2'";
$retval .= " value='" . __('filter items by name') . "' />";
$retval .= "<span title='" . __('Clear Fast Filter') . "'>X</span>";
$retval .= "</form>";
$retval .= "</li>";
@ -974,7 +999,18 @@ class PMA_NavigationTree
private function _getPageSelector($node)
{
$retval = '';
if ($node->type == Node::CONTAINER && ! $node->is_group) {
if ($node === $this->_tree) {
$retval .= PMA_commonFunctions::getInstance()->getListNavigator(
$this->_tree->getPresence('databases', $this->_searchClause),
$this->_pos,
array('server' => $GLOBALS['server']),
'navigation.php',
'frame_navigation',
$GLOBALS['cfg']['MaxNavigationItems'],
'pos',
array('dbselector')
);
} else if ($node->type == Node::CONTAINER && ! $node->is_group) {
$paths = $node->getPaths();
$level = isset($paths['aPath_clean'][4]) ? 3 : 2;
@ -994,9 +1030,9 @@ class PMA_NavigationTree
}
$num = $node->realParent()->getPresence(
$node->real_name,
$this->_searchClause
$this->_searchClause2
);
$retval = $this->_commonFunctions->getListNavigator(
$retval .= $this->_commonFunctions->getListNavigator(
$num,
$pos,
$_url_params,

View File

@ -359,6 +359,13 @@ class Node
{
$query = "SELECT `SCHEMA_NAME` ";
$query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` ";
if (! empty($searchClause)) {
$query .= "WHERE `SCHEMA_NAME` LIKE '%";
$query .= $this->_commonFunctions->sqlAddSlashes(
$searchClause, true
);
$query .= "%' ";
}
$query .= "ORDER BY `SCHEMA_NAME` ASC ";
$query .= "LIMIT $pos, {$GLOBALS['cfg']['MaxNavigationItems']}";
return PMA_DBI_fetch_result($query);
@ -390,9 +397,23 @@ class Node
if (! $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['DisableIS']) {
$query = "SELECT COUNT(*) ";
$query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` ";
if (! empty($searchClause)) {
$query .= "WHERE `SCHEMA_NAME` LIKE '%";
$query .= $this->_commonFunctions->sqlAddSlashes(
$searchClause, true
);
$query .= "%' ";
}
$retval = (int)PMA_DBI_fetch_value($query);
} else {
$query = "SHOW DATABASES ";
if (! empty($searchClause)) {
$query .= "LIKE '%";
$query .= $this->_commonFunctions->sqlAddSlashes(
$searchClause, true
);
$query .= "%' ";
}
$retval = PMA_DBI_num_rows(PMA_DBI_try_query($query));
}
return $retval;

View File

@ -201,6 +201,9 @@ li.fast_filter span {
font-weight: bold;
color: #800;
}
li.fast_filter.db_fast_filter {
border: 0;
}
/* Resize handler */
#pma_navigation_resizer {

View File

@ -196,6 +196,9 @@ li.fast_filter span {
font-weight: bold;
color: #800;
}
li.fast_filter.db_fast_filter {
border: 0;
}
/* Resize handler */
#pma_navigation_resizer {