mirror of
https://github.com/vrana/adminer.git
synced 2025-08-30 09:39:51 +02:00
Add drag-n-drop moving of rows in table editing
This commit is contained in:
@@ -418,7 +418,7 @@ class Adminer {
|
||||
);
|
||||
|
||||
echo "<div ", ($key != "" ? "" : "class='no-sort'"), ">",
|
||||
"<span class='jsonly handle'>=</span>";
|
||||
"<span class='jsonly handle'></span>";
|
||||
|
||||
if ($functions || $grouping) {
|
||||
echo "<select name='columns[$i][fun]'>",
|
||||
@@ -499,7 +499,7 @@ class Adminer {
|
||||
if ($key != "" && $val == "") continue;
|
||||
|
||||
echo "<div ", ($key != "" ? "" : "class='no-sort'"), ">",
|
||||
"<span class='jsonly handle'>=</span>",
|
||||
"<span class='jsonly handle'></span>",
|
||||
select_input("name='order[$i]'", $columns, $val, $key !== "" ? "selectFieldChange" : "selectAddRow"),
|
||||
checkbox("desc[$i]", 1, isset($_GET["desc"][$key]), lang('descending')),
|
||||
" <input type='image' src='../adminer/static/cross.gif' class='jsonly icon remove' title='" . h(lang('Remove')) . "' alt='x'>",
|
||||
|
@@ -288,7 +288,14 @@ function edit_fields(array $fields, array $collations, $type = "TABLE", $foreign
|
||||
?>
|
||||
|
||||
<thead><tr>
|
||||
<?php if ($type == "PROCEDURE") { ?><td></td><?php } ?>
|
||||
<?php
|
||||
if (support("move_col")) {
|
||||
echo "<td class='jsonly'></td>";
|
||||
}
|
||||
if ($type == "PROCEDURE") {
|
||||
echo "<td></td>";
|
||||
}
|
||||
?>
|
||||
<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-length"><?php echo lang('Length'); ?></td>
|
||||
@@ -308,9 +315,9 @@ function edit_fields(array $fields, array $collations, $type = "TABLE", $foreign
|
||||
<?php } ?>
|
||||
<td><?php echo "<input type='image' class='icon' name='add[" . (support("move_col") ? 0 : count($fields)) . "]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'>" . script("row_count = " . count($fields) . ";"); ?></td>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<?php
|
||||
echo script("mixin(qsl('tbody'), {onclick: editingClick, onkeydown: editingKeydown, oninput: editingInput});");
|
||||
echo "<tbody>\n";
|
||||
|
||||
foreach ($fields as $i => $field) {
|
||||
$i++;
|
||||
$orig = $field[($_POST ? "orig" : "field")];
|
||||
@@ -319,6 +326,9 @@ function edit_fields(array $fields, array $collations, $type = "TABLE", $foreign
|
||||
$style = $display ? "" : "style='display: none;'";
|
||||
echo "<tr $style>\n";
|
||||
|
||||
if (support("move_col")) {
|
||||
echo "<th class='handle jsonly'></th>";
|
||||
}
|
||||
if ($type == "PROCEDURE") {
|
||||
echo "<td>", html_select("fields[$i][inout]", explode("|", $inout), $field["inout"]), "</td>\n";
|
||||
}
|
||||
@@ -353,14 +363,17 @@ function edit_fields(array $fields, array $collations, $type = "TABLE", $foreign
|
||||
echo "<td>";
|
||||
if (support("move_col")) {
|
||||
echo "<input type='image' class='icon' name='add[$i]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'> ",
|
||||
"<input type='image' class='icon' name='up[$i]' src='../adminer/static/up.gif' alt='↑' title='" . lang('Move up') . "'> ",
|
||||
"<input type='image' class='icon' name='down[$i]' src='../adminer/static/down.gif' alt='↓' title='" . lang('Move down') . "'> ";
|
||||
"<input type='image' class='icon hidden' name='up[$i]' src='../adminer/static/up.gif' alt='↑' title='" . lang('Move up') . "'> ",
|
||||
"<input type='image' class='icon hidden' name='down[$i]' src='../adminer/static/down.gif' alt='↓' title='" . lang('Move down') . "'> ";
|
||||
}
|
||||
if ($orig == "" || support("drop_col")) {
|
||||
echo "<input type='image' class='icon' name='drop_col[$i]' src='../adminer/static/cross.gif' alt='x' title='" . lang('Remove') . "'>";
|
||||
}
|
||||
echo "</td>\n</tr>\n";
|
||||
}
|
||||
|
||||
echo "</tbody>";
|
||||
echo script("mixin(qs('#edit-fields tbody'), {onclick: editingClick, onkeydown: editingKeydown, oninput: editingInput}); initSortable('#edit-fields tbody');");
|
||||
}
|
||||
|
||||
/** Move fields up and down or add field
|
||||
|
@@ -250,11 +250,11 @@ function confirm($message = "", $selector = "qsl('input')") {
|
||||
return script("$selector.onclick = function () { return confirm('" . ($message ? js_escape($message) : lang('Are you sure?')) . "'); };", "");
|
||||
}
|
||||
|
||||
/** Print header for hidden fieldset (close by </div></fieldset>)
|
||||
* @param string
|
||||
* @param string
|
||||
* @param bool
|
||||
*/
|
||||
/**
|
||||
* Prints header for hidden fieldset (close by </div></fieldset>)
|
||||
* @param $id string
|
||||
* @param $legend string
|
||||
*/
|
||||
function print_fieldset($id, $legend, $visible = false, $sortable = false) {
|
||||
echo "<fieldset><legend>";
|
||||
echo "<a href='#fieldset-$id'>$legend</a>";
|
||||
|
@@ -10,7 +10,7 @@ h3 { font-weight: normal; font-size: 130%; margin: 1em 0 0; }
|
||||
form { margin: 0; }
|
||||
td table { width: 100%; margin: 0; }
|
||||
table { margin: 1em 20px 0 0; border-collapse: collapse; font-size: 90%; }
|
||||
td, th { border: 1px solid #999; padding: .2em .3em; }
|
||||
td, th { box-sizing: border-box; border: 1px solid #999; padding: .2em .3em; }
|
||||
th { background: #eee; text-align: left; }
|
||||
thead th { text-align: center; padding: .2em .5em; }
|
||||
thead td, thead th { background: #ddf; } /* position: sticky; causes Firefox to lose borders */
|
||||
@@ -72,12 +72,15 @@ p.nowrap { white-space: pre; }
|
||||
.logout { margin-top: .5em; position: absolute; top: 0; right: 0; }
|
||||
.loadmore { margin-left: 1ex; }
|
||||
.tables-filter { padding: .8em 1em 0; }
|
||||
.handle { display: inline-block; width: 18px; height: 18px; padding-right: 5px; vertical-align: middle; overflow: hidden; font-size: 130%; text-align: center; line-height: 16px; opacity: 0.2; cursor: grab; }
|
||||
.sortable { position: relative; }
|
||||
.sortable .no-sort .handle { opacity: 0; cursor: default; }
|
||||
.handle { cursor: grab; vertical-align: middle; }
|
||||
.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; }
|
||||
.placeholder { opacity: 0; }
|
||||
.dragging { position: absolute; z-index: 1; }
|
||||
.dragging .handle { cursor: grabbing; }
|
||||
.dragging { position: absolute; margin: 0; background: #fff; }
|
||||
.dragging * { cursor: grabbing; }
|
||||
table.dragging { background: #eee; }
|
||||
/* .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; }
|
||||
|
@@ -253,10 +253,6 @@ function editingClick(event) {
|
||||
var name = el.name;
|
||||
if (/^add\[/.test(name)) {
|
||||
editingAddRow.call(el, 1);
|
||||
} else if (/^up\[/.test(name)) {
|
||||
editingMoveRow.call(el, 1);
|
||||
} else if (/^down\[/.test(name)) {
|
||||
editingMoveRow.call(el);
|
||||
} else if (/^drop_col\[/.test(name)) {
|
||||
editingRemoveRow.call(el, 'fields\$1[field]');
|
||||
} else {
|
||||
@@ -353,7 +349,10 @@ function editingAddRow(focus) {
|
||||
}
|
||||
}
|
||||
tags[0].oninput = editingNameChange;
|
||||
|
||||
initSortableRow(row2);
|
||||
row.parentNode.insertBefore(row2, row.nextSibling);
|
||||
|
||||
if (focus) {
|
||||
input.oninput = editingNameChange;
|
||||
input.focus();
|
||||
@@ -375,22 +374,6 @@ function editingRemoveRow(name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Move table row for field
|
||||
* @param [boolean]
|
||||
* @return boolean false for success
|
||||
* @this HTMLInputElement
|
||||
*/
|
||||
function editingMoveRow(up){
|
||||
var row = parentTag(this, 'tr');
|
||||
if (!('nextElementSibling' in row)) {
|
||||
return true;
|
||||
}
|
||||
row.parentNode.insertBefore(row, up
|
||||
? row.previousElementSibling
|
||||
: row.nextElementSibling ? row.nextElementSibling.nextElementSibling : row.parentNode.firstChild);
|
||||
return false;
|
||||
}
|
||||
|
||||
var lastType = '';
|
||||
|
||||
/** Clear length and hide collation or unsigned
|
||||
|
@@ -544,8 +544,8 @@ function selectSearchSearch() {
|
||||
|
||||
// Sorting.
|
||||
(function() {
|
||||
let placeholderRow, draggingRow, nextRow;
|
||||
let startY, maxY;
|
||||
let placeholderRow, nextRow, dragHelper;
|
||||
let startY, minY, maxY;
|
||||
|
||||
/**
|
||||
* Initializes sortable list of DIV elements.
|
||||
@@ -576,27 +576,52 @@ function selectSearchSearch() {
|
||||
event.preventDefault();
|
||||
|
||||
const parent = row.parentNode;
|
||||
startY = event.clientY - row.offsetTop;
|
||||
maxY = parent.offsetHeight - row.offsetHeight;
|
||||
startY = event.clientY - getOffsetTop(row);
|
||||
minY = getOffsetTop(parent);
|
||||
maxY = minY + parent.offsetHeight - row.offsetHeight;
|
||||
|
||||
placeholderRow = row.cloneNode(true);
|
||||
placeholderRow.classList.add("placeholder");
|
||||
placeholderRow.style.top = (event.clientY - startY) + "px";
|
||||
parent.insertBefore(placeholderRow, row);
|
||||
|
||||
draggingRow = row;
|
||||
draggingRow.classList.add("dragging");
|
||||
parent.insertBefore(draggingRow, parent.firstChild);
|
||||
nextRow = row.nextElementSibling;
|
||||
|
||||
nextRow = placeholderRow.nextElementSibling;
|
||||
let top = event.clientY - startY;
|
||||
let left = getOffsetLeft(row);
|
||||
let width = row.getBoundingClientRect().width;
|
||||
|
||||
updateSorting(event);
|
||||
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", () => {
|
||||
draggingRow.classList.remove("dragging");
|
||||
parent.insertBefore(draggingRow, placeholderRow);
|
||||
dragHelper.classList.remove("dragging");
|
||||
parent.insertBefore(dragHelper.tagName === "TABLE" ? dragHelper.firstChild : dragHelper, placeholderRow);
|
||||
placeholderRow.remove();
|
||||
|
||||
window.removeEventListener("mousemove", updateSorting);
|
||||
@@ -605,8 +630,11 @@ function selectSearchSearch() {
|
||||
};
|
||||
|
||||
function updateSorting(event) {
|
||||
let top = Math.min(Math.max(event.clientY - startY, 0), maxY);
|
||||
draggingRow.style.top = top + "px";
|
||||
let top = Math.min(Math.max(event.clientY - startY, minY), maxY);
|
||||
dragHelper.style.top = `${top}px`;
|
||||
|
||||
const parent = placeholderRow.parentNode;
|
||||
top = top - minY + parent.offsetTop;
|
||||
|
||||
let sibling;
|
||||
if (top > placeholderRow.offsetTop + placeholderRow.offsetHeight / 2) {
|
||||
@@ -1149,6 +1177,18 @@ function cloneNode(el) {
|
||||
return el2;
|
||||
}
|
||||
|
||||
function getOffsetTop(element) {
|
||||
let box = element.getBoundingClientRect();
|
||||
|
||||
return box.top + window.scrollY;
|
||||
}
|
||||
|
||||
function getOffsetLeft(element) {
|
||||
let box = element.getBoundingClientRect();
|
||||
|
||||
return box.left + window.scrollX;
|
||||
}
|
||||
|
||||
oninput = function (event) {
|
||||
var target = event.target;
|
||||
var maxLength = target.getAttribute('data-maxlength');
|
||||
|
Reference in New Issue
Block a user