diff --git a/adminer/include/adminer.inc.php b/adminer/include/adminer.inc.php index 277e4fbe..4f864177 100644 --- a/adminer/include/adminer.inc.php +++ b/adminer/include/adminer.inc.php @@ -1062,6 +1062,7 @@ bodyLoad('" . lang('No tables.') . "\n"; } else { + $this->printTablesFilter(); $this->tablesPrint($tables); } } @@ -1106,28 +1107,51 @@ bodyLoad('\n"; } - /** Prints table list in menu - * @param array result of table_status('', true) - * @return null - */ - function tablesPrint($tables) { + function printTablesFilter() + { + global $adminer; + + echo "
" + . "" + . script("initTablesFilter(" . json_encode($adminer->database()) . ");") + . "
\n"; + } + + /** + * Prints table list in menu. + * + * @param array $tables Result of table_status('', true) + * @return null + */ + function tablesPrint(array $tables) { echo "\n"; + + return null; } } diff --git a/adminer/static/default.css b/adminer/static/default.css index e52fc067..fc77e680 100644 --- a/adminer/static/default.css +++ b/adminer/static/default.css @@ -31,6 +31,7 @@ input.default { box-shadow: 1px 1px 1px #777; } input.required { box-shadow: 1px 1px 1px red; } input.maxlength { box-shadow: 1px 1px 1px red; } input.wayoff { left: -1000px; position: absolute; } +input::placeholder { color: #000; opacity: 0.4; } .center { text-align: center; } .block { display: block; } .version { color: #777; font-size: 67%; } @@ -68,6 +69,7 @@ input.wayoff { left: -1000px; position: absolute; } .links a { white-space: nowrap; margin-right: 20px; } .logout { margin-top: .5em; position: absolute; top: 0; right: 0; } .loadmore { margin-left: 1ex; } +.tables-filter { padding: .8em 1em 0; } /* .edit used in designs */ #menu { position: absolute; margin: 10px 0 0; padding: 0 0 30px 0; top: 2em; left: 0; width: 19em; } #menu p, #logins, #tables { padding: .8em 1em; margin: 0; border-bottom: 1px solid #ccc; } @@ -83,6 +85,7 @@ input.wayoff { left: -1000px; position: absolute; } #schema { margin-left: 60px; position: relative; -moz-user-select: none; -webkit-user-select: none; } #schema .table { border: 1px solid silver; padding: 0 2px; cursor: move; position: absolute; } #schema .references { position: absolute; } +#tables-filter { width: 100%; } #help { position: absolute; border: 1px solid #999; background: #eee; padding: 5px; font-family: monospace; z-index: 1; } .rtl h2 { margin: 0 -18px 20px 0; } diff --git a/adminer/static/functions.js b/adminer/static/functions.js index 5f62992d..c27acf4b 100644 --- a/adminer/static/functions.js +++ b/adminer/static/functions.js @@ -357,7 +357,78 @@ function pageClick(href, page) { } } +let tablesFilterTimeout = null; +let tablesFilterValue = ''; +function initTablesFilter(dbName) { + if (sessionStorage) { + document.addEventListener('DOMContentLoaded', function () { + if (dbName === sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')) { + qs('#tables-filter').value = sessionStorage.getItem('adminer_tables_filter'); + filterTables(); + } else { + sessionStorage.removeItem('adminer_tables_filter'); + } + + sessionStorage.setItem('adminer_tables_filter_db', dbName); + }); + } + + const filterInput = qs('#tables-filter'); + filterInput.addEventListener('input', function () { + window.clearTimeout(tablesFilterTimeout); + tablesFilterTimeout = window.setTimeout(filterTables, 200); + }); + + document.body.addEventListener('keydown', function(event) { + if (isCtrl(event) && event.shiftKey && event.key.toUpperCase() === 'F') { + filterInput.focus(); + filterInput.select(); + + event.preventDefault(); + } + }); +} + +function filterTables() { + const value = qs('#tables-filter').value.toLowerCase(); + if (value === tablesFilterValue) { + return; + } + tablesFilterValue = value; + + let reg + if (value !== '') { + const valueExp = (`${value}`).replace(/[\\.+*?\[^\]$(){}=!<>|:]/g, '\\$&'); + reg = new RegExp(`(${valueExp})`, 'gi'); + } + + if (sessionStorage) { + sessionStorage.setItem('adminer_tables_filter', value); + } + + const tables = qsa('#tables li'); + for (let i = 0; i < tables.length; i++) { + let a = qs('a[data-main="true"], span[data-main="true"]', tables[i]); + + let tableName = tables[i].dataset.tableName; + if (tableName == null) { + tableName = a.innerHTML.trim(); + + tables[i].dataset.tableName = tableName; + } + + if (value === "") { + tables[i].classList.remove('hidden'); + a.innerHTML = tableName; + } else if (tableName.toLowerCase().indexOf(value) >= 0) { + tables[i].classList.remove('hidden'); + a.innerHTML = tableName.replace(reg, '$1'); + } else { + tables[i].classList.add('hidden'); + } + } +} /** Display items in menu * @param MouseEvent diff --git a/editor/include/adminer.inc.php b/editor/include/adminer.inc.php index be9d7436..5cf02dc9 100644 --- a/editor/include/adminer.inc.php +++ b/editor/include/adminer.inc.php @@ -623,6 +623,7 @@ qsl('div').onclick = whisperClick;", "") if (!$table_status) { echo "

" . lang('No tables.') . "\n"; } else { + $this->printTablesFilter(); $this->tablesPrint($table_status); } } @@ -632,19 +633,32 @@ qsl('div').onclick = whisperClick;", "") function databasesPrint($missing) { } - function tablesPrint($tables) { - echo "