1
0
mirror of https://github.com/vrana/adminer.git synced 2025-08-30 09:39:51 +02:00

Compare commits

...

17 Commits
v4.10 ... v4.11

Author SHA1 Message Date
Peter Knut
81e337bed1 Release 4.11 2024-10-30 22:14:44 +01:00
Peter Knut
18ddbf1d60 MySQL: Fix highlighting current table in menu on macOS 2024-10-30 22:12:59 +01:00
Peter Knut
e4235d21e5 Clean up JS code 2024-10-30 21:16:39 +01:00
Peter Knut
10dfc54bf4 Show help popup after a short delay, refactoring 2024-10-30 21:16:39 +01:00
Peter Knut
af3c863be3 Fix drag-n-drop moving of function parameters 2024-10-30 21:16:39 +01:00
Peter Knut
6cd5495c1b PostgreSQL: Show list of schemas in database, unify lists of sequences and user types 2024-10-30 21:16:39 +01:00
Peter Knut
78ad8381ab Update CS and SK translations 2024-10-30 21:16:39 +01:00
Peter Knut
87fc82f88e Fix printing error message while validating server URL 2024-10-30 21:16:39 +01:00
Peter Knut
0519a0b985 Devel: Add modification time to CSS and JS links for easier development 2024-10-30 21:16:39 +01:00
Peter Knut
f61cf1ba0c Support drag-n-drop moving on touch screens 2024-10-30 21:16:39 +01:00
HyP3r
fc2e025603 MS SQL: Prefix Unicode strings with 'N' so they are treated correctly 2024-10-30 21:16:39 +01:00
Peter Knut
659e72b692 MariaDB: Fix several links to documentation pages 2024-10-30 21:16:39 +01:00
Peter Knut
123373ca82 Switch to custom JUSH library 2024-10-30 21:16:39 +01:00
Peter Knut
e99f2d90cf Update project information 2024-10-30 21:16:39 +01:00
Peter Knut
bdabc5aa13 Small CSS tuning 2024-10-30 21:16:39 +01:00
Peter Knut
92f3e0ca00 Reset the style of sortable row after dragging 2024-10-22 23:29:03 +02:00
Peter Knut
aa1266e4f2 Bump version to 4.10.1-dev 2024-10-22 23:29:03 +02:00
34 changed files with 454 additions and 293 deletions

View File

@@ -1,5 +1,18 @@
# Changelog
## Adminer 4.11 (2024-10-30)
- Support drag-n-drop moving on touch screens
- Fix drag-n-drop moving of function parameters
- Update project information in comments
- Update CS and SK translations
- Show help popup after a short delay
- PostgreSQL: Show list of schemas in database, unify lists of sequences and user types
- MariaDB: Fix several links to documentation pages
- MySQL: Fix highlighting current table in menu on macOS
- MS SQL: Prefix Unicode strings with 'N' so they are treated correctly
- Fix printing error message while validating server URL
- Small CSS tuning
## Adminer 4.10 (2024-10-22)
### UI changes and improvements

View File

@@ -182,8 +182,8 @@ foreach ($engines as $engine) {
<p>
<?php if (support("columns") || $TABLE == "") { ?>
<?php echo lang('Table name'); ?>: <input name="name" data-maxlength="64" value="<?php echo h($row["name"]); ?>" autocapitalize="off">
<?php if ($TABLE == "" && !$_POST) { echo script("focus(qs('#form')['name']);"); } ?>
<?php echo ($engines ? "<select name='Engine'>" . optionlist(array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . "</select>" . on_help("getTarget(event).value", 1) . script("qsl('select').onchange = helpClose;") : ""); ?>
<?php if ($TABLE == "" && !$_POST) { echo script("focus(gid('form')['name']);"); } ?>
<?php echo ($engines ? "<select name='Engine'>" . optionlist(array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . "</select>" . help_script_command("value", true) : ""); ?>
<?php echo ($collations && !preg_match("~sqlite|mssql~", $jush) ? html_select("Collation", array("" => "(" . lang('collation') . ")") + $collations, $row["Collation"]) : ""); ?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php } ?>
@@ -221,7 +221,7 @@ if (support("partitioning")) {
print_fieldset("partition", lang('Partition by'), $row["partition_by"]);
?>
<p>
<?php echo "<select name='partition_by'>" . optionlist(array("" => "") + $partition_by, $row["partition_by"]) . "</select>" . on_help("getTarget(event).value.replace(/./, 'PARTITION BY \$&')", 1) . script("qsl('select').onchange = partitionByChange;"); ?>
<?php echo "<select name='partition_by'>" . optionlist(array("" => "") + $partition_by, $row["partition_by"]) . "</select>" . help_script_command("value.replace(/./, 'PARTITION BY \$&')", true) . script("qsl('select').onchange = partitionByChange;"); ?>
(<input name="partition" value="<?php echo h($row["partition"]); ?>">)
<?php echo lang('Partitions'); ?>: <input type="number" name="partitions" class="size<?php echo ($partition_table || !$row["partition_by"] ? " hidden" : ""); ?>" value="<?php echo h($row["partitions"]); ?>">
<table cellspacing="0" id="partition-table"<?php echo ($partition_table ? "" : " class='hidden'"); ?>>

View File

@@ -66,7 +66,7 @@ echo ($_POST["add_x"] || strpos($name, "\n")
'mariadb' => "supported-character-sets-and-collations/",
'mssql' => "ms187963.aspx",
)) : "");
echo script("focus(qs('#name'));");
echo script("focus(gid('name'));");
?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php

View File

@@ -47,7 +47,28 @@ if ($tables_views && !$error && !$_POST["search"]) {
page_header(($_GET["ns"] == "" ? lang('Database') . ": " . h(DB) : lang('Schema') . ": " . h($_GET["ns"])), $error, true);
if ($adminer->homepage()) {
if ($_GET["ns"] !== "") {
if ($_GET["ns"] === "") {
echo "<h3 id='schemas'>" . lang('Schemas') . "</h3>\n";
$schemas = schemas();
if (!$schemas) {
echo "<p class='message'>" . lang('No schemas.') . "\n";
} else {
// TODO: Checkboxes for batch dropping of schemas.
echo "<div class='scrollable'>\n",
"<table class='nowrap'>\n",
'<thead><tr class="wrap">',
'<th>', lang('Schema'), "</th>",
'</tr></thead>';
foreach ($schemas as $name) {
echo "<tr", odd(), ">",
"<th><a href='", h(ME), "ns=" . urlencode($name), "' title='", lang('Show schema'), "'>" . h($name) . "</a></th>",
"</tr>";
}
echo '</table></div>';
}
} else {
echo "<h3 id='tables-views'>" . lang('Tables and views') . "</h3>\n";
$tables_list = tables_list();
if (!$tables_list) {
@@ -73,7 +94,7 @@ if ($adminer->homepage()) {
echo "<table cellspacing='0' class='nowrap checkable'>\n";
echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});");
echo '<thead><tr class="wrap">';
echo '<td><input id="check-all" type="checkbox" class="jsonly">' . script("qs('#check-all').onclick = partial(formCheck, /^(tables|views)\[/);", "");
echo '<td><input id="check-all" type="checkbox" class="jsonly">' . script("gid('check-all').onclick = partial(formCheck, /^(tables|views)\[/);", "");
echo '<th>' . lang('Table');
echo '<td>' . lang('Engine') . doc_link(array('sql' => 'storage-engines.html'));
echo '<td>' . lang('Collation') . doc_link(array('sql' => 'charset-charsets.html', 'mariadb' => 'supported-character-sets-and-collations/'));
@@ -126,17 +147,17 @@ if ($adminer->homepage()) {
echo "</div>\n";
if (!information_schema(DB)) {
echo "<div class='footer'><div>\n";
$vacuum = "<input type='submit' value='" . lang('Vacuum') . "'> " . on_help("'VACUUM'");
$optimize = "<input type='submit' name='optimize' value='" . lang('Optimize') . "'> " . on_help($jush == "sql" ? "'OPTIMIZE TABLE'" : "'VACUUM OPTIMIZE'");
$vacuum = "<input type='submit' value='" . lang('Vacuum') . "'> " . help_script("VACUUM");
$optimize = "<input type='submit' name='optimize' value='" . lang('Optimize') . "'> " . help_script($jush == "sql" ? "OPTIMIZE TABLE" : "VACUUM OPTIMIZE");
echo "<fieldset><legend>" . lang('Selected') . " <span id='selected'></span></legend><div>"
. ($jush == "sqlite" ? $vacuum
: ($jush == "pgsql" ? $vacuum . $optimize
: ($jush == "sql" ? "<input type='submit' value='" . lang('Analyze') . "'> " . on_help("'ANALYZE TABLE'") . $optimize
. "<input type='submit' name='check' value='" . lang('Check') . "'> " . on_help("'CHECK TABLE'")
. "<input type='submit' name='repair' value='" . lang('Repair') . "'> " . on_help("'REPAIR TABLE'")
: ($jush == "sql" ? "<input type='submit' value='" . lang('Analyze') . "'> " . help_script("ANALYZE TABLE") . $optimize
. "<input type='submit' name='check' value='" . lang('Check') . "'> " . help_script("CHECK TABLE")
. "<input type='submit' name='repair' value='" . lang('Repair') . "'> " . help_script("REPAIR TABLE")
: "")))
. "<input type='submit' name='truncate' value='" . lang('Truncate') . "'> " . on_help($jush == "sqlite" ? "'DELETE'" : "'TRUNCATE" . ($jush == "pgsql" ? "'" : " TABLE'")) . confirm()
. "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . on_help("'DROP TABLE'") . confirm() . "\n";
. "<input type='submit' name='truncate' value='" . lang('Truncate') . "'> " . help_script($jush == "sqlite" ? "DELETE" : ("TRUNCATE" . ($jush == "pgsql" ? "" : " TABLE"))) . confirm()
. "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . help_script("DROP TABLE") . confirm() . "\n";
$databases = (support("scheme") ? $adminer->schemas() : $adminer->databases());
if (count($databases) != 1 && $jush != "sqlite") {
$db = (isset($_POST["target"]) ? $_POST["target"] : (support("scheme") ? $_GET["ns"] : DB));
@@ -186,12 +207,16 @@ if ($adminer->homepage()) {
echo "<h3 id='sequences'>" . lang('Sequences') . "</h3>\n";
$sequences = get_vals("SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = current_schema() ORDER BY sequence_name");
if ($sequences) {
echo "<table>\n";
echo "<thead><tr><th>" . lang('Name') . "</thead>\n";
echo "<table>\n",
"<thead><tr><th>", lang('Name'), "</th><td></td></tr></thead>\n";
odd('');
foreach ($sequences as $val) {
echo "<tr" . odd() . "><th><a href='" . h(ME) . "sequence=" . urlencode($val) . "'>" . h($val) . "</a>\n";
echo "<tr", odd(), ">",
"<th>", h($val), "</th>",
"<td><a href='", h(ME), "sequence=", urlencode($val), "'>", lang('Alter'), "</a></td>\n";
}
echo "</table>\n";
}
echo "<p class='links'><a href='" . h(ME) . "sequence='>" . lang('Create sequence') . "</a>\n";
@@ -201,12 +226,16 @@ if ($adminer->homepage()) {
echo "<h3 id='user-types'>" . lang('User types') . "</h3>\n";
$user_types = types();
if ($user_types) {
echo "<table>\n";
echo "<thead><tr><th>" . lang('Name') . "</thead>\n";
echo "<table>\n",
"<thead><tr><th>", lang('Name'), "</th><td></td></tr></thead>\n";
odd('');
foreach ($user_types as $val) {
echo "<tr" . odd() . "><th><a href='" . h(ME) . "type=" . urlencode($val) . "'>" . h($val) . "</a>\n";
echo "<tr", odd(), ">",
"<th>", h($val), "</th>",
"<td><a href='", h(ME), "type=", urlencode($val), "'>", lang('Alter'), "</a></td>\n";
}
echo "</table>\n";
}
echo "<p class='links'><a href='" . h(ME) . "type='>" . lang('Create type') . "</a>\n";

View File

@@ -40,7 +40,8 @@ if (isset($_GET["mssql"])) {
}
function quote($string) {
return "'" . str_replace("'", "''", $string) . "'";
$unicode = strlen($string) != strlen(utf8_decode($string));
return ($unicode ? "N" : "") . "'" . str_replace("'", "''", $string) . "'";
}
function select_db($database) {
@@ -163,7 +164,8 @@ if (isset($_GET["mssql"])) {
}
function quote($string) {
return "'" . str_replace("'", "''", $string) . "'";
$unicode = strlen($string) != strlen(utf8_decode($string));
return ($unicode ? "N" : "") . "'" . str_replace("'", "''", $string) . "'";
}
function select_db($database) {

View File

@@ -500,11 +500,14 @@ if (!defined("DRIVER")) {
* @return array array($name => array("Name" => , "Engine" => , "Comment" => , "Oid" => , "Rows" => , "Collation" => , "Auto_increment" => , "Data_length" => , "Index_length" => , "Data_free" => )) or only inner array with $name
*/
function table_status($name = "", $fast = false) {
$return = array();
foreach (get_rows($fast && min_version(5)
? "SELECT TABLE_NAME AS Name, ENGINE AS Engine, CREATE_OPTIONS AS Create_options, TABLE_COMMENT AS Comment FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() " . ($name != "" ? "AND TABLE_NAME = " . q($name) : "ORDER BY Name")
: "SHOW TABLE STATUS" . ($name != "" ? " LIKE " . q(addcslashes($name, "%_\\")) : "")
) as $row) {
if ($fast && min_version(5)) {
$query = "SELECT TABLE_NAME AS Name, ENGINE AS Engine, CREATE_OPTIONS AS Create_options, TABLE_COMMENT AS Comment FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() " . ($name != "" ? "AND TABLE_NAME = " . q($name) : "ORDER BY Name");
} else {
$query = "SHOW TABLE STATUS" . ($name != "" ? " LIKE " . q(addcslashes($name, "%_\\")) : "");
}
$tables = [];
foreach (get_rows($query) as $row) {
if ($row["Engine"] == "InnoDB") {
// ignore internal comment, unnecessary since MySQL 5.1.21
$row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\1', $row["Comment"]);
@@ -513,11 +516,15 @@ if (!defined("DRIVER")) {
$row["Comment"] = "";
}
if ($name != "") {
// MariaDB: Table name is returned as lowercase on macOS, so we fix it here.
$row["Name"] = $name;
return $row;
}
$return[$row["Name"]] = $row;
$tables[$row["Name"]] = $row;
}
return $return;
return $tables;
}
/** Find out whether the identifier is view

View File

@@ -182,8 +182,8 @@ $prefixes = array();
if (DB != "") {
$checked = ($TABLE != "" ? "" : " checked");
echo "<thead><tr>";
echo "<th style='text-align: left;'><label class='block'><input type='checkbox' id='check-tables'$checked>" . lang('Tables') . "</label>" . script("qs('#check-tables').onclick = partial(formCheck, /^tables\\[/);", "");
echo "<th style='text-align: right;'><label class='block'>" . lang('Data') . "<input type='checkbox' id='check-data'$checked></label>" . script("qs('#check-data').onclick = partial(formCheck, /^data\\[/);", "");
echo "<th style='text-align: left;'><label class='block'><input type='checkbox' id='check-tables'$checked>" . lang('Tables') . "</label>" . script("gid('check-tables').onclick = partial(formCheck, /^tables\\[/);", "");
echo "<th style='text-align: right;'><label class='block'>" . lang('Data') . "<input type='checkbox' id='check-data'$checked></label>" . script("gid('check-data').onclick = partial(formCheck, /^data\\[/);", "");
echo "</thead>\n";
$views = "";
@@ -208,7 +208,7 @@ if (DB != "") {
} else {
echo "<thead><tr><th style='text-align: left;'>";
echo "<label class='block'><input type='checkbox' id='check-databases'" . ($TABLE == "" ? " checked" : "") . ">" . lang('Database') . "</label>";
echo script("qs('#check-databases').onclick = partial(formCheck, /^databases\\[/);", "");
echo script("gid('check-databases').onclick = partial(formCheck, /^databases\\[/);", "");
echo "</thead>\n";
$databases = $adminer->databases();
if ($databases) {

View File

@@ -129,7 +129,7 @@ class Adminer {
echo "<table cellspacing='0' class='layout'>\n";
echo $this->loginFormField('driver', '<tr><th>' . lang('System') . '<td>', html_select("auth[driver]", $drivers, DRIVER, "loginDriver(this);") . "\n");
echo $this->loginFormField('server', '<tr><th>' . lang('Server') . '<td>', '<input name="auth[server]" value="' . h(SERVER) . '" title="hostname[:port]" placeholder="localhost" autocapitalize="off">' . "\n");
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input name="auth[username]" id="username" value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("focus(qs('#username')); qs('#username').form['auth[driver]'].onchange();"));
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input name="auth[username]" id="username" value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("focus(gid('username')); gid('username').form['auth[driver]'].onchange();"));
echo $this->loginFormField('password', '<tr><th>' . lang('Password') . '<td>', '<input type="password" name="auth[password]" autocomplete="current-password">' . "\n");
echo $this->loginFormField('db', '<tr><th>' . lang('Database') . '<td>', '<input name="auth[db]" value="' . h($_GET["db"]) . '" autocapitalize="off">' . "\n");
echo "</table>\n";
@@ -424,8 +424,8 @@ class Adminer {
echo "<select name='columns[$i][fun]'>",
optionlist([-1 => ""] + array_filter([lang('Functions') => $functions, lang('Aggregation') => $grouping]), $val["fun"]),
"</select>",
on_help("getTarget(event).value && getTarget(event).value.replace(/ |\$/, '(') + ')'", 1),
script("qsl('select').onchange = (event) => { helpClose();" . ($key !== "" ? "" : " qsl('select, input:not(.remove)', event.target.parentNode).onchange();") . " };", ""),
help_script_command("value && value.replace(/ |\$/, '(') + ')'", true),
script("qsl('select').onchange = (event) => { " . ($key !== "" ? "" : " qsl('select, input:not(.remove)', event.target.parentNode).onchange();") . " };", ""),
"($column)";
} else {
echo $column;
@@ -557,7 +557,7 @@ class Adminer {
json_row($key);
}
echo ";\n";
echo "selectFieldChange.call(qs('#form')['select']);\n";
echo "selectFieldChange.call(gid('form')['select']);\n";
echo "</script>\n";
echo "</div></fieldset>\n";
}
@@ -1073,7 +1073,7 @@ class Adminer {
}
}
if ($output) {
echo "<ul id='logins'>\n$output</ul>\n" . script("mixin(qs('#logins'), {onmouseover: menuOver, onmouseout: menuOut});");
echo "<ul id='logins'>\n$output</ul>\n" . script("mixin(gid('logins'), {onmouseover: menuOver, onmouseout: menuOut});");
}
} else {
$tables = array();
@@ -1156,7 +1156,7 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
if ($databases) {
echo "<select id='database-select' name='db'>" . optionlist(["" => lang('Database')] + $databases, DB) . "</select>"
. script("mixin(qs('#database-select'), {onmousedown: dbMouseDown, onchange: dbChange});");
. script("mixin(gid('database-select'), {onmousedown: dbMouseDown, onchange: dbChange});");
} else {
echo "<input id='database-select' name='db' value='" . h(DB) . "' autocapitalize='off'>\n";
}
@@ -1164,7 +1164,7 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
if (support("scheme") && $missing != "db" && DB != "" && $connection->select_db(DB)) {
echo "<br><select id='scheme-select' name='ns'>" . optionlist(["" => lang('Schema')] + $adminer->schemas(), $_GET["ns"]) . "</select>"
. script("mixin(qs('#scheme-select'), {onmousedown: dbMouseDown, onchange: dbChange});");
. script("mixin(gid('scheme-select'), {onmousedown: dbMouseDown, onchange: dbChange});");
if ($_GET["ns"] != "") {
set_schema($_GET["ns"]);
@@ -1200,7 +1200,7 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
* @return null
*/
function tablesPrint($tables) {
echo "<ul id='tables'>" . script("mixin(qs('#tables'), {onmouseover: menuOver, onmouseout: menuOut});");
echo "<ul id='tables'>" . script("mixin(gid('tables'), {onmouseover: menuOver, onmouseout: menuOut});");
foreach ($tables as $table => $status) {
$name = $this->tableName($status);

View File

@@ -71,7 +71,7 @@ if (!function_exists('is_server_host_valid')) {
*/
function build_http_url($server, $username, $password, $defaultServer, $defaultPort = null) {
if (!preg_match('~^(https?://)?([^:]*)(:\d+)?$~', rtrim($server, '/'), $matches)) {
$this->error = lang('Invalid server or credentials.');
auth_error(lang('Invalid server or credentials.'));
return false;
}

View File

@@ -29,9 +29,9 @@ function page_header($title, $error = "", $breadcrumb = [], $title2 = "") {
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="robots" content="noindex">
<title><?php echo $title_page; ?></title>
<link rel="stylesheet" type="text/css" href="../adminer/static/default.css">
<?php echo script_src("../adminer/static/functions.js"); ?>
<?php echo script_src("static/editing.js"); ?>
<link rel="stylesheet" type="text/css" href="../adminer/static/default.css?<?php echo filemtime("../adminer/static/default.css"); ?>">
<?php echo script_src("../adminer/static/functions.js?" . filemtime("../adminer/static/functions.js")); ?>
<?php echo script_src("static/editing.js?" . filemtime("../adminer/static/editing.js")); ?>
<?php if ($adminer->head()) { ?>
<link rel="shortcut icon" type="image/x-icon" href="../adminer/static/favicon.ico">
<link rel="apple-touch-icon" href="../adminer/static/favicon.ico">
@@ -54,7 +54,7 @@ function page_header($title, $error = "", $breadcrumb = [], $title2 = "") {
</script>
<div id="help" class="jush-<?php echo $jush; ?> jsonly hidden"></div>
<?php echo script("mixin(qs('#help'), {onmouseover: function () { helpOpen = 1; }, onmouseout: helpMouseout});"); ?>
<?php echo script("initHelpPopup();"); ?>
<div id="content">
<?php

View File

@@ -297,7 +297,7 @@ function edit_fields(array $fields, array $collations, $type = "TABLE", $foreign
}
?>
<th id="label-name"><?php echo ($type == "TABLE" ? lang('Column name') : lang('Parameter name')); ?></th>
<td id="label-type"><?php echo lang('Type'); ?><textarea id="enum-edit" rows="4" cols="12" wrap="off" style="display: none;"></textarea><?php echo script("qs('#enum-edit').onblur = editingLengthBlur;"); ?></td>
<td id="label-type"><?php echo lang('Type'); ?><textarea id="enum-edit" rows="4" cols="12" wrap="off" style="display: none;"></textarea><?php echo script("gid('enum-edit').onblur = editingLengthBlur;"); ?></td>
<td id="label-length"><?php echo lang('Length'); ?></td>
<td><?php echo lang('Options'); /* no label required, options have their own label */ ?></td>
<?php if ($type == "TABLE") { ?>
@@ -621,7 +621,7 @@ function doc_link(array $paths, $text = "<sup>?</sup>") {
];
if (preg_match('~MariaDB~', $server_info)) {
$urls['sql'] = "https://mariadb.com/kb/en/library/";
$urls['sql'] = "https://mariadb.com/kb/en/";
$paths['sql'] = (isset($paths['mariadb']) ? $paths['mariadb'] : str_replace(".html", "/", $paths['sql']));
}

View File

@@ -967,7 +967,7 @@ function input($field, $value, $function) {
$has_function = (in_array($function, $functions) || isset($functions[$function]));
echo (count($functions) > 1
? "<select name='function[$name]' $disabled>" . optionlist($functions, $function === null || $has_function ? $function : "") . "</select>"
. on_help("getTarget(event).value.replace(/^SQL\$/, '')", 1)
. help_script_command("value.replace(/^SQL\$/, '')", true)
. script("qsl('select').onchange = functionChange;", "")
: h(reset($functions))
) . '<td>';
@@ -1486,13 +1486,26 @@ function lzw_decompress($binary) {
return $return;
}
/** Return events to display help on mouse over
* @param string JS expression
* @param bool JS expression
* @return string
*/
function on_help($command, $side = 0) {
return script("mixin(qsl('select, input'), {onmouseover: function (event) { helpMouseover.call(this, event, $command, $side) }, onmouseout: helpMouseout});", "");
/**
* @param string $text Help text.
* @param bool $side Side position.
*
* @return string
*/
function help_script($text, $side = false)
{
return script("initHelpFor(qsl('select, input'), '" . h($text) . "', $side);", "");
}
/**
* @param string $command JS expression for returning the help text.
* @param bool $side Side position.
*
* @return string
*/
function help_script_command($command, $side = false)
{
return script("initHelpFor(qsl('select, input'), (value) => { return $command; }, $side);", "");
}
/** Print edit data form
@@ -1586,7 +1599,7 @@ function edit_form($table, $fields, $row, $update) {
}
}
echo ($update ? "<input type='submit' name='delete' value='" . lang('Delete') . "'>" . confirm() . "\n"
: ($_POST || !$fields ? "" : script("focus(qsa('td', qs('#form'))[1].firstChild);"))
: ($_POST || !$fields ? "" : script("focus(qsa('td', gid('form'))[1].firstChild);"))
);
if (isset($_GET["select"])) {
hidden_fields(array("check" => (array) $_POST["check"], "clone" => $_POST["clone"], "all" => $_POST["all"]));

View File

@@ -1,2 +1,2 @@
<?php
$VERSION = "4.10";
$VERSION = "4.11";

View File

@@ -1,11 +1,14 @@
<?php
/** Adminer - Compact database management
* @link https://www.adminer.org/
* @author Jakub Vrana, https://www.vrana.cz/
* @copyright 2007 Jakub Vrana
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
/**
* Adminer - Database management in a single PHP file
*
* @link https://github.com/pematon/adminer
* @author Jakub Vrana (https://www.vrana.cz/)
* @author Peter Knut
* @copyright 2007-2021 Jakub Vrana, 2024 Peter Knut
* @license Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
* @license GNU General Public License, version 2 (https://www.gnu.org/licenses/gpl-2.0.html)
*/
include "./include/bootstrap.inc.php";
include "./include/tmpfile.inc.php";

View File

@@ -259,8 +259,8 @@ $translations = array(
'%d row(s)' => array('%d řádek', '%d řádky', '%d řádků'),
'Page' => 'Stránka',
'last' => 'poslední',
'Load more data' => 'Nahrát další data',
'Loading' => 'Nahrává se',
'Load more data' => 'Načíst další data',
'Loading' => 'Načítá se',
'Whole result' => 'Celý výsledek',
'%d byte(s)' => array('%d bajt', '%d bajty', '%d bajtů'),

View File

@@ -277,8 +277,8 @@ $translations = array(
'DB' => 'DB',
'File must be in UTF-8 encoding.' => 'Súbor musí byť v kódovaní UTF-8.',
'Modify' => 'Zmeniť',
'Load more data' => 'Nahráť ďalšie dáta',
'Loading' => 'Nahráva sa',
'Load more data' => 'Načítať ďalšie dáta',
'Loading' => 'Načítava sa',
'ATTACH queries are not supported.' => 'Dotazy ATTACH nie sú podporované.',
'Warnings' => 'Varovania',
'%d / ' => '%d / ',

View File

@@ -39,12 +39,16 @@ $routine_languages = routine_languages();
<?php echo ($routine_languages ? lang('Language') . ": " . html_select("language", $routine_languages, $row["language"]) . "\n" : ""); ?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<div class="scrollable">
<table cellspacing="0" class="nowrap">
<table cellspacing="0" class="nowrap" id="edit-fields">
<?php
edit_fields($row["fields"], $collations, $routine);
if (isset($_GET["function"])) {
echo "<tr><td>" . lang('Return type');
echo "<tbody><tr><th></th>",
"<th>", lang('Return type'), "</th>";
edit_type("returns", $row["returns"], $collations, array(), ($jush == "pgsql" ? array("void", "trigger") : array()));
echo "<td></td></tr></tbody>\n";
}
?>
</table>

View File

@@ -50,9 +50,9 @@ foreach (table_status('', true) as $table => $table_status) {
?>
<div id="schema" style="height: <?php echo $top; ?>em;">
<script<?php echo nonce(); ?>>
qs('#schema').onselectstart = function () { return false; };
gid('schema').onselectstart = function () { return false; };
var tablePos = {<?php echo implode(",", $table_pos_js) . "\n"; ?>};
var em = qs('#schema').offsetHeight / <?php echo $top; ?>;
var em = gid('schema').offsetHeight / <?php echo $top; ?>;
document.onmousemove = schemaMousemove;
document.onmouseup = partialArg(schemaMouseup, '<?php echo js_escape(DB); ?>');
</script>
@@ -61,12 +61,12 @@ foreach ($schema as $name => $table) {
echo "<div class='table' style='top: " . $table["pos"][0] . "em; left: " . $table["pos"][1] . "em;'>";
echo '<a href="' . h(ME) . 'table=' . urlencode($name) . '"><b>' . h($name) . "</b></a>";
echo script("qsl('div').onmousedown = schemaMousedown;");
foreach ($table["fields"] as $field) {
$val = '<span' . type_class($field["type"]) . ' title="' . h($field["full_type"] . ($field["null"] ? " NULL" : '')) . '">' . h($field["field"]) . '</span>';
echo "<br>" . ($field["primary"] ? "<i>$val</i>" : $val);
}
foreach ((array) $table["references"] as $target_name => $refs) {
foreach ($refs as $left => $ref) {
$left1 = $left - $table_pos[$name][1];
@@ -76,7 +76,7 @@ foreach ($schema as $name => $table) {
}
}
}
foreach ((array) $referenced[$name] as $target_name => $refs) {
foreach ($refs as $left => $columns) {
$left1 = $left - $table_pos[$name][1];
@@ -86,7 +86,7 @@ foreach ($schema as $name => $table) {
}
}
}
echo "\n</div>\n";
}

View File

@@ -27,7 +27,7 @@ if (!$row) {
<form action="" method="post">
<p><input name="name" id="name" value="<?php echo h($row["name"]); ?>" autocapitalize="off">
<?php echo script("focus(qs('#name'));"); ?>
<?php echo script("focus(gid('name'));"); ?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php
if ($_GET["ns"] != "") {

View File

@@ -322,10 +322,10 @@ if (!$columns && support("table")) {
echo "<div class='scrollable'>";
echo "<table id='table' cellspacing='0' class='nowrap checkable'>";
echo script("mixin(qs('#table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true), onkeydown: editingKeydown});");
echo script("mixin(gid('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true), onkeydown: editingKeydown});");
echo "<thead><tr>" . (!$group && $select
? ""
: "<td><input type='checkbox' id='all-page' class='jsonly'>" . script("qs('#all-page').onclick = partial(formCheck, /check/);", "")
: "<td><input type='checkbox' id='all-page' class='jsonly'>" . script("gid('all-page').onclick = partial(formCheck, /check/);", "")
. " <a href='" . h($_GET["modify"] ? remove_from_uri("modify") : $_SERVER["REQUEST_URI"] . "&modify=1") . "'>" . lang('Modify') . "</a>");
$names = array();
$functions = array();
@@ -353,10 +353,10 @@ if (!$columns && support("table")) {
}
echo "<span class='column hidden'>";
if ($sortable) {
echo "<a href='" . h($href . $desc) . "' title='" . lang('descending') . "' class='text'> ↓</a>";
echo "<a href='" . h($href . $desc) . "' title='" . lang('descending') . "' class='text'> ↓</a>";
}
if (!$val["fun"] && isset($field["privileges"]["where"])) {
echo '<a href="#fieldset-search" title="' . lang('Search') . '" class="text jsonly"> =</a>';
echo '<a href="#fieldset-search" title="' . lang('Search') . '" class="text jsonly"> =</a>';
echo script("qsl('a').onclick = partial(selectSearch, '" . js_escape($key) . "');");
}
echo "</span>";

View File

@@ -243,7 +243,7 @@ if (!isset($_GET["import"])) {
}
echo "<p>";
textarea("query", $q, 20);
echo script(($_POST ? "" : "qs('textarea').focus();\n") . "qs('#form').onsubmit = partial(sqlSubmit, qs('#form'), '" . js_escape(remove_from_uri("sql|limit|error_stops|only_errors|history")) . "');");
echo script(($_POST ? "" : "qs('textarea').focus();\n") . "gid('form').onsubmit = partial(sqlSubmit, gid('form'), '" . js_escape(remove_from_uri("sql|limit|error_stops|only_errors|history")) . "');");
echo "<p>$execute\n";
echo lang('Limit rows') . ": <input type='number' name='limit' class='size' value='" . h($_POST ? $_POST["limit"] : $_GET["limit"]) . "'>\n";

View File

@@ -1,7 +1,7 @@
/** @author Ondrej Valka, http://valka.info */
body { color: #000; background: #fff; font: 90%/1.25 Verdana, Arial, Helvetica, sans-serif; margin: 0; width: -moz-fit-content; width: fit-content; }
a { color: blue; text-decoration: none; }
a:hover { color: red; text-decoration: underline; }
a:link:hover { color: red; text-decoration: underline; }
a.text:hover { text-decoration: none; }
a.jush-help:hover { color: inherit; }
h1 { font-size: 150%; margin: 0; padding: .8em 1em; border-bottom: 1px solid #999; font-weight: normal; color: #777; background: #eee; }
@@ -25,7 +25,7 @@ pre code { display: block; font-size: 100%; }
pre, textarea { font: 110%/1.25 monospace; }
pre.jush { background: #fff; }
input, textarea, select { box-sizing: border-box; }
input:not([type="radio"]), select { vertical-align: middle; }
input[type="image"] { vertical-align: middle; margin-top: -3px; }
input[type="number"] { -moz-appearance: textfield; }
input::-webkit-inner-spin-button { -webkit-appearance: none; }
input.default { box-shadow: 1px 1px 1px #777; }
@@ -76,7 +76,8 @@ p.nowrap { white-space: pre; }
.handle:before { content: "="; display: inline-block; width: 18px; height: 18px; overflow: hidden; font-size: 130%; text-align: center; line-height: 16px; opacity: 0.2; }
span.handle { display: inline-block; width: 18px; height: 18px; padding-right: .3em; }
th.handle:before { vertical-align: middle; }
.no-sort .handle { cursor: default; opacity: 0; }
.no-sort .handle { cursor: default; }
.no-sort .handle:before { content: "•"; font-size: 100%; }
.placeholder { opacity: 0; }
.dragging { position: absolute; margin: 0; background: #fff; }
.dragging * { cursor: grabbing; }

View File

@@ -16,17 +16,22 @@ function bodyLoad(version, maria) {
if (maria) {
for (var i = 1; i < obj.length; i++) {
obj[i] = obj[i]
.replace(/\.html/, '/')
.replace(/-type-syntax/, '-data-types')
.replace('.html', '/')
.replace('-type-syntax', '-data-types')
.replace(/numeric-(data-types)/, '$1-$&')
.replace(/#statvar_.*/, '#$$1')
.replace(/replication-options-(master|binary-log)\//, 'replication-and-binary-log-system-variables/')
.replace('server-options/', 'server-system-variables/')
.replace('innodb-parameters/', 'innodb-system-variables/')
.replace(/#(statvar|sysvar|option_mysqld)_(.*)/, '#$2')
.replace(/#sysvar_(.*)/, '#$1')
;
}
}
}
obj[key] = (maria ? obj[key].replace(/dev\.mysql\.com\/doc\/mysql\/en\//, 'mariadb.com/kb/en/library/') : obj[key]) // MariaDB
.replace(/\/doc\/mysql/, '/doc/refman/' + version) // MySQL
.replace(/\/docs\/current/, '/docs/' + version) // PostgreSQL
obj[key] = (maria ? obj[key].replace('dev.mysql.com/doc/mysql/en/', 'mariadb.com/kb/en/') : obj[key]) // MariaDB
.replace('/doc/mysql/', '/doc/refman/' + version) // MySQL
.replace('/docs/current/', '/docs/' + version) // PostgreSQL
;
}
}
@@ -83,13 +88,17 @@ function messagesPrint(el) {
/** Hide or show some login rows for selected driver
* @param HTMLSelectElement
*/
function loginDriver(driver) {
var trs = parentTag(driver, 'table').rows;
var disabled = /sqlite/.test(selectValue(driver));
alterClass(trs[1], 'hidden', disabled); // 1 - row with server
/**
* Hides or shows some login rows for selected driver.
*
* @param {HTMLSelectElement} driverSelect
*/
function loginDriver(driverSelect) {
const trs = parentTag(driverSelect, 'table').rows;
const disabled = /sqlite/.test(selectValue(driverSelect));
// 1 - row with server
trs[1].classList.toggle('hidden', disabled);
trs[1].getElementsByTagName('input')[0].disabled = disabled;
}
@@ -231,11 +240,13 @@ function editFields() {
els = qsa('[name$="[type]"]');
for (var i = 0; i < els.length; i++) {
mixin(els[i], {
onfocus: function () { lastType = selectValue(this); },
onfocus: () => {
lastType = selectValue(this);
},
onchange: editingTypeChange,
onmouseover: function (event) { helpMouseover.call(this, event, getTarget(event).value, 1) },
onmouseout: helpMouseout
});
initHelpFor(els[i], (value) => { return value; }, true);
}
}
@@ -244,7 +255,7 @@ function editFields() {
* @return boolean false to cancel action
*/
function editingClick(event) {
var el = getTarget(event);
var el = event.target;
if (!isTag(el, 'input')) {
el = parentTag(el, 'label');
el = el && qs('input', el);
@@ -273,7 +284,7 @@ function editingClick(event) {
* @param InputEvent
*/
function editingInput(event) {
var el = getTarget(event);
var el = event.target;
if (/\[default]$/.test(el.name)) {
el.previousSibling.checked = true;
}
@@ -398,26 +409,26 @@ function editingTypeChange() {
el.checked = false;
}
if (el.name === name + '[collation]') {
alterClass(el, 'hidden', !/(char|text|enum|set)$/.test(text));
el.classList.toggle('hidden', !/(char|text|enum|set)$/.test(text));
}
if (el.name === name + '[unsigned]') {
alterClass(el, 'hidden', !/(^|[^o])int(?!er)|numeric|real|float|double|decimal|money/.test(text));
el.classList.toggle('hidden', !/(^|[^o])int(?!er)|numeric|real|float|double|decimal|money/.test(text));
}
if (el.name === name + '[on_update]') {
alterClass(el, 'hidden', !/timestamp|datetime/.test(text)); // MySQL supports datetime since 5.6.5
// MySQL supports datetime since 5.6.5.
el.classList.toggle('hidden', !/timestamp|datetime/.test(text));
}
if (el.name === name + '[on_delete]') {
alterClass(el, 'hidden', !/`/.test(text));
el.classList.toggle('hidden', !/`/.test(text));
}
}
helpClose();
}
/** Mark length as required
* @this HTMLInputElement
*/
function editingLengthChange() {
alterClass(this, 'required', !this.value.length && /var(char|binary)$/.test(selectValue(this.parentNode.previousSibling.firstChild)));
this.classList.toggle('required', !this.value.length && /var(char|binary)$/.test(selectValue(this.parentNode.previousSibling.firstChild)));
}
/** Edit enum or set
@@ -426,7 +437,7 @@ function editingLengthChange() {
function editingLengthFocus() {
var td = this.parentNode;
if (/(enum|set)$/.test(selectValue(td.previousSibling.firstChild))) {
var edit = qs('#enum-edit');
var edit = gid('enum-edit');
edit.value = enumValues(this.value);
td.appendChild(edit);
this.style.display = 'none';
@@ -470,9 +481,9 @@ function editingLengthBlur() {
* @param number
*/
function columnShow(checked, column) {
var trs = qsa('tr', qs('#edit-fields'));
var trs = qsa('tr', gid('edit-fields'));
for (var i=0; i < trs.length; i++) {
alterClass(qsa('td', trs[i])[column], 'hidden', !checked);
qsa('td', trs[i])[column].classList.toggle('hidden', !checked);
}
}
@@ -481,9 +492,9 @@ function columnShow(checked, column) {
*/
function partitionByChange() {
var partitionTable = /RANGE|LIST/.test(selectValue(this));
alterClass(this.form['partitions'], 'hidden', partitionTable || !this.selectedIndex);
alterClass(qs('#partition-table'), 'hidden', !partitionTable);
helpClose();
this.form['partitions'].classList.toggle('hidden', partitionTable || !this.selectedIndex);
gid('partition-table').classList.toggle('hidden', !partitionTable);
}
/** Add next partition row
@@ -503,7 +514,7 @@ function partitionNameChange() {
function editingCommentsClick(el, focus) {
var comment = el.form['Comment'];
columnShow(el.checked, 6);
alterClass(comment, 'hidden', !el.checked);
comment.classList.toggle('hidden', !el.checked);
if (focus && el.checked) {
comment.focus();
}
@@ -516,7 +527,7 @@ function editingCommentsClick(el, focus) {
* @this HTMLTableElement
*/
function dumpClick(event) {
var el = parentTag(getTarget(event), 'label');
var el = parentTag(event.target, 'label');
if (el) {
el = qs('input', el);
var match = /(.+)\[]$/.exec(el.name);
@@ -646,7 +657,7 @@ function triggerChange(tableRe, table, form) {
if (tableRe.test(form['Trigger'].value)) {
form['Trigger'].value = table + '_' + (selectValue(form['Timing']).charAt(0) + formEvent.charAt(0)).toLowerCase();
}
alterClass(form['Of'], 'hidden', !/ OF/.test(formEvent));
form['Of'].classList.toggle('hidden', !/ OF/.test(formEvent));
}
@@ -720,55 +731,114 @@ function schemaMouseup(event, db) {
s += '_' + key + ':' + Math.round(tablePos[key][0] * 10000) / 10000 + 'x' + Math.round(tablePos[key][1] * 10000) / 10000;
}
s = encodeURIComponent(s.substr(1));
var link = qs('#schema-link');
var link = gid('schema-link');
link.href = link.href.replace(/[^=]+$/, '') + s;
cookie('adminer_schema-' + db + '=' + s, 30); //! special chars in db
}
}
// Help.
(function() {
let openTimeout = null;
let closeTimeout = null;
let helpVisible = false;
var helpOpen, helpIgnore; // when mouse outs <option> then it mouse overs border of <select> - ignore it
window.initHelpPopup = function () {
const help = gid("help");
/** Display help
* @param MouseEvent
* @param string
* @param bool display on left side (otherwise on top)
* @this HTMLElement
*/
function helpMouseover(event, text, side) {
var target = getTarget(event);
if (!text) {
helpClose();
} else if (window.jush && (!helpIgnore || this !== target)) {
helpOpen = 1;
var help = qs('#help');
help.innerHTML = text;
jush.highlight_tag([ help ]);
alterClass(help, 'hidden');
var rect = target.getBoundingClientRect();
var body = document.documentElement;
help.style.top = (body.scrollTop + rect.top - (side ? (help.offsetHeight - target.offsetHeight) / 2 : help.offsetHeight)) + 'px';
help.style.left = (body.scrollLeft + rect.left - (side ? help.offsetWidth : (help.offsetWidth - target.offsetWidth) / 2)) + 'px';
}
}
help.addEventListener("mouseenter", () => {
clearTimeout(closeTimeout);
closeTimeout = null;
});
/** Close help after timeout
* @param MouseEvent
* @this HTMLElement
*/
function helpMouseout(event) {
helpOpen = 0;
helpIgnore = (this !== getTarget(event));
setTimeout(function () {
if (!helpOpen) {
helpClose();
help.addEventListener("mouseleave", hideHelp);
};
/**
* @param {HTMLElement} element
* @param {string|function} content
* @param {boolean} side Displays on left side (otherwise on top).
*/
window.initHelpFor = function(element, content, side = false) {
const withCallback = typeof content === "function";
element.addEventListener("mouseenter", (event) => {
showHelp(event.target, withCallback ? content(event.target.value) : content, side)
});
element.addEventListener("mouseleave", hideHelp);
element.addEventListener("blur", hideHelp);
if (withCallback) {
element.addEventListener("change", hideHelp);
}
}, 200);
}
};
/** Close help
*/
function helpClose() {
alterClass(qs('#help'), 'hidden', true);
}
/**
* Displays help popup after a small delay.
*
* @param {HTMLElement} element
* @param {string} text
* @param {boolean} side display on left side (otherwise on top)
*/
function showHelp(element, text, side) {
if (!text) {
hideHelp();
return;
}
if (isSorting() || !window.jush) {
return;
}
clearTimeout(openTimeout);
openTimeout = null;
clearTimeout(closeTimeout);
closeTimeout = null;
const help = gid("help");
help.innerHTML = text;
jush.highlight_tag([help]);
// Display help briefly to calculate position properly.
help.classList.remove("hidden");
const rect = element.getBoundingClientRect();
const root = document.documentElement;
help.style.top = (root.scrollTop + rect.top - (side ? (help.offsetHeight - element.offsetHeight) / 2 : help.offsetHeight)) + 'px';
help.style.left = (root.scrollLeft + rect.left - (side ? help.offsetWidth : (help.offsetWidth - element.offsetWidth) / 2)) + 'px';
if (helpVisible) {
return;
}
help.classList.add("hidden");
openTimeout = setTimeout(() => {
gid("help").classList.remove("hidden");
helpVisible = true;
openTimeout = null;
}, 600);
}
/**
* Closes the help popup after a small delay.
*/
function hideHelp() {
if (openTimeout) {
clearTimeout(openTimeout);
openTimeout = null;
return;
}
closeTimeout = setTimeout(() => {
gid("help").classList.add("hidden");
helpVisible = false;
closeTimeout = null;
}, 200);
}
})();

View File

@@ -73,17 +73,6 @@ function mixin(target, source) {
}
}
/** Add or remove CSS class
* @param HTMLElement
* @param string
* @param [bool]
*/
function alterClass(el, className, enable) {
if (el) {
el.className = el.className.replace(RegExp('(^|\\s)' + className + '(\\s|$)'), '$2') + (enable ? ' ' + className : '');
}
}
/**
* Toggles visibility of element with ID.
*
@@ -129,7 +118,7 @@ function verifyVersion(currentVersion, baseUrl, token) {
ajax(baseUrl + 'script=version', function () {}, data);
if (currentVersion !== version) {
qs('#version').innerText = version;
gid('version').innerText = version;
}
});
}
@@ -173,7 +162,7 @@ function parentTag(el, tag) {
*/
function trCheck(el) {
var tr = parentTag(el, 'tr');
alterClass(tr, 'checked', el.checked);
tr.classList.toggle('checked', el.checked);
if (el.form && el.form['all'] && el.form['all'].onclick) { // Opera treats form.all as document.all
el.form['all'].onclick();
}
@@ -186,7 +175,7 @@ function trCheck(el) {
*/
function selectCount(id, count) {
setHtml(id, (count === '' ? '' : '(' + (count + '').replace(/\B(?=(\d{3})+$)/g, thousandsSeparator) + ')'));
var el = qs('#' + id);
var el = gid(id);
if (el) {
var inputs = qsa('input', el.parentNode.parentNode);
for (var i = 0; i < inputs.length; i++) {
@@ -259,7 +248,7 @@ function formChecked(el, name) {
* @param [boolean] force click
*/
function tableClick(event, click) {
var td = parentTag(getTarget(event), 'td');
var td = parentTag(event.target, 'td');
var text;
if (td && (text = td.getAttribute('data-text'))) {
if (selectClick.call(td, event, +text, td.getAttribute('data-warning'))) {
@@ -267,7 +256,7 @@ function tableClick(event, click) {
}
}
click = (click || !window.getSelection || getSelection().isCollapsed);
var el = getTarget(event);
var el = event.target;
while (!isTag(el, 'tr')) {
if (isTag(el, 'table|a|input|textarea')) {
if (el.type !== 'checkbox') {
@@ -374,7 +363,7 @@ 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');
gid('tables-filter').value = sessionStorage.getItem('adminer_tables_filter');
filterTables();
} else {
sessionStorage.removeItem('adminer_tables_filter');
@@ -384,7 +373,7 @@ function initTablesFilter(dbName) {
});
}
const filterInput = qs('#tables-filter');
const filterInput = gid('tables-filter');
filterInput.addEventListener('input', function () {
window.clearTimeout(tablesFilterTimeout);
tablesFilterTimeout = window.setTimeout(filterTables, 200);
@@ -401,7 +390,7 @@ function initTablesFilter(dbName) {
}
function filterTables() {
const value = qs('#tables-filter').value.toLowerCase();
const value = gid('tables-filter').value.toLowerCase();
if (value === tablesFilterValue) {
return;
}
@@ -445,7 +434,7 @@ function filterTables() {
* @this HTMLElement
*/
function menuOver(event) {
var a = getTarget(event);
var a = event.target;
if (isTag(a, 'a|span') && a.offsetLeft + a.offsetWidth > a.parentNode.offsetWidth - 15) { // 15 - ellipsis
this.style.overflow = 'visible';
}
@@ -544,13 +533,13 @@ function selectSearchSearch() {
// Sorting.
(function() {
let placeholderRow, nextRow, dragHelper;
let placeholderRow = null, nextRow = null, dragHelper = null;
let startY, minY, maxY;
/**
* Initializes sortable list of DIV elements.
*
* @param {string} parentId
* @param {string} parentSelector
*/
window.initSortable = function(parentSelector) {
const parent = qs(parentSelector);
@@ -572,65 +561,73 @@ function selectSearchSearch() {
row.classList.remove("no-sort");
const handle = qs(".handle", row);
handle.addEventListener("mousedown", (event) => {
event.preventDefault();
const parent = row.parentNode;
startY = event.clientY - getOffsetTop(row);
minY = getOffsetTop(parent);
maxY = minY + parent.offsetHeight - row.offsetHeight;
placeholderRow = row.cloneNode(true);
placeholderRow.classList.add("placeholder");
parent.insertBefore(placeholderRow, row);
nextRow = row.nextElementSibling;
let top = event.clientY - startY;
let left = getOffsetLeft(row);
let width = row.getBoundingClientRect().width;
if (row.tagName === "TR") {
const firstChild = row.firstElementChild;
const borderWidth = (firstChild.offsetWidth - firstChild.clientWidth) / 2;
const borderHeight = (firstChild.offsetHeight - firstChild.clientHeight) / 2;
minY -= borderHeight;
maxY -= borderHeight;
top -= borderHeight;
left -= borderWidth;
width += 2 * borderWidth;
for (const child of row.children) {
child.style.width = child.getBoundingClientRect().width + "px";
}
dragHelper = document.createElement("table");
dragHelper.appendChild(row);
} else {
dragHelper = row;
}
dragHelper.style.top = `${top}px`;
dragHelper.style.left = `${left}px`;
dragHelper.style.width = `${width}px`;
dragHelper.classList.add("dragging");
document.body.appendChild(dragHelper);
window.addEventListener("mousemove", updateSorting);
window.addEventListener("mouseup", () => {
dragHelper.classList.remove("dragging");
parent.insertBefore(dragHelper.tagName === "TABLE" ? dragHelper.firstChild : dragHelper, placeholderRow);
placeholderRow.remove();
window.removeEventListener("mousemove", updateSorting);
}, { once: true });
});
handle.addEventListener("mousedown", (event) => { startSorting(row, event) });
handle.addEventListener("touchstart", (event) => { startSorting(row, event) });
};
window.isSorting = function () {
return dragHelper !== null;
};
function startSorting(row, event) {
event.preventDefault();
const pointerY = getPointerY(event);
const parent = row.parentNode;
startY = pointerY - getOffsetTop(row);
minY = getOffsetTop(parent);
maxY = minY + parent.offsetHeight - row.offsetHeight;
placeholderRow = row.cloneNode(true);
placeholderRow.classList.add("placeholder");
parent.insertBefore(placeholderRow, row);
nextRow = row.nextElementSibling;
let top = pointerY - startY;
let left = getOffsetLeft(row);
let width = row.getBoundingClientRect().width;
if (row.tagName === "TR") {
const firstChild = row.firstElementChild;
const borderWidth = (firstChild.offsetWidth - firstChild.clientWidth) / 2;
const borderHeight = (firstChild.offsetHeight - firstChild.clientHeight) / 2;
minY -= borderHeight;
maxY -= borderHeight;
top -= borderHeight;
left -= borderWidth;
width += 2 * borderWidth;
for (const child of row.children) {
child.style.width = child.getBoundingClientRect().width + "px";
}
dragHelper = document.createElement("table");
dragHelper.appendChild(row);
} else {
dragHelper = row;
}
dragHelper.style.top = `${top}px`;
dragHelper.style.left = `${left}px`;
dragHelper.style.width = `${width}px`;
dragHelper.classList.add("dragging");
document.body.appendChild(dragHelper);
window.addEventListener("mousemove", updateSorting);
window.addEventListener("touchmove", updateSorting);
window.addEventListener("mouseup", finishSorting);
window.addEventListener("touchend", finishSorting);
window.addEventListener("touchcancel", finishSorting);
}
function updateSorting(event) {
let top = Math.min(Math.max(event.clientY - startY, minY), maxY);
const pointerY = getPointerY(event);
let top = Math.min(Math.max(pointerY - startY, minY), maxY);
dragHelper.style.top = `${top}px`;
const parent = placeholderRow.parentNode;
@@ -656,6 +653,34 @@ function selectSearchSearch() {
}
}
}
function finishSorting() {
dragHelper.classList.remove("dragging");
dragHelper.style.top = null;
dragHelper.style.left = null;
dragHelper.style.width = null;
placeholderRow.parentNode.insertBefore(dragHelper.tagName === "TABLE" ? dragHelper.firstChild : dragHelper, placeholderRow);
placeholderRow.remove();
placeholderRow = nextRow = dragHelper = null;
window.removeEventListener("mousemove", updateSorting);
window.removeEventListener("touchmove", updateSorting);
window.removeEventListener("mouseup", finishSorting);
window.removeEventListener("touchend", finishSorting);
window.removeEventListener("touchcancel", finishSorting);
}
function getPointerY(event) {
if (event.type.includes("touch")) {
const touch = event.touches[0] || event.changedTouches[0];
return touch.clientY;
} else {
return event.clientY;
}
}
})();
@@ -681,7 +706,7 @@ function columnMouse(className) {
* @return boolean false
*/
function selectSearch(name) {
var el = qs('#fieldset-search');
var el = gid('fieldset-search');
el.className = '';
var divs = qsa('div', el);
for (var i=0; i < divs.length; i++) {
@@ -708,16 +733,6 @@ function isCtrl(event) {
return (event.ctrlKey || event.metaKey) && !event.altKey; // shiftKey allowed
}
/** Return event target
* @param Event
* @return HTMLElement
*/
function getTarget(event) {
return event.target || event.srcElement;
}
/** Send form by Ctrl+Enter on <select> and <textarea>
* @param KeyboardEvent
* @param [string]
@@ -725,7 +740,7 @@ function getTarget(event) {
*/
function bodyKeydown(event, button) {
eventStop(event);
var target = getTarget(event);
var target = event.target;
if (target.jushTextarea) {
target = target.jushTextarea;
}
@@ -749,7 +764,7 @@ function bodyKeydown(event, button) {
* @param MouseEvent
*/
function bodyClick(event) {
var target = getTarget(event);
var target = event.target;
if ((isCtrl(event) || event.shiftKey) && target.type === 'submit' && isTag(target, 'input')) {
target.form.target = '_blank';
setTimeout(function () {
@@ -767,7 +782,7 @@ function bodyClick(event) {
*/
function editingKeydown(event) {
if ((event.keyCode === 40 || event.keyCode === 38) && isCtrl(event)) { // 40 - Down, 38 - Up
var target = getTarget(event);
var target = event.target;
var sibling = (event.keyCode === 40 ? 'nextSibling' : 'previousSibling');
var el = target.parentNode.parentNode[sibling];
if (el && (isTag(el, 'tr') || (el = el[sibling])) && isTag(el, 'tr') && (el = el.childNodes[nodePosition(target.parentNode)]) && (el = el.childNodes[nodePosition(target)])) {
@@ -792,7 +807,6 @@ function functionChange() {
// Undefined with the set data type.
if (!input) {
helpClose();
return;
}
@@ -822,8 +836,6 @@ function functionChange() {
}
oninput({target: input});
helpClose();
}
/**
@@ -868,7 +880,7 @@ function fieldChange() {
function ajax(url, callback, data, message) {
var request = (window.XMLHttpRequest ? new XMLHttpRequest() : (window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : false));
if (request) {
var ajaxStatus = qs('#ajaxstatus');
var ajaxStatus = gid('ajaxstatus');
if (message) {
ajaxStatus.innerHTML = '<div class="message">' + message + '</div>';
ajaxStatus.className = ajaxStatus.className.replace(/ hidden/g, '');
@@ -938,9 +950,9 @@ function ajaxForm(form, message, button) {
return ajax(url, function (request) {
setHtml('ajaxstatus', request.responseText);
if (window.jush) {
jush.highlight_tag(qsa('code', qs('#ajaxstatus')), 0);
jush.highlight_tag(qsa('code', gid('ajaxstatus')), 0);
}
messagesPrint(qs('#ajaxstatus'));
messagesPrint(gid('ajaxstatus'));
}, data, message);
}
@@ -955,7 +967,7 @@ function ajaxForm(form, message, button) {
*/
function selectClick(event, text, warning) {
var td = this;
var target = getTarget(event);
var target = event.target;
if (!isCtrl(event) || isTag(td.firstChild, 'input|textarea') || isTag(target, 'a')) {
return;
}
@@ -1042,7 +1054,7 @@ function selectLoadMore(limit, loading) {
return !ajax(href, function (request) {
var tbody = document.createElement('tbody');
tbody.innerHTML = request.responseText;
qs('#table').appendChild(tbody);
gid('table').appendChild(tbody);
if (tbody.children.length < limit) {
a.parentNode.removeChild(a);
} else {
@@ -1096,9 +1108,9 @@ function setupSubmitHighlightInput(input) {
* @this HTMLInputElement
*/
function inputFocus() {
var submit = findDefaultSubmit(this);
const submit = findDefaultSubmit(this);
if (submit) {
alterClass(submit, 'default', true);
submit.classList.toggle('default', true);
}
}
@@ -1106,9 +1118,9 @@ function inputFocus() {
* @this HTMLInputElement
*/
function inputBlur() {
var submit = findDefaultSubmit(this);
const submit = findDefaultSubmit(this);
if (submit) {
alterClass(submit, 'default');
submit.classList.toggle('default', false);
}
}
@@ -1190,7 +1202,9 @@ function getOffsetLeft(element) {
}
oninput = function (event) {
var target = event.target;
var maxLength = target.getAttribute('data-maxlength');
alterClass(target, 'maxlength', target.value && maxLength != null && target.value.length > maxLength); // maxLength could be 0
const target = event.target;
const maxLength = target.getAttribute('data-maxlength');
// maxLength could be 0
target.classList.toggle('maxlength', target.value && maxLength != null && target.value.length > maxLength);
};

View File

@@ -40,7 +40,7 @@ page_header(($name != "" ? lang('Alter trigger') . ": " . h($name) : lang('Creat
<tr><th><?php echo lang('Type'); ?><td><?php echo html_select("Type", $trigger_options["Type"], $row["Type"]); ?>
</table>
<p><?php echo lang('Name'); ?>: <input name="Trigger" value="<?php echo h($row["Trigger"]); ?>" data-maxlength="64" autocapitalize="off">
<?php echo script("qs('#form')['Timing'].onchange();"); ?>
<?php echo script("gid('form')['Timing'].onchange();"); ?>
<p><?php textarea("Statement", $row["Statement"]); ?>
<p>
<input type="submit" value="<?php echo lang('Save'); ?>">

View File

@@ -142,7 +142,7 @@ if ($_POST) {
<tr><th><?php echo lang('Server'); ?><td><input name="host" data-maxlength="60" value="<?php echo h($row["host"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Username'); ?><td><input name="user" data-maxlength="80" value="<?php echo h($row["user"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Password'); ?><td><input name="pass" id="pass" value="<?php echo h($row["pass"]); ?>" autocomplete="new-password">
<?php if (!$row["hashed"]) { echo script("typePassword(qs('#pass'));"); } ?>
<?php if (!$row["hashed"]) { echo script("typePassword(gid('pass'));"); } ?>
<?php echo (min_version(8) ? "" : checkbox("hashed", 1, $row["hashed"], lang('Hashed'), "typePassword(this.form['pass'], this.checked);")); ?>
</table>

View File

@@ -439,13 +439,14 @@ if ($_SESSION["lang"]) {
$file = str_replace("<?php switch_lang(); ?>\n", "", $file);
$file = str_replace('<?php echo $LANG; ?>', $_SESSION["lang"], $file);
}
$file = str_replace('<?php echo script_src("static/editing.js"); ?>' . "\n", "", $file);
$file = str_replace('<?php echo script_src("static/editing.js?" . filemtime("../adminer/static/editing.js")); ?>' . "\n", "", $file);
$file = preg_replace('~\s+echo script_src\("\.\./vendor/vrana/jush/modules/jush-(textarea|txt|js|\$jush)\.js"\);~', '', $file);
$file = str_replace('<link rel="stylesheet" type="text/css" href="../vendor/vrana/jush/jush.css">' . "\n", "", $file);
$file = preg_replace_callback("~compile_file\\('([^']+)'(?:, '([^']*)')?\\)~", 'compile_file', $file); // integrate static files
$replace = 'preg_replace("~\\\\\\\\?.*~", "", ME) . "?file=\1&version=' . substr(md5(microtime()), 0, 8) . '"';
$file = preg_replace('~\.\./adminer/static/(default\.css|favicon\.ico)~', '<?php echo h(' . $replace . '); ?>', $file);
$file = preg_replace('~"\.\./adminer/static/(functions\.js)"~', $replace, $file);
$file = preg_replace('~\.\./adminer/static/(favicon\.ico)~', '<?php echo h(' . $replace . '); ?>', $file);
$file = preg_replace('~\.\./adminer/static/(default\.css)\?.*default.css"\);\s+\?>~', '<?php echo h(' . $replace . '); ?>', $file);
$file = preg_replace('~"\.\./adminer/static/(functions\.js)\?".*functions.js"\)~', $replace, $file);
$file = preg_replace('~\.\./adminer/static/([^\'"]*)~', '" . h(' . $replace . ') . "', $file);
$file = preg_replace('~"\.\./vendor/vrana/jush/modules/(jush\.js)"~', $replace, $file);
$file = preg_replace("~<\\?php\\s*\\?>\n?|\\?>\n?<\\?php~", '', $file);

View File

@@ -29,7 +29,7 @@
"php": "5.6 - 8.3",
"ext-pdo": "*",
"ext-json": "*",
"vrana/jush": "@dev",
"vrana/jush": "2.0.*",
"vrana/jsshrink": "@dev"
},
"suggest": {
@@ -57,7 +57,7 @@
"repositories": [
{
"type": "vcs",
"url": "https://github.com/vrana/jush.git"
"url": "https://github.com/pematon/jush.git"
},
{
"type": "vcs",

View File

@@ -11,11 +11,11 @@ if ($adminer->homepage()) {
echo "<table cellspacing='0' class='nowrap checkable'>\n";
echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});");
echo '<thead><tr class="wrap">';
echo '<td><input id="check-all" type="checkbox" class="jsonly">' . script("qs('#check-all').onclick = partial(formCheck, /^tables\[/);", "");
echo '<td><input id="check-all" type="checkbox" class="jsonly">' . script("gid('check-all').onclick = partial(formCheck, /^tables\[/);", "");
echo '<th>' . lang('Table');
echo '<td>' . lang('Rows');
echo "</thead>\n";
foreach (table_status() as $table => $row) {
$name = $adminer->tableName($row);
if (isset($row["Engine"]) && $name != "") {
@@ -25,7 +25,7 @@ if ($adminer->homepage()) {
echo "<td align='right'><a href='" . h(ME . "edit=") . urlencode($table) . "'>" . ($row["Engine"] == "InnoDB" && $val ? "~ $val" : $val) . "</a>";
}
}
echo "</table>\n";
echo "</div>\n";
echo "</form>\n";

View File

@@ -77,7 +77,7 @@ class Adminer {
function loginForm() {
echo "<table cellspacing='0' class='layout'>\n";
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input type="hidden" name="auth[driver]" value="server"><input name="auth[username]" id="username" value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("focus(qs('#username'));"));
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input type="hidden" name="auth[driver]" value="server"><input name="auth[username]" id="username" value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("focus(gid('username'));"));
echo $this->loginFormField('password', '<tr><th>' . lang('Password') . '<td>', '<input type="password" name="auth[password]" autocomplete="current-password">' . "\n");
echo "</table>\n";
echo "<p><input type='submit' value='" . lang('Login') . "'>\n";
@@ -620,7 +620,7 @@ qsl('div').onclick = whisperClick;", "")
if ($password !== null) {
if ($first) {
echo "<ul id='logins'>";
echo script("mixin(qs('#logins'), {onmouseover: menuOver, onmouseout: menuOut});");
echo script("mixin(gid('logins'), {onmouseover: menuOver, onmouseout: menuOut});");
$first = false;
}
echo "<li><a href='" . h(auth_url($vendor, "", $username)) . "'>" . ($username != "" ? h($username) : "<i>" . lang('empty') . "</i>") . "</a>\n";
@@ -655,7 +655,7 @@ qsl('div').onclick = whisperClick;", "")
}
function tablesPrint($tables) {
echo "<ul id='tables'>" . script("mixin(qs('#tables'), {onmouseover: menuOver, onmouseout: menuOut});");
echo "<ul id='tables'>" . script("mixin(gid('tables'), {onmouseover: menuOver, onmouseout: menuOut});");
foreach ($tables as $row) {
// Skip views and tables without a name.

View File

@@ -1,11 +1,14 @@
<?php
/** Adminer Editor - Compact database editor
* @link https://www.adminer.org/
* @author Jakub Vrana, https://www.vrana.cz/
* @copyright 2009 Jakub Vrana
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
/**
* Adminer Editor - Compact database editor for end-users
*
* @link https://github.com/pematon/adminer
* @author Jakub Vrana (https://www.vrana.cz/)
* @author Peter Knut
* @copyright 2009-2021 Jakub Vrana, 2024 Peter Knut
* @license Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
* @license GNU General Public License, version 2 (https://www.gnu.org/licenses/gpl-2.0.html)
*/
include "../adminer/include/bootstrap.inc.php";
$drivers[DRIVER] = lang('Login');

View File

@@ -6,13 +6,14 @@ function messagesPrint() {
function selectFieldChange() {
}
var helpOpen;
// Help.
(function() {
window.initHelpPopup = function () {
};
function helpMouseover() {
}
function helpMouseout() {
}
window.initHelpFor = function(element, content, side = false) {
};
})();
/** Display typeahead
* @param string
@@ -42,7 +43,7 @@ function whisper(url) {
*/
function whisperClick(event) {
var field = this.previousSibling;
var el = getTarget(event);
var el = event.target;
if (isTag(el, 'a') && !(event.button || event.shiftKey || event.altKey || isCtrl(event))) {
field.value = el.firstChild.data;
field.previousSibling.value = decodeURIComponent(el.href.replace(/.*=/, ''));

View File

@@ -65,7 +65,7 @@ tinyMCE.init({
return "<textarea$attrs id='fields-" . h($field["field"]) . "' rows='12' cols='50'>" . h($value) . "</textarea>" . script("
tinyMCE.remove(tinyMCE.get('fields-" . js_escape($field["field"]) . "') || { });
tinyMCE.EditorManager.execCommand('mceAddControl', true, 'fields-" . js_escape($field["field"]) . "');
qs('#form').onsubmit = function () {
gid('form').onsubmit = function () {
tinyMCE.each(tinyMCE.editors, function (ed) {
ed.remove();
});