Docfile commited on
Commit
50b44f1
·
verified ·
1 Parent(s): 3e64da2

Update api/templates/admin/edit_texte.html

Browse files
Files changed (1) hide show
  1. api/templates/admin/edit_texte.html +238 -51
api/templates/admin/edit_texte.html CHANGED
@@ -4,44 +4,90 @@
4
 
5
  {% block styles %}
6
  <style>
 
 
 
7
  .block-editor {
8
  position: relative;
9
  transition: all 0.3s ease;
10
  }
11
-
12
  .block-ghost {
13
  opacity: 0.5;
14
  background: var(--primary-color);
15
  }
16
-
17
  .block-handle {
18
  cursor: move;
19
  color: var(--muted-color);
 
20
  }
21
-
22
  .image-position-example {
23
  padding: 10px;
24
  border: 1px dashed var(--border-color);
25
  margin-top: 10px;
26
  border-radius: 4px;
27
  }
28
-
29
  .block-image-container {
30
  margin-bottom: 15px;
31
  }
32
-
33
  .image-preview {
34
  max-height: 150px;
35
  object-fit: contain;
 
 
 
36
  }
37
-
38
  .gallery-image {
39
  transition: transform 0.2s;
40
  cursor: pointer;
 
 
 
41
  }
42
-
43
  .gallery-image:hover {
44
  transform: scale(1.05);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
46
  </style>
47
  {% endblock %}
@@ -85,11 +131,11 @@
85
  </ul>
86
  </div>
87
  </div>
88
-
89
  <div class="col-md-9">
90
  <div class="admin-container">
91
  <h2 class="admin-title">Éditer la méthodologie : {{ texte.titre }}</h2>
92
-
93
  <div class="mb-4">
94
  <a href="{{ url_for('admin_bp.textes') }}" class="btn btn-secondary mb-3">
95
  <i class="fas fa-arrow-left"></i> Retour à la liste
@@ -98,7 +144,7 @@
98
  <i class="fas fa-history"></i> Voir l'historique
99
  </a>
100
  </div>
101
-
102
  <!-- Basic Information Form -->
103
  <div class="card mb-4">
104
  <div class="card-header">
@@ -106,13 +152,14 @@
106
  </div>
107
  <div class="card-body">
108
  <form method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}">
 
109
  <input type="hidden" name="action" value="update_basic">
110
-
111
  <div class="form-group mb-3">
112
  <label for="titre">Titre</label>
113
  <input type="text" class="form-control" id="titre" name="titre" value="{{ texte.titre }}" required>
114
  </div>
115
-
116
  <div class="form-group mb-3">
117
  <label for="sous_categorie_id">Sous-catégorie</label>
118
  <select class="form-control" id="sous_categorie_id" name="sous_categorie_id" required>
@@ -123,14 +170,14 @@
123
  {% endfor %}
124
  </select>
125
  </div>
126
-
127
  <button type="submit" class="btn btn-primary">
128
  <i class="fas fa-save"></i> Mettre à jour les informations
129
  </button>
130
  </form>
131
  </div>
132
  </div>
133
-
134
  <!-- Content Blocks Editor -->
135
  <div class="card mb-4">
136
  <div class="card-header d-flex justify-content-between align-items-center">
@@ -141,14 +188,15 @@
141
  </div>
142
  <div class="card-body">
143
  <p class="text-muted mb-4">
144
- Organisez votre contenu en blocs distincts. Chaque bloc peut contenir un titre, du texte et une image.
145
- Vous pouvez réorganiser les blocs en les faisant glisser.
146
  </p>
147
-
148
  <form id="blocks-form" method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}">
 
149
  <input type="hidden" name="action" value="update_blocks">
150
  <input type="hidden" id="blocks-data" name="blocks_data" value="">
151
-
152
  <div id="blocks-container">
153
  {% for block in blocks %}
154
  <div class="block-editor mb-4" data-block-id="{{ block.id }}">
@@ -158,7 +206,7 @@
158
  <h3 class="block-editor-title">Bloc #{{ loop.index }}</h3>
159
  </div>
160
  <div class="block-editor-actions">
161
- <button type="button" class="btn btn-danger btn-sm delete-block-btn">
162
  <i class="fas fa-trash"></i>
163
  </button>
164
  </div>
@@ -168,11 +216,16 @@
168
  <input type="text" class="form-control block-title" id="block-{{ block.id }}-title" value="{{ block.title or '' }}">
169
  </div>
170
  <div class="form-group mb-3">
171
- <label for="block-{{ block.id }}-content">Contenu du bloc</label>
172
- <textarea class="form-control block-content" id="block-{{ block.id }}-content" rows="5">{{ block.content or '' }}</textarea>
 
 
 
 
 
173
  </div>
174
  <div class="form-group">
175
- <label>Image</label>
176
  <div class="d-flex align-items-center mb-2">
177
  <button type="button" class="btn btn-primary btn-sm select-image-btn" {% if block.image %}style="display:none;"{% endif %}>
178
  <i class="fas fa-image"></i> Sélectionner une image
@@ -182,16 +235,16 @@
182
  </button>
183
  </div>
184
  <input type="hidden" class="block-image-id" value="{{ block.image.id if block.image else '' }}">
185
-
186
- {% if block.image %}
187
  <div class="block-image-container">
188
- <img src="{{ block.image.src }}" alt="{{ block.image.alt }}" class="image-preview">
 
 
 
 
189
  </div>
190
- {% else %}
191
- <img src="" alt="Preview" class="image-preview" style="display:none;">
192
- {% endif %}
193
-
194
- <div class="form-group mt-3">
195
  <label for="block-{{ block.id }}-image-position">Position de l'image</label>
196
  <select class="form-control image-position-select" id="block-{{ block.id }}-image-position">
197
  <option value="left" {% if block.image_position == 'left' %}selected{% endif %}>Gauche</option>
@@ -203,39 +256,51 @@
203
  </div>
204
  {% endfor %}
205
  </div>
206
-
207
  <div class="mt-4 text-center">
208
  <button type="button" id="save-blocks-button" class="btn btn-primary btn-lg">
209
- <i class="fas fa-save"></i> Enregistrer les modifications
210
  </button>
211
  </div>
212
  </form>
213
  </div>
214
  </div>
215
-
216
  <!-- Image Upload Section -->
217
  <div class="card mb-4">
218
  <div class="card-header">
219
- <h4>Ajouter une nouvelle image</h4>
220
  </div>
221
  <div class="card-body">
222
- <form method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}" enctype="multipart/form-data">
223
- <input type="hidden" name="action" value="upload_image">
224
-
 
 
225
  <div class="form-group mb-3">
226
  <label for="image">Sélectionner une image</label>
227
- <input type="file" class="form-control" id="image" name="image" accept="image/*" required>
228
  </div>
229
-
230
  <div class="form-group mb-3">
231
  <label for="alt_text">Texte alternatif (pour l'accessibilité)</label>
232
- <input type="text" class="form-control" id="alt_text" name="alt_text" placeholder="Description de l'image">
233
  </div>
234
-
 
 
 
235
  <button type="submit" class="btn btn-success">
236
- <i class="fas fa-upload"></i> Télécharger l'image
237
  </button>
238
  </form>
 
 
 
 
 
 
 
239
  </div>
240
  </div>
241
  </div>
@@ -244,24 +309,26 @@
244
 
245
  <!-- Image Gallery Modal -->
246
  <div class="modal fade" id="image-gallery-modal" tabindex="-1" aria-labelledby="imageGalleryModalLabel" aria-hidden="true">
247
- <div class="modal-dialog modal-lg">
248
  <div class="modal-content">
249
  <div class="modal-header">
250
- <h5 class="modal-title" id="imageGalleryModalLabel">Sélectionner une image</h5>
251
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
252
  </div>
253
  <div class="modal-body">
254
- <div class="row">
 
255
  {% for image in images %}
256
- <div class="col-md-3 col-sm-4 col-6 mb-3">
257
- <div class="gallery-item" data-image-id="{{ image.id }}">
258
- <img src="{{ image.src }}" alt="{{ image.alt }}" class="gallery-image img-fluid">
 
259
  </div>
260
  </div>
261
  {% else %}
262
  <div class="col-12">
263
  <div class="alert alert-info">
264
- Aucune image disponible. Veuillez en télécharger une.
265
  </div>
266
  </div>
267
  {% endfor %}
@@ -277,6 +344,126 @@
277
 
278
  {% block scripts %}
279
  <!-- Include Sortable.js for drag and drop functionality -->
280
- <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js"></script>
 
 
 
 
 
 
281
  <script src="{{ url_for('static', filename='js/admin.js') }}"></script>
282
- {% endblock %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  {% block styles %}
6
  <style>
7
+ /* Quill editor needs some height */
8
+ .ql-container { min-height: 150px; }
9
+
10
  .block-editor {
11
  position: relative;
12
  transition: all 0.3s ease;
13
  }
14
+
15
  .block-ghost {
16
  opacity: 0.5;
17
  background: var(--primary-color);
18
  }
19
+
20
  .block-handle {
21
  cursor: move;
22
  color: var(--muted-color);
23
+ padding-right: 10px; /* Add some space next to handle */
24
  }
25
+
26
  .image-position-example {
27
  padding: 10px;
28
  border: 1px dashed var(--border-color);
29
  margin-top: 10px;
30
  border-radius: 4px;
31
  }
32
+
33
  .block-image-container {
34
  margin-bottom: 15px;
35
  }
36
+
37
  .image-preview {
38
  max-height: 150px;
39
  object-fit: contain;
40
+ border-radius: 4px;
41
+ border: 1px solid var(--border-color);
42
+ background-color: var(--background-color);
43
  }
44
+
45
  .gallery-image {
46
  transition: transform 0.2s;
47
  cursor: pointer;
48
+ border: 1px solid var(--border-color);
49
+ padding: 5px;
50
+ border-radius: 4px;
51
  }
52
+
53
  .gallery-image:hover {
54
  transform: scale(1.05);
55
+ border-color: var(--primary-color);
56
+ }
57
+
58
+ /* Style adjustments for Quill within the block */
59
+ .block-content-editor {
60
+ background-color: var(--input-bg); /* Match theme */
61
+ border-radius: 4px; /* Match form controls */
62
+ margin-bottom: 5px; /* Space between editor and hidden input if needed */
63
+ }
64
+
65
+ /* Style the block editor structure */
66
+ .block-editor {
67
+ background-color: var(--card-bg);
68
+ padding: 20px;
69
+ border: 1px solid var(--border-color);
70
+ border-radius: 8px;
71
+ box-shadow: var(--shadow);
72
+ }
73
+ .block-editor-header {
74
+ display: flex;
75
+ justify-content: space-between;
76
+ align-items: center;
77
+ margin-bottom: 15px;
78
+ padding-bottom: 10px;
79
+ border-bottom: 1px solid var(--border-color);
80
+ }
81
+ .block-editor-title {
82
+ margin: 0;
83
+ font-size: 1.2rem;
84
+ font-weight: 600;
85
+ }
86
+ .delete-block-btn i {
87
+ pointer-events: none; /* Ensure clicking icon triggers button */
88
+ }
89
+ .ml-2 { /* Simple margin helper */
90
+ margin-left: 0.5rem !important;
91
  }
92
  </style>
93
  {% endblock %}
 
131
  </ul>
132
  </div>
133
  </div>
134
+
135
  <div class="col-md-9">
136
  <div class="admin-container">
137
  <h2 class="admin-title">Éditer la méthodologie : {{ texte.titre }}</h2>
138
+
139
  <div class="mb-4">
140
  <a href="{{ url_for('admin_bp.textes') }}" class="btn btn-secondary mb-3">
141
  <i class="fas fa-arrow-left"></i> Retour à la liste
 
144
  <i class="fas fa-history"></i> Voir l'historique
145
  </a>
146
  </div>
147
+
148
  <!-- Basic Information Form -->
149
  <div class="card mb-4">
150
  <div class="card-header">
 
152
  </div>
153
  <div class="card-body">
154
  <form method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}">
155
+ <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> {# Add CSRF token if using Flask-WTF #}
156
  <input type="hidden" name="action" value="update_basic">
157
+
158
  <div class="form-group mb-3">
159
  <label for="titre">Titre</label>
160
  <input type="text" class="form-control" id="titre" name="titre" value="{{ texte.titre }}" required>
161
  </div>
162
+
163
  <div class="form-group mb-3">
164
  <label for="sous_categorie_id">Sous-catégorie</label>
165
  <select class="form-control" id="sous_categorie_id" name="sous_categorie_id" required>
 
170
  {% endfor %}
171
  </select>
172
  </div>
173
+
174
  <button type="submit" class="btn btn-primary">
175
  <i class="fas fa-save"></i> Mettre à jour les informations
176
  </button>
177
  </form>
178
  </div>
179
  </div>
180
+
181
  <!-- Content Blocks Editor -->
182
  <div class="card mb-4">
183
  <div class="card-header d-flex justify-content-between align-items-center">
 
188
  </div>
189
  <div class="card-body">
190
  <p class="text-muted mb-4">
191
+ Organisez votre contenu en blocs distincts. Chaque bloc peut contenir un titre, du texte riche et une image.
192
+ Vous pouvez réorganiser les blocs en les faisant glisser (<i class="fas fa-grip-vertical"></i>).
193
  </p>
194
+
195
  <form id="blocks-form" method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}">
196
+ <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> {# Add CSRF token if using Flask-WTF #}
197
  <input type="hidden" name="action" value="update_blocks">
198
  <input type="hidden" id="blocks-data" name="blocks_data" value="">
199
+
200
  <div id="blocks-container">
201
  {% for block in blocks %}
202
  <div class="block-editor mb-4" data-block-id="{{ block.id }}">
 
206
  <h3 class="block-editor-title">Bloc #{{ loop.index }}</h3>
207
  </div>
208
  <div class="block-editor-actions">
209
+ <button type="button" class="btn btn-danger btn-sm delete-block-btn" title="Supprimer ce bloc">
210
  <i class="fas fa-trash"></i>
211
  </button>
212
  </div>
 
216
  <input type="text" class="form-control block-title" id="block-{{ block.id }}-title" value="{{ block.title or '' }}">
217
  </div>
218
  <div class="form-group mb-3">
219
+ <label for="quill-editor-{{ block.id }}">Contenu du bloc</label>
220
+ <!-- Quill editor container -->
221
+ <div id="quill-editor-{{ block.id }}" class="block-content-editor">
222
+ {{ block.content|safe if block.content else '' }}
223
+ </div>
224
+ <!-- Hidden input to store Quill's HTML content -->
225
+ <input type="hidden" class="block-content-hidden" id="block-{{ block.id }}-content" value="{{ block.content or '' }}">
226
  </div>
227
  <div class="form-group">
228
+ <label>Image (optionnel)</label>
229
  <div class="d-flex align-items-center mb-2">
230
  <button type="button" class="btn btn-primary btn-sm select-image-btn" {% if block.image %}style="display:none;"{% endif %}>
231
  <i class="fas fa-image"></i> Sélectionner une image
 
235
  </button>
236
  </div>
237
  <input type="hidden" class="block-image-id" value="{{ block.image.id if block.image else '' }}">
238
+
 
239
  <div class="block-image-container">
240
+ {% if block.image %}
241
+ <img src="{{ block.image.src }}" alt="{{ block.image.alt or 'Prévisualisation' }}" class="image-preview">
242
+ {% else %}
243
+ <img src="" alt="Preview" class="image-preview" style="display:none;">
244
+ {% endif %}
245
  </div>
246
+
247
+ <div class="form-group mt-3 {% if not block.image %}d-none{% endif %} image-position-controls"> {# Hide position if no image #}
 
 
 
248
  <label for="block-{{ block.id }}-image-position">Position de l'image</label>
249
  <select class="form-control image-position-select" id="block-{{ block.id }}-image-position">
250
  <option value="left" {% if block.image_position == 'left' %}selected{% endif %}>Gauche</option>
 
256
  </div>
257
  {% endfor %}
258
  </div>
259
+
260
  <div class="mt-4 text-center">
261
  <button type="button" id="save-blocks-button" class="btn btn-primary btn-lg">
262
+ <i class="fas fa-save"></i> Enregistrer les blocs
263
  </button>
264
  </div>
265
  </form>
266
  </div>
267
  </div>
268
+
269
  <!-- Image Upload Section -->
270
  <div class="card mb-4">
271
  <div class="card-header">
272
+ <h4>Ajouter une nouvelle image (Galerie)</h4>
273
  </div>
274
  <div class="card-body">
275
+ <form method="POST" action="{{ url_for('admin_bp.upload_image_action') }}" enctype="multipart/form-data" id="image-upload-form"> {# Action points to a dedicated route #}
276
+ <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> {# Add CSRF token if using Flask-WTF #}
277
+ {# Removed 'action' hidden input, handled by route #}
278
+ {# Removed texte_id hidden input, not needed for general upload #}
279
+
280
  <div class="form-group mb-3">
281
  <label for="image">Sélectionner une image</label>
282
+ <input type="file" class="form-control" id="image-file" name="image" accept="image/*" required>
283
  </div>
284
+
285
  <div class="form-group mb-3">
286
  <label for="alt_text">Texte alternatif (pour l'accessibilité)</label>
287
+ <input type="text" class="form-control" id="alt_text" name="alt_text" placeholder="Description de l'image" required>
288
  </div>
289
+
290
+ <img id="upload-image-preview" src="#" alt="Image Preview" style="display: none; max-height: 100px; margin-bottom: 10px;"/>
291
+
292
+
293
  <button type="submit" class="btn btn-success">
294
+ <i class="fas fa-upload"></i> Télécharger et ajouter à la galerie
295
  </button>
296
  </form>
297
+ <div id="upload-status" class="mt-3"></div> {# For AJAX feedback #}
298
+
299
+ <div class="mt-3">
300
+ <a href="{{ url_for('admin_bp.images') }}" class="btn btn-info">
301
+ <i class="fas fa-images"></i> Gérer la galerie d'images
302
+ </a>
303
+ </div>
304
  </div>
305
  </div>
306
  </div>
 
309
 
310
  <!-- Image Gallery Modal -->
311
  <div class="modal fade" id="image-gallery-modal" tabindex="-1" aria-labelledby="imageGalleryModalLabel" aria-hidden="true">
312
+ <div class="modal-dialog modal-xl"> {# Larger modal for more images #}
313
  <div class="modal-content">
314
  <div class="modal-header">
315
+ <h5 class="modal-title" id="imageGalleryModalLabel">Sélectionner une image de la galerie</h5>
316
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
317
  </div>
318
  <div class="modal-body">
319
+ <div id="image-gallery-content" class="row">
320
+ {# Images will be loaded here dynamically by JS or initially #}
321
  {% for image in images %}
322
+ <div class="col-lg-2 col-md-3 col-sm-4 col-6 mb-3">
323
+ <div class="gallery-item text-center" data-image-id="{{ image.id }}">
324
+ <img src="{{ image.src }}" alt="{{ image.alt or 'Image galerie' }}" class="gallery-image img-fluid">
325
+ <small class="d-block mt-1 text-muted" style="word-wrap: break-word;">{{ image.alt or '(Sans description)'}}</small>
326
  </div>
327
  </div>
328
  {% else %}
329
  <div class="col-12">
330
  <div class="alert alert-info">
331
+ Aucune image disponible dans la galerie. Veuillez en télécharger une via la section ci-dessus ou la page "Images".
332
  </div>
333
  </div>
334
  {% endfor %}
 
344
 
345
  {% block scripts %}
346
  <!-- Include Sortable.js for drag and drop functionality -->
347
+ <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
348
+
349
+ <!-- Include Quill.js -->
350
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/quill.snow.css" rel="stylesheet">
351
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/quill.js"></script>
352
+
353
+ <!-- Your Custom Admin JS -->
354
  <script src="{{ url_for('static', filename='js/admin.js') }}"></script>
355
+
356
+ <script>
357
+ // Add specific JS for this page if needed,
358
+ // for example, handling the image upload AJAX response.
359
+
360
+ document.addEventListener('DOMContentLoaded', function() {
361
+ // Show/Hide image position controls based on image presence
362
+ function toggleImagePositionControls(blockEditor) {
363
+ const imageIdInput = blockEditor.querySelector('.block-image-id');
364
+ const positionControls = blockEditor.querySelector('.image-position-controls');
365
+ if (positionControls) {
366
+ if (imageIdInput && imageIdInput.value) {
367
+ positionControls.classList.remove('d-none');
368
+ } else {
369
+ positionControls.classList.add('d-none');
370
+ }
371
+ }
372
+ }
373
+
374
+ // Initial check for all blocks
375
+ document.querySelectorAll('.block-editor').forEach(toggleImagePositionControls);
376
+
377
+ // Add event listeners to image selection/removal buttons to update controls
378
+ document.querySelectorAll('.select-image-btn, .remove-image-btn').forEach(button => {
379
+ button.addEventListener('click', function() {
380
+ // Need a small delay for the image ID value to potentially update
381
+ setTimeout(() => {
382
+ toggleImagePositionControls(this.closest('.block-editor'));
383
+ }, 50);
384
+ });
385
+ });
386
+
387
+ // Update position controls when an image is selected from the gallery
388
+ const galleryModal = document.getElementById('image-gallery-modal');
389
+ if (galleryModal) {
390
+ galleryModal.addEventListener('click', function(event) {
391
+ const galleryItem = event.target.closest('.gallery-item');
392
+ if (galleryItem) {
393
+ const targetBlockId = galleryModal.getAttribute('data-target-block');
394
+ const blockEditor = document.querySelector(`.block-editor[data-block-id="${targetBlockId}"]`);
395
+ if(blockEditor) {
396
+ // Delay necessary as the image selection logic in admin.js runs first
397
+ setTimeout(() => {
398
+ toggleImagePositionControls(blockEditor);
399
+ }, 100);
400
+ }
401
+ }
402
+ });
403
+ }
404
+
405
+ // Image Upload Preview
406
+ const imageFileInput = document.getElementById('image-file');
407
+ const imagePreview = document.getElementById('upload-image-preview');
408
+
409
+ if(imageFileInput && imagePreview) {
410
+ imageFileInput.addEventListener('change', function() {
411
+ if (this.files && this.files[0]) {
412
+ const reader = new FileReader();
413
+ reader.onload = function(e) {
414
+ imagePreview.src = e.target.result;
415
+ imagePreview.style.display = 'block';
416
+ }
417
+ reader.readAsDataURL(this.files[0]);
418
+ } else {
419
+ imagePreview.src = '#';
420
+ imagePreview.style.display = 'none';
421
+ }
422
+ });
423
+ }
424
+
425
+ // Optional: AJAX Image Upload Handling (Example)
426
+ const imageUploadForm = document.getElementById('image-upload-form');
427
+ const uploadStatusDiv = document.getElementById('upload-status');
428
+
429
+ if (imageUploadForm && uploadStatusDiv) {
430
+ imageUploadForm.addEventListener('submit', function(e) {
431
+ e.preventDefault(); // Prevent default form submission
432
+ uploadStatusDiv.innerHTML = '<div class="alert alert-info">Téléchargement en cours...</div>';
433
+ const formData = new FormData(this);
434
+
435
+ fetch(this.action, { // Use the form's action URL
436
+ method: 'POST',
437
+ body: formData,
438
+ headers: {
439
+ // No 'Content-Type': browser sets it correctly for FormData
440
+ 'X-CSRFToken': this.querySelector('input[name="csrf_token"]').value // Send CSRF token if needed
441
+ }
442
+ })
443
+ .then(response => response.json())
444
+ .then(data => {
445
+ if (data.success) {
446
+ uploadStatusDiv.innerHTML = `<div class="alert alert-success">Image "${data.alt}" ajoutée avec succès !</div>`;
447
+ // Optionally: Clear the form
448
+ imageUploadForm.reset();
449
+ if(imagePreview) imagePreview.style.display = 'none';
450
+ // Optionally: Refresh the image gallery modal content (more complex)
451
+ // You might need another fetch call to get updated gallery HTML
452
+ // or just add the new image data to the modal dynamically.
453
+ // For simplicity, we'll just notify the user.
454
+ alert('Image ajoutée à la galerie. Vous pouvez maintenant la sélectionner pour un bloc.');
455
+ } else {
456
+ uploadStatusDiv.innerHTML = `<div class="alert alert-danger">Erreur: ${data.error || 'Impossible de télécharger l\'image.'}</div>`;
457
+ }
458
+ })
459
+ .catch(error => {
460
+ console.error('Upload error:', error);
461
+ uploadStatusDiv.innerHTML = '<div class="alert alert-danger">Erreur lors du téléchargement. Vérifiez la console.</div>';
462
+ });
463
+ });
464
+ }
465
+
466
+
467
+ });
468
+ </script>
469
+ {% endblock %}