fix(database): column resize follows mouse, inline rename in context menu
- Column resize: use getBoundingClientRect() + setPointerCapture for proper tracking
- Context menu 'Name' field: click to edit, Enter to save, Escape to cancel
- Rename persists to server via PUT /db/properties/{id}/api
This commit is contained in:
@@ -164,30 +164,29 @@
|
||||
thead.querySelectorAll('.db-col-resize-handle').forEach(handle => {
|
||||
handle.onpointerdown = function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.setPointerCapture(e.pointerId);
|
||||
const propId = parseInt(this.dataset.propId);
|
||||
const th = this.parentElement;
|
||||
const startX = e.clientX;
|
||||
const startW = th.offsetWidth;
|
||||
const startW = th.getBoundingClientRect().width;
|
||||
|
||||
function onMove(ev) {
|
||||
const diff = ev.clientX - startX;
|
||||
const newW = Math.max(60, startW + diff);
|
||||
state.colWidths[propId] = newW;
|
||||
// Update header
|
||||
th.style.width = newW + 'px';
|
||||
th.style.minWidth = newW + 'px';
|
||||
// Update all cells in this column
|
||||
const colIdx = state.properties.findIndex(p => p.id === propId);
|
||||
if (colIdx >= 0) {
|
||||
document.querySelectorAll('#db-tbody .db-row').forEach(row => {
|
||||
const cells = row.querySelectorAll('.db-td-cell');
|
||||
if (cells[colIdx]) {
|
||||
cells[colIdx].style.minWidth = newW + 'px';
|
||||
}
|
||||
if (cells[colIdx]) cells[colIdx].style.minWidth = newW + 'px';
|
||||
});
|
||||
}
|
||||
}
|
||||
function onUp() {
|
||||
function onUp(ev) {
|
||||
handle.releasePointerCapture(ev.pointerId);
|
||||
document.removeEventListener('pointermove', onMove);
|
||||
document.removeEventListener('pointerup', onUp);
|
||||
document.body.style.cursor = '';
|
||||
@@ -242,7 +241,38 @@
|
||||
|
||||
// Set header
|
||||
document.getElementById('db-col-menu-icon').innerHTML = propTypeSvg(propType);
|
||||
document.getElementById('db-col-menu-name').textContent = propName;
|
||||
const nameEl = document.getElementById('db-col-menu-name');
|
||||
nameEl.textContent = propName;
|
||||
nameEl.contentEditable = 'false';
|
||||
nameEl.style.cursor = 'text';
|
||||
nameEl.style.border = 'none';
|
||||
nameEl.style.outline = 'none';
|
||||
nameEl.style.padding = '0';
|
||||
nameEl.style.background = 'transparent';
|
||||
nameEl.title = 'Click to rename';
|
||||
// Click on name to edit
|
||||
nameEl.onclick = function(e) {
|
||||
e.stopPropagation();
|
||||
if (nameEl.contentEditable === 'true') return;
|
||||
nameEl.contentEditable = 'true';
|
||||
nameEl.style.border = '1px solid var(--accent, #2383E2)';
|
||||
nameEl.style.borderRadius = '3px';
|
||||
nameEl.style.padding = '2px 4px';
|
||||
nameEl.style.outline = 'none';
|
||||
nameEl.focus();
|
||||
// Select all text
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(nameEl);
|
||||
const sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
};
|
||||
// Blur/Enter → save rename
|
||||
nameEl.onblur = function() { commitColRename(propId); };
|
||||
nameEl.onkeydown = function(e) {
|
||||
if (e.key === 'Enter') { e.preventDefault(); commitColRename(propId); }
|
||||
else if (e.key === 'Escape') { cancelColRename(propId, propName); }
|
||||
};
|
||||
document.getElementById('db-col-menu-info').textContent = 'ⓘ';
|
||||
|
||||
// Position near the anchor
|
||||
@@ -268,13 +298,55 @@
|
||||
const menu = document.getElementById('db-col-menu');
|
||||
if (menu) {
|
||||
menu.style.display = 'none';
|
||||
// Hide all submenus
|
||||
menu.querySelectorAll('.db-col-menu-sub').forEach(s => s.style.display = 'none');
|
||||
}
|
||||
state.colMenuPropId = null;
|
||||
state.colMenuSubOpen = null;
|
||||
}
|
||||
|
||||
async function commitColRename(propId) {
|
||||
const nameEl = document.getElementById('db-col-menu-name');
|
||||
if (!nameEl) return;
|
||||
const newName = nameEl.textContent.trim();
|
||||
if (!newName) return;
|
||||
nameEl.contentEditable = 'false';
|
||||
nameEl.style.border = 'none';
|
||||
nameEl.style.borderRadius = '0';
|
||||
nameEl.style.padding = '0';
|
||||
|
||||
const prop = state.properties.find(p => p.id === propId);
|
||||
if (!prop || prop.name === newName) return;
|
||||
|
||||
// Update local state
|
||||
prop.name = newName;
|
||||
// Update header in table
|
||||
renderTable();
|
||||
// If menu still open, update its display
|
||||
if (state.colMenuPropId === propId) {
|
||||
nameEl.textContent = newName;
|
||||
}
|
||||
|
||||
// Persist to server
|
||||
const csrf = document.cookie.match(/csrf_token=([^;]+)/);
|
||||
try {
|
||||
await fetch('/db/properties/' + propId + '/api', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrf ? csrf[1] : '' },
|
||||
body: JSON.stringify({ name: newName })
|
||||
});
|
||||
} catch(e) { console.error('[DB] rename property error:', e); }
|
||||
}
|
||||
|
||||
function cancelColRename(propId, originalName) {
|
||||
const nameEl = document.getElementById('db-col-menu-name');
|
||||
if (!nameEl) return;
|
||||
nameEl.contentEditable = 'false';
|
||||
nameEl.textContent = originalName;
|
||||
nameEl.style.border = 'none';
|
||||
nameEl.style.borderRadius = '0';
|
||||
nameEl.style.padding = '0';
|
||||
}
|
||||
|
||||
function toggleColSubmenu(subId) {
|
||||
const sub = document.getElementById(subId);
|
||||
if (!sub) return;
|
||||
|
||||
Reference in New Issue
Block a user