refactor(orders): extract form cleanup to reusable module

Moved empty order items cleanup logic from order_form.html to a dedicated
order_form_cleanup.js module for better code organization.

Changes:
- Created order_form_cleanup.js with initOrderFormCleanup() function (~136 lines)
  - Automatically removes empty order item forms before submit
  - Handles both new and saved forms differently
  - Updates TOTAL_FORMS and reindexes remaining forms
  - Compatible with Django formsets

- Updated order_form.html:
  - Added order_form_cleanup.js include
  - Added initialization call for #order-form
  - Removed inline cleanup code (~111 lines)

Benefits:
- Cleaner template (111 lines removed)
- Reusable across other formset-based forms
- Easier to test and maintain
- Consistent with other extracted modules

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-23 16:10:57 +03:00
parent 98501c1c26
commit 5de1ae9bb9
2 changed files with 141 additions and 111 deletions

View File

@@ -0,0 +1,138 @@
/**
* Order Form Cleanup Module
* Автоматическая очистка пустых позиций заказа перед отправкой формы
*/
(function(window) {
'use strict';
/**
* Инициализирует автоочистку пустых форм при submit
* @param {Element|string} formElement - DOM элемент формы или селектор
*/
function initOrderFormCleanup(formElement) {
var form = typeof formElement === 'string'
? document.querySelector(formElement)
: formElement;
if (!form) {
console.error('[OrderFormCleanup] Form not found');
return;
}
// Обработчик submit - очищаем пустые строки перед валидацией
form.addEventListener('submit', function(e) {
console.log('[Form Cleanup] Начало очистки пустых форм товаров');
// Находим все формы товаров
var itemForms = Array.from(document.querySelectorAll('.order-item-form'));
console.log('[Form Cleanup] Найдено форм:', itemForms.length);
// Собираем формы для удаления
var formsToRemove = [];
itemForms.forEach(function(itemForm, formIndex) {
// Пропускаем уже удалённые формы
if (itemForm.classList.contains('deleted')) {
console.log('[Form Cleanup] Форма ' + formIndex + ': уже удалена, пропуск');
return;
}
// Находим поля
var productField = itemForm.querySelector('[name$="-product"]');
var kitField = itemForm.querySelector('[name$="-product_kit"]');
var quantityField = itemForm.querySelector('[name$="-quantity"]');
var priceField = itemForm.querySelector('[name$="-price"]');
var idField = itemForm.querySelector('[name$="-id"]');
// Проверяем значения (пустота = нет значения или значение пустое)
var hasProduct = productField && productField.value && productField.value.trim();
var hasKit = kitField && kitField.value && kitField.value.trim();
var hasQuantity = quantityField && quantityField.value && quantityField.value.trim();
var hasPrice = priceField && priceField.value && priceField.value.trim();
console.log('[Form Cleanup] Форма ' + formIndex + ':');
console.log(' - product: ' + (hasProduct || '(пусто)'));
console.log(' - kit: ' + (hasKit || '(пусто)'));
console.log(' - quantity: ' + (hasQuantity || '(пусто)'));
console.log(' - price: ' + (hasPrice || '(пусто)'));
// Если ВСЁ пусто — это мусорная строка, удаляем
var isCompletelyEmpty = !hasProduct && !hasKit && !hasQuantity && !hasPrice;
console.log(' - Полностью пустая? ' + isCompletelyEmpty);
if (isCompletelyEmpty) {
// Если есть ID (сохранённая позиция) — помечаем на удаление
if (idField && idField.value) {
console.log(' - Действие: помечаем DELETE (есть ID: ' + idField.value + ')');
var deleteCheckbox = itemForm.querySelector('input[name$="-DELETE"]');
if (deleteCheckbox) {
deleteCheckbox.checked = true;
}
itemForm.classList.add('deleted');
itemForm.style.display = 'none';
} else {
console.log(' - Действие: помечаем для удаления из formset (нет ID)');
// Новая несохранённая форма — помечаем для удаления
formsToRemove.push(itemForm);
}
} else {
console.log(' - Действие: оставляем (не пустая, пойдёт на валидацию)');
}
});
// Удаляем помеченные формы и пересчитываем индексы
if (formsToRemove.length > 0) {
console.log('[Form Cleanup] Удаление ' + formsToRemove.length + ' пустых форм...');
// Удаляем формы из DOM
formsToRemove.forEach(function(itemForm) {
itemForm.remove();
});
// Обновляем TOTAL_FORMS
var totalFormsInput = document.querySelector('[name="items-TOTAL_FORMS"]');
if (totalFormsInput) {
var oldTotal = parseInt(totalFormsInput.value);
var newTotal = oldTotal - formsToRemove.length;
console.log('[Form Cleanup] Обновление TOTAL_FORMS: ' + oldTotal + ' → ' + newTotal);
totalFormsInput.value = newTotal;
}
// Пересчитываем индексы оставшихся форм
var remainingForms = Array.from(document.querySelectorAll('.order-item-form:not(.deleted)'));
console.log('[Form Cleanup] Пересчёт индексов для ' + remainingForms.length + ' оставшихся форм...');
remainingForms.forEach(function(itemForm, newIndex) {
// Находим все поля с name="items-N-..."
var fields = itemForm.querySelectorAll('[name^="items-"]');
fields.forEach(function(field) {
var name = field.getAttribute('name');
// Меняем индекс: items-СТАРЫЙ-поле → items-НОВЫЙ-поле
var newName = name.replace(/^items-\d+/, 'items-' + newIndex);
if (name !== newName) {
console.log('[Form Cleanup] Переименование: ' + name + ' → ' + newName);
field.setAttribute('name', newName);
// Обновляем ID тоже (для связи с label)
if (field.id) {
var newId = field.id.replace(/^id_items-\d+/, 'id_items-' + newIndex);
field.setAttribute('id', newId);
}
}
});
});
}
console.log('[Form Cleanup] Очистка завершена');
// Всё остальное идёт на валидацию Django как есть
});
console.log('[OrderFormCleanup] Initialized for form:', form.id || form);
}
// Экспорт
window.initOrderFormCleanup = initOrderFormCleanup;
})(window);