feat(Formules): Ajoute champ 'pos' pour ordonner les formules.
🐛 fix(CrmEditor): Améliore la gestion du copier-coller et retire le toast d'erreur.
```
This commit is contained in:
Serreau Jovann
2026-01-30 09:48:27 +01:00
parent 4873c24bb2
commit b6f90721ad
3 changed files with 56 additions and 20 deletions

View File

@@ -37,11 +37,6 @@ export class CrmEditor extends HTMLTextAreaElement {
</button> </button>
</div> </div>
<!-- Toast de sécurité -->
<div id="paste-error" class="absolute top-16 left-1/2 -translate-x-1/2 bg-red-500 text-white px-4 py-2 rounded-full text-xs font-bold shadow-xl opacity-0 transition-all duration-300 pointer-events-none z-50">
Copie impossible
</div>
<div id="wysiwyg-area" <div id="wysiwyg-area"
contenteditable="true" contenteditable="true"
class="p-6 min-h-[300px] max-h-[600px] overflow-y-auto focus:outline-none bg-white text-slate-900 prose prose-slate max-w-none shadow-inner break-words w-full"> class="p-6 min-h-[300px] max-h-[600px] overflow-y-auto focus:outline-none bg-white text-slate-900 prose prose-slate max-w-none shadow-inner break-words w-full">
@@ -50,9 +45,9 @@ export class CrmEditor extends HTMLTextAreaElement {
<div class="flex items-center justify-between px-4 py-2 border-t border-white/10 bg-black/20 text-[11px] font-medium tracking-wide"> <div class="flex items-center justify-between px-4 py-2 border-t border-white/10 bg-black/20 text-[11px] font-medium tracking-wide">
<div id="char-counter" class="flex items-center gap-2"> <div id="char-counter" class="flex items-center gap-2">
<span id="char-count" class="text-white bg-white/10 px-2 py-0.5 rounded-full">0 caractères</span> <span id="char-count" class="text-white bg-white/10 px-2 py-0.5 rounded-full">0 caractères</span>
<span id="seo-warning" class="text-orange-400 opacity-0 transition-opacity italic">Texte insuffisant pour un référencement optimal</span> <span id="seo-warning" class="text-orange-400 opacity-0 transition-opacity italic">Texte insuffisant</span>
</div> </div>
<div class="text-white/40 uppercase tracking-widest font-bold">EsyWysiwyg 1.0</div> <div class="text-white/40 uppercase tracking-widest font-bold">EsyWysiwyg 1.1</div>
</div> </div>
`; `;
@@ -60,17 +55,21 @@ export class CrmEditor extends HTMLTextAreaElement {
this.wysiwyg = this.editorContainer.querySelector('#wysiwyg-area'); this.wysiwyg = this.editorContainer.querySelector('#wysiwyg-area');
this.colorInput = this.editorContainer.querySelector('#text-color-input'); this.colorInput = this.editorContainer.querySelector('#text-color-input');
this.colorBar = this.editorContainer.querySelector('#color-bar'); this.colorBar = this.editorContainer.querySelector('#color-bar');
this.pasteError = this.editorContainer.querySelector('#paste-error');
this.initEvents(); this.initEvents();
this.updateStats(); this.updateStats();
} }
initEvents() { initEvents() {
// Sécurité anti-collage // --- NOUVELLE LOGIQUE DE NETTOYAGE (PASTE) ---
this.wysiwyg.addEventListener('paste', (e) => { this.wysiwyg.addEventListener('paste', (e) => {
e.preventDefault(); e.preventDefault();
this.showPasteWarning(); // On récupère uniquement le texte brut du presse-papier
const text = (e.originalEvent || e).clipboardData.getData('text/plain');
// On l'insère proprement à l'endroit du curseur sans aucune balise
document.execCommand('insertText', false, text);
this.syncValue();
this.updateStats();
}); });
// Boutons standards // Boutons standards
@@ -102,16 +101,6 @@ export class CrmEditor extends HTMLTextAreaElement {
}); });
} }
showPasteWarning() {
this.pasteError.classList.remove('opacity-0', 'scale-90');
this.pasteError.classList.add('opacity-100', 'scale-100');
setTimeout(() => {
this.pasteError.classList.add('opacity-0', 'scale-90');
this.pasteError.classList.remove('opacity-100', 'scale-100');
}, 2000);
}
updateStats() { updateStats() {
const text = this.wysiwyg.innerText || ""; const text = this.wysiwyg.innerText || "";
const count = text.trim().length; const count = text.trim().length;

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260130081429 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE formules ADD pos INT DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE formules DROP pos');
}
}

View File

@@ -72,6 +72,9 @@ class Formules
#[ORM\OneToOne(mappedBy: 'formule', cascade: ['persist', 'remove'])] #[ORM\OneToOne(mappedBy: 'formule', cascade: ['persist', 'remove'])]
private ?FormulesRestriction $formulesRestriction = null; private ?FormulesRestriction $formulesRestriction = null;
#[ORM\Column(nullable: true)]
private ?int $pos = null;
public function __construct() public function __construct()
{ {
$this->formulesProductIncluses = new ArrayCollection(); $this->formulesProductIncluses = new ArrayCollection();
@@ -332,4 +335,16 @@ class Formules
return $this; return $this;
} }
public function getPos(): ?int
{
return $this->pos;
}
public function setPos(?int $pos): static
{
$this->pos = $pos;
return $this;
}
} }