Files
ludikevent_crm/assets/libs/RepeatLine.js
Serreau Jovann 5d6c0fdde7 ```
 feat(Product.php): Ajoute relation DevisLine et méthodes associées en français.
 feat(DevisLine.php): Ajoute propriétés et relations pour ligne de devis en français.
 feat(DevisController.php): Intègre génération PDF et ajout de lignes de devis en français.
🎨 style: Améliore la mise en page et l'esthétique de l'interface admin en français.
 feat: Initialise TomSelect et gère les adresses client dans DevisManager en français.
🐛 fix: Corrige l'initialisation de TomSelect et la gestion des lignes répétées en français.
 test: Ajoute génération du bon pour accord et signature en français.
```
2026-01-19 17:56:57 +01:00

126 lines
3.9 KiB
JavaScript

import { initTomSelect } from "./initTomSelect.js" // Assure-toi que le chemin est correct
export class RepeatLine extends HTMLDivElement {
connectedCallback() {
this.$props = this.getProps(this, { maxRows: 20 });
this.$refs = this.getRefs(this);
// On stocke le HTML de la première ligne comme modèle
this.rowHTML = this.$refs.rows.children[0].outerHTML;
this.init();
}
setUpRow(row) {
const rowRefs = this.getRefs(row);
if (rowRefs.removeButton) {
rowRefs.removeButton.onclick = (e) => {
e.preventDefault();
this.removeRow(row);
};
}
}
updateAddButton() {
if (this.$refs.rows.children.length >= this.$props.maxRows) {
this.$refs.addButton.setAttribute('disabled', '');
return;
}
this.$refs.addButton.removeAttribute('disabled');
}
updateFieldNames() {
[...this.$refs.rows.children].forEach((el, index) => {
el.querySelectorAll('[name]').forEach(input => {
const newName = input.getAttribute('name').replace(/\[\d+\]/gm, `[${index}]`);
input.setAttribute('name', newName);
});
});
}
addRow() {
if (!this.rowHTML || this.$refs.rows.children.length >= this.$props.maxRows) return;
// Création de la nouvelle ligne
let newRow = this.createFromHTML(this.rowHTML);
newRow.removeAttribute('id');
// Nettoyage spécifique pour TomSelect avant insertion
// Si on clone une ligne qui avait déjà TomSelect, on reset le select
newRow.querySelectorAll('select').forEach(select => {
// Supprimer les classes et éléments injectés par TomSelect si présents dans le template
select.classList.remove('tomselect', 'ts-hidden-visually');
select.innerHTML = '<option value="">Sélectionner...</option>';
// Supprimer le wrapper TomSelect s'il a été cloné par erreur
const wrapper = select.nextElementSibling;
if (wrapper && wrapper.classList.contains('ts-wrapper')) {
wrapper.remove();
}
});
this.setUpRow(newRow);
this.$refs.rows.appendChild(newRow);
// Réinitialisation des valeurs
newRow.querySelectorAll('input,textarea,select').forEach(el => {
el.value = "";
if (el.tagName === 'SELECT') el.selectedIndex = 0;
});
// --- INITIALISATION TOMSELECT SUR LA NOUVELLE LIGNE ---
initTomSelect(newRow);
this.updateFieldNames();
this.updateAddButton();
// Focus sur le premier élément de la nouvelle ligne
const firstInput = newRow.querySelector('input,textarea,select');
if (firstInput) firstInput.focus();
}
removeRow(row) {
if (this.$refs.rows.children.length <= 1) return;
// Détruire l'instance TomSelect pour libérer la mémoire avant de supprimer le DOM
row.querySelectorAll('select').forEach(select => {
if (select.tomselect) {
select.tomselect.destroy();
}
});
row.remove();
this.updateFieldNames();
this.updateAddButton();
}
init() {
this.setUpRow(this.$refs.rows.children[0]);
this.$refs.addButton.onclick = (e) => {
e.preventDefault();
this.addRow();
}
this.updateFieldNames();
}
getRefs(el) {
let result = {};
[...el.querySelectorAll('[data-ref]')].forEach(ref => {
result[ref.dataset.ref] = ref;
});
return result;
}
getProps(el, defaults = {}) {
return Object.assign(defaults, JSON.parse(el.dataset.props ?? '{}'));
}
createFromHTML(html = '') {
let element = document.createElement('div');
element.innerHTML = html.trim();
return element.firstElementChild;
}
}