Feature: удаление строки табличной части по кнопке-крестику (сразу, без чекбокса)
Made-with: Cursor
This commit is contained in:
10
HISTORY.md
10
HISTORY.md
@@ -1,6 +1,14 @@
|
||||
# История изменений ERP WaterSurf
|
||||
|
||||
# История изменений ERP WaterSurf
|
||||
## 2025-02-25 23:15 UTC – Удаление строки табличной части по кнопке-крестику
|
||||
|
||||
**Проблема**: Удаление строки происходило при сохранении документа (чекбокс «Удалить»), что было неочевидно и неудобно.
|
||||
|
||||
**Решение**: В формах заказа клиента и заказа поставщику чекбокс и подпись «Удалить» заменены на кнопку в виде красного крестика (×). По нажатию строка сразу удаляется из DOM, индексы полей formset пересчитываются (reindexRows), обновляется TOTAL_FORMS и пересчёт сумм по строкам. При добавлении новой строки после вставки клона также вызывается reindexRows().
|
||||
|
||||
**Изменения**: order_form.html (кнопка .ws-btn-remove-row, reindexRows, делегированный click на tbody), supplier_order_form.html (аналогично), theme-compact.css (стили .ws-btn-remove-row — красный крестик, hover; удалены стили .ws-delete-row-label).
|
||||
|
||||
---
|
||||
|
||||
## 2025-02-25 22:50 UTC – Добавление строки: одна строка за клик, понятное удаление
|
||||
|
||||
|
||||
@@ -132,11 +132,25 @@
|
||||
width: 5%;
|
||||
}
|
||||
|
||||
.ws-table-items label.ws-delete-row-label {
|
||||
.ws-table-items .ws-btn-remove-row {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: #c62828;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: var(--ws-text-muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ws-table-items .ws-btn-remove-row:hover {
|
||||
background: rgba(198, 40, 40, 0.12);
|
||||
color: #b71c1c;
|
||||
}
|
||||
|
||||
.ws-table-items .ws-col-product select {
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<td class="ws-col-currency">{{ f.currency }}</td>
|
||||
<td class="ws-col-qty">{{ f.quantity }}</td>
|
||||
<td class="row-amount ws-col-cost ws-num">—</td>
|
||||
<td class="ws-col-del"><label class="ws-delete-row-label">{% if f.DELETE %}{{ f.DELETE }}{% endif %} Удалить</label></td>
|
||||
<td class="ws-col-del"><button type="button" class="ws-btn-remove-row" title="Удалить строку" aria-label="Удалить строку">×</button></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -133,6 +133,34 @@
|
||||
|
||||
updateRowAmounts();
|
||||
|
||||
function reindexRows() {
|
||||
var prefix = getPrefix();
|
||||
var rows = tbody.querySelectorAll('.item-row');
|
||||
rows.forEach(function(row, i) {
|
||||
row.querySelectorAll('input, select').forEach(function(el) {
|
||||
var n = el.getAttribute('name');
|
||||
if (n && n.indexOf(prefix) === 0) {
|
||||
el.setAttribute('name', n.replace(new RegExp('^' + prefix + '\\d+'), prefix + i));
|
||||
}
|
||||
var id = el.getAttribute('id');
|
||||
if (id) {
|
||||
el.setAttribute('id', id.replace(new RegExp(prefix + '\\d+'), prefix + i));
|
||||
}
|
||||
});
|
||||
});
|
||||
totalInput.value = String(rows.length);
|
||||
updateRowAmounts();
|
||||
}
|
||||
|
||||
tbody.addEventListener('click', function(e) {
|
||||
var btn = e.target.closest('.ws-btn-remove-row');
|
||||
if (!btn) return;
|
||||
var row = btn.closest('tr.item-row');
|
||||
if (!row) return;
|
||||
row.remove();
|
||||
reindexRows();
|
||||
});
|
||||
|
||||
document.getElementById('add-order-row').addEventListener('click', function() {
|
||||
var rows = tbody.querySelectorAll('.item-row');
|
||||
var lastRow = rows[rows.length - 1];
|
||||
@@ -156,13 +184,8 @@
|
||||
});
|
||||
var amountCell = clone.querySelector('.row-amount');
|
||||
if (amountCell) amountCell.textContent = '—';
|
||||
var delCheckbox = clone.querySelector('input[name$="-DELETE"]');
|
||||
if (delCheckbox) {
|
||||
var delLabel = clone.querySelector('label.ws-delete-row-label');
|
||||
if (delLabel) delLabel.setAttribute('for', delCheckbox.id);
|
||||
}
|
||||
tbody.appendChild(clone);
|
||||
totalInput.value = nextIndex + 1;
|
||||
reindexRows();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<td class="ws-col-currency">{{ f.currency }}</td>
|
||||
<td class="ws-col-qty">{{ f.quantity }}</td>
|
||||
<td class="row-amount ws-col-cost ws-num">—</td>
|
||||
<td class="ws-col-del"><label class="ws-delete-row-label">{% if f.DELETE %}{{ f.DELETE }}{% endif %} Удалить</label></td>
|
||||
<td class="ws-col-del"><button type="button" class="ws-btn-remove-row" title="Удалить строку" aria-label="Удалить строку">×</button></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -138,6 +138,34 @@
|
||||
|
||||
updateRowAmounts();
|
||||
|
||||
function reindexRows() {
|
||||
var prefix = getPrefix();
|
||||
var rows = tbody.querySelectorAll('.item-row');
|
||||
rows.forEach(function(row, i) {
|
||||
row.querySelectorAll('input, select').forEach(function(el) {
|
||||
var n = el.getAttribute('name');
|
||||
if (n && n.indexOf(prefix) === 0) {
|
||||
el.setAttribute('name', n.replace(new RegExp('^' + prefix + '\\d+'), prefix + i));
|
||||
}
|
||||
var id = el.getAttribute('id');
|
||||
if (id) {
|
||||
el.setAttribute('id', id.replace(new RegExp(prefix + '\\d+'), prefix + i));
|
||||
}
|
||||
});
|
||||
});
|
||||
totalInput.value = String(rows.length);
|
||||
updateRowAmounts();
|
||||
}
|
||||
|
||||
tbody.addEventListener('click', function(e) {
|
||||
var btn = e.target.closest('.ws-btn-remove-row');
|
||||
if (!btn) return;
|
||||
var row = btn.closest('tr.item-row');
|
||||
if (!row) return;
|
||||
row.remove();
|
||||
reindexRows();
|
||||
});
|
||||
|
||||
document.getElementById('add-supplier-order-row').addEventListener('click', function() {
|
||||
var rows = tbody.querySelectorAll('.item-row');
|
||||
var lastRow = rows[rows.length - 1];
|
||||
@@ -151,9 +179,7 @@
|
||||
el.setAttribute('name', name.replace(new RegExp('^' + prefix + '\\d+-'), prefix + nextIndex + '-'));
|
||||
el.setAttribute('id', (el.getAttribute('id') || '').replace(new RegExp(prefix + '\\d+-'), prefix + nextIndex + '-'));
|
||||
}
|
||||
if (el.name && el.name.indexOf('-DELETE') !== -1) {
|
||||
el.checked = false;
|
||||
} else if (el.name && el.name.indexOf('-id') !== -1) {
|
||||
if (el.name && el.name.indexOf('-id') !== -1) {
|
||||
el.value = '';
|
||||
} else if (el.type !== 'hidden') {
|
||||
el.value = '';
|
||||
@@ -161,13 +187,8 @@
|
||||
});
|
||||
var amountCell = clone.querySelector('.row-amount');
|
||||
if (amountCell) amountCell.textContent = '—';
|
||||
var delCheckbox = clone.querySelector('input[name$="-DELETE"]');
|
||||
if (delCheckbox) {
|
||||
var delLabel = clone.querySelector('label.ws-delete-row-label');
|
||||
if (delLabel) delLabel.setAttribute('for', delCheckbox.id);
|
||||
}
|
||||
tbody.appendChild(clone);
|
||||
totalInput.value = nextIndex + 1;
|
||||
reindexRows();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user