aboutsummaryrefslogtreecommitdiff
path: root/public/js/tinymce.js
diff options
context:
space:
mode:
Diffstat (limited to 'public/js/tinymce.js')
-rw-r--r--public/js/tinymce.js647
1 files changed, 354 insertions, 293 deletions
diff --git a/public/js/tinymce.js b/public/js/tinymce.js
index f153246..071c61b 100644
--- a/public/js/tinymce.js
+++ b/public/js/tinymce.js
@@ -1,178 +1,40 @@
1let editors = {}; 1// code à réorganiser
2// seule certaines fonctions ont leur place dans Editor, d'autres servent à manipuler les articles d'une autre manière (déplacer, supprimer...)
3// => encapsuler Editor dans une classe Article (comme la balise) qui existe même quand l'éditeur est fermé
2 4
3function openEditor(id, page = '') {
4 var creation_mode;
5 var real_id;
6 var article;
7 5
8 // création ou modification d'un article? 6/* -- utilisé par les évènements -- */
9 if(id[0] === 'n'){ 7let editors = {};
10 creation_mode = true; 8function openEditor(id){
11 article = document.getElementById(id); 9 if(!editors[id]){
10 editors[id] = new Editor(id); // appel de init à l'intérieur
12 } 11 }
13 else{ 12 //else{editors[id].reopen();}
14 creation_mode = false; 13}
15 // Récupérer et sauvegarder le contenu d'origine de l'article 14// placement d'un nouvel article dans un bloc "Articles libres"
16 real_id = 'i' + id.slice(1); 15function setArticlePlacement(id){
17 article = document.getElementById(id); 16 if(editors[id]){
18 document.getElementById(id).setAttribute('data-original-content', article.innerHTML); 17 editors[id].setArticlePlacement(id);
19 } 18 }
20 19}
21 tinymce.init({ 20function closeEditor(id, restore_old){
22 selector: `#${id}`, 21 if(editors[id]){
23 language: 'fr_FR', // téléchargement ici: https://www.tiny.cloud/get-tiny/language-packages/ 22 editors[id].close(restore_old);
24 language_url: 'js/tinymce-langs/fr_FR.js', // ou installer tweeb/tinymce-i18n avec composer
25 license_key: 'gpl',
26 branding: false,
27 plugins: 'lists link autolink table image media autoresize help',
28 toolbar: 'undo redo newdocument print selectall styles bold italic underline strikethrough fontsizeinput forecolor backcolor fontfamily align numlist bullist outdent indent table link image media help',
29 menubar: false,
30 toolbar_mode: 'wrap',
31 statusbar: false,
32 setup: function (editor) {
33 editor.on('init', function (){
34 editors[id] = editor;
35
36 // boutons "Modifier", "Supprimer", "déplacer vers le haut", "déplacer vers le bas", "Annuler" et "Soumettre"
37 document.querySelector(`#cancel-${id}`).classList.remove('hidden');
38 document.querySelector(`#submit-${id}`).classList.remove('hidden');
39 if(creation_mode === false){
40 document.querySelector(`#edit-${id}`).classList.add('hidden');
41 if(page != 'article'){
42 document.querySelector(`#position_up-${id}`).classList.add('hidden');
43 document.querySelector(`#position_down-${id}`).classList.add('hidden');
44 document.querySelector(`#delete-${real_id}`).classList.add('hidden');
45 }
46 }
47 else{
48 document.querySelector(`#new-${id}`).classList.add('hidden'); // id = new-new-id_node
49 }
50 });
51 let skipPastePreProcess = false;
52 editor.on('Paste', function (e){ // déclenchement AVANT PastePreProcess et quelque que soit le contenu collé
53 const clipboardData = (e.clipboardData || e.originalEvent.clipboardData);
54 if(!clipboardData){
55 return;
56 }
57 const items = clipboardData.items;
58 let foundImage = false;
59
60 for(let i = 0; i < items.length; i++){
61 let item = items[i];
62
63 if(item.type.indexOf('image') !== -1){ // test type MIME contenant image
64 foundImage = true;
65
66 const file = item.getAsFile(); // presse-papier => fichier lisible
67 const reader = new FileReader();
68
69 reader.onload = function (event){ // fonction exécutée lorsque reader.readAsDataURL(file) est terminée
70 const base64Data = event.target.result; // données de l'image
71
72 fetch('index.php?action=upload_image_base64', {
73 method: 'POST',
74 headers: { 'Content-Type': 'application/json' },
75 body: JSON.stringify({ image_base64: base64Data })
76 })
77 .then(response => response.json())
78 .then(data => {
79 if(data.location){
80 editor.insertContent('<img src="' + data.location + '">');
81 }
82 })
83 .catch(error => {
84 console.error('Erreur lors de l’upload de l’image base64 :', error);
85 });
86 };
87 reader.readAsDataURL(file); // lecture asynchrone du fichier
88 }
89 }
90
91 if(foundImage){
92 e.preventDefault(); // supprime le collage automatiue
93 skipPastePreProcess = true; // désactiver le PastePreProcess pour ce collage
94 }
95 });
96 editor.on('PastePreProcess', function (e){ // déclenchement au collage AVANT insertion dans l'éditeur
97 const parser = new DOMParser();
98 const doc = parser.parseFromString(e.content, 'text/html');
99 const images = doc.querySelectorAll('img');
100
101 let downloads_in_progress = [];
102
103 images.forEach(img => {
104 if(img.src.startsWith('file://')){ // détection d'images non insérables
105 console.warn('Image locale non insérable dans tinymce :', img.src);
106 img.outerHTML = `<div style="border:1px solid red; padding:10px; margin:5px 0; background-color:#ffe6e6; color:#a94442; font-size:14px;">
107 "Image locale non insérée (vient-elle d'un document LibreOffice ?). Effacez ce message rouge et copiez-collez l'image seule.</div>`;
108 }
109 else if(img.src.startsWith('http')){ // détection d'images web
110 const promise = fetch('index.php?action=upload_image_url', { // promesse d'un fichier téléchargeable sur le serveur
111 method: 'POST',
112 headers: { 'Content-Type': 'application/json' },
113 body: JSON.stringify({ image_url: img.src })
114 })
115 .then(response => response.json())
116 .then(data => {
117 if(data.location){
118 img.src = data.location; // remplacer l'image par celle du serveur
119 }
120 })
121 .catch(error => {
122 console.error('Erreur lors de l’upload de l’image distante:', error);
123 });
124
125 downloads_in_progress.push(promise);
126 }
127 });
128
129 // une image web ou plus: différer l'insertion dans l'éditeur le temps que le serveur télécharge les images
130 if(downloads_in_progress.length > 0){
131 e.preventDefault();
132
133 Promise.all(downloads_in_progress).then(() => {
134 e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc)
135 editor.insertContent(e.content);
136 });
137 }
138 else{
139 e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc)
140 }
141 }); // fin editor.on('PastePreProcess'...
142 },
143 // upload d'image natif de tinymce avec le bouton "Insérer une image"
144 images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
145 const formData = new FormData();
146 formData.append("file", blobInfo.blob());
147
148 fetch("index.php?action=upload_image_tinymce", {
149 method: "POST",
150 body: formData
151 })
152 .then(response => response.json())
153 .then(data => {
154 if(data.location) {
155 resolve(data.location);
156 }
157 else {
158 reject("Erreur: Chemin d'image invalide");
159 }
160 })
161 .catch(error => {
162 reject("Erreur lors de l'upload");
163 });
164 }),
165 image_caption: true
166 });
167
168 // Remplacer le contenu de l'article par l'éditeur
169 if(creation_mode === false){
170 document.getElementById(id).innerHTML = article.innerHTML;
171 } 23 }
172} 24}
173 25function submitArticle(id, clone = null)
174function deleteArticle(id, page = '') { 26{
175 if (confirm('Voulez-vous vraiment supprimer cet article ?')) 27 if(editors[id]){
28 editors[id].submit(clone);
29 }
30 else if(window.Config.page === "article" && id[0] === 'n'){ // bouton Tout enregistrer (pas d'éditeur)
31 editors[id] = new Editor(id);
32 editors[id].submit();
33 }
34}
35// standalone contraîrement aux autres fonctions ici
36function deleteArticle(id){
37 if(confirm('Voulez-vous vraiment supprimer cet article ?'))
176 { 38 {
177 // Envoyer une requête au serveur pour supprimer l'article 39 // Envoyer une requête au serveur pour supprimer l'article
178 fetch('index.php?action=delete_article', { 40 fetch('index.php?action=delete_article', {
@@ -199,146 +61,337 @@ function deleteArticle(id, page = '') {
199 } 61 }
200} 62}
201 63
202function closeEditor(id, page = '', restore_old = true) 64
65
66class Editor
203{ 67{
204 var creation_mode; 68 constructor(id){
205 var real_id; 69 this.id = id;
206 var article; 70 this.article = document.getElementById(this.id);
207 var parent; 71 this.creation_mode = this.id[0] === 'n' ? true : false;
208 72 //this.isOpen = false;
209 // création ou modification d'un article? 73 this.tiny_instance = null;
210 if(id[0] === 'n'){
211 creation_mode = true;
212 }
213 else{
214 creation_mode = false;
215 }
216 74
217 // Fermer l'éditeur 75 // moche, on ne devrait sortir l'envoi des données avec fetch de Editor.submit
218 tinymce.remove(`#${id}`); 76 if(!this.creation_mode || window.Config.page !== 'article'){
219 delete editors[id]; 77 if(this.creation_mode && window.Config.page !== 'article'){
220 78 this.setArticlePlacement(this.id);
221 if(creation_mode){ 79 }
222 article = document.getElementById(id); 80 else{
223 parent = findParent(article, 'section'); 81 // insérer le contenu de l'article dans l'éditeur
224 } 82 this.article.setAttribute('data-original-content', this.article.innerHTML);
225 else{ 83 }
226 real_id = 'i' + id.slice(1); 84 this.init();
85 }
86 //else // bouton Tout enregistrer, pas d'éditeur
227 } 87 }
228 88
229 // Restaurer le contenu d'origine de l'article 89 setArticlePlacement(id_block){
230 if(restore_old){ 90 const checked_button = document.querySelector('input[name="article_placement-' + id_block + '"]:checked');
231 const originalContent = document.getElementById(id).getAttribute('data-original-content'); 91 if(checked_button){ // vrai clic
232 document.getElementById(id).innerHTML = originalContent; 92 this.placement = checked_button.value;
93 }
94 else{
95 document.getElementById('radio_last-' + id_block).checked = true; // faux clic
96 this.placement = 'last';
97 }
233 } 98 }
99
100 init(){
101 tinymce.init({
102 selector: `#${this.id}`, // avec un # comme dans querySelector
103 language: 'fr_FR', // téléchargement ici: https://www.tiny.cloud/get-tiny/language-packages/
104 language_url: 'js/tinymce-langs/fr_FR.js', // ou installer tweeb/tinymce-i18n avec composer
105 license_key: 'gpl',
106 branding: false,
107 plugins: 'lists link autolink table image media autoresize help',
108 toolbar: 'undo redo newdocument print selectall styles bold italic underline strikethrough fontsizeinput forecolor backcolor fontfamily align numlist bullist outdent indent table link image media help',
109 menubar: false,
110 toolbar_mode: 'wrap',
111 statusbar: false,
112 // les fonctions fléchées permettent de garder le contexte (= this)
113 setup: (editor) => {
114 editor.on('init', () => {
115 this.tiny_instance = editor;
116
117 // boutons "Modifier", "Supprimer", "déplacer vers le haut", "déplacer vers le bas", "Annuler" et "Soumettre"
118 document.getElementById(`cancel-${this.id}`).classList.remove('hidden');
119 document.getElementById(`submit-${this.id}`).classList.remove('hidden');
120 const radio = document.getElementById(`radio-${this.id}`);
121 if(radio){
122 radio.classList.remove('hidden');
123 }
124 if(this.creation_mode){
125 document.getElementById(`new-${this.id}`).classList.add('hidden'); // id = new-new-id_node
126 }
127 else{
128 document.getElementById(`edit-${this.id}`).classList.add('hidden');
129 if(window.Config.page !== 'article'){
130 document.getElementById(`position_up-${this.id}`).classList.add('hidden');
131 document.getElementById(`position_down-${this.id}`).classList.add('hidden');
132 document.getElementById(`delete-${('i' + this.id.slice(1))}`).classList.add('hidden');
133 }
134 }
135 });
136 let skipPastePreProcess = false;
137 editor.on('Paste', function (e){ // déclenchement AVANT PastePreProcess et quelque que soit le contenu collé
138 const clipboardData = (e.clipboardData || e.originalEvent.clipboardData);
139 if(!clipboardData){
140 return;
141 }
142 const items = clipboardData.items;
143 let foundImage = false;
144
145 for(let i = 0; i < items.length; i++){
146 let item = items[i];
147
148 if(item.type.indexOf('image') !== -1){ // test type MIME contenant image
149 foundImage = true;
234 150
235 // boutons: "Nouvel article", Modifier", "Supprimer", "déplacer vers le haut", "déplacer vers le bas", "Annuler" et "Valider" 151 const file = item.getAsFile(); // presse-papier => fichier lisible
236 document.querySelector(`#cancel-${id}`).classList.add('hidden'); 152 const reader = new FileReader();
237 document.querySelector(`#submit-${id}`).classList.add('hidden'); 153
238 if(creation_mode){ 154 reader.onload = function (event){ // fonction exécutée lorsque reader.readAsDataURL(file) est terminée
239 document.querySelector(`#new-${id}`).classList.remove('hidden'); // id = new-new-id_node 155 const base64Data = event.target.result; // données de l'image
156
157 fetch('index.php?action=upload_image_base64', {
158 method: 'POST',
159 headers: { 'Content-Type': 'application/json' },
160 body: JSON.stringify({ image_base64: base64Data })
161 })
162 .then(response => response.json())
163 .then(data => {
164 if(data.location){
165 editor.insertContent('<img src="' + data.location + '">');
166 }
167 })
168 .catch(error => {
169 console.error('Erreur lors de l’upload de l’image base64 :', error);
170 });
171 };
172 reader.readAsDataURL(file); // lecture asynchrone du fichier
173 }
174 }
175
176 if(foundImage){
177 e.preventDefault(); // supprime le collage automatiue
178 skipPastePreProcess = true; // désactiver le PastePreProcess pour ce collage
179 }
180 });
181 editor.on('PastePreProcess', function (e){ // déclenchement au collage AVANT insertion dans l'éditeur
182 const parser = new DOMParser();
183 const doc = parser.parseFromString(e.content, 'text/html');
184 const images = doc.querySelectorAll('img');
185
186 let downloads_in_progress = [];
187
188 images.forEach(img => {
189 if(img.src.startsWith('file://')){ // détection d'images non insérables
190 console.warn('Image locale non insérable dans tinymce :', img.src);
191 img.outerHTML = `<div style="border:1px solid red; padding:10px; margin:5px 0; background-color:#ffe6e6; color:#a94442; font-size:14px;">
192 "Image locale non insérée (vient-elle d'un document LibreOffice ?). Effacez ce message rouge et copiez-collez l'image seule.</div>`;
193 }
194 else if(img.src.startsWith('http')){ // détection d'images web
195 const promise = fetch('index.php?action=upload_image_url', { // promesse d'un fichier téléchargeable sur le serveur
196 method: 'POST',
197 headers: { 'Content-Type': 'application/json' },
198 body: JSON.stringify({ image_url: img.src })
199 })
200 .then(response => response.json())
201 .then(data => {
202 if(data.location){
203 img.src = data.location; // remplacer l'image par celle du serveur
204 }
205 })
206 .catch(error => {
207 console.error('Erreur lors de l’upload de l’image distante:', error);
208 });
209
210 downloads_in_progress.push(promise);
211 }
212 });
213
214 // une image web ou plus: différer l'insertion dans l'éditeur le temps que le serveur télécharge les images
215 if(downloads_in_progress.length > 0){
216 e.preventDefault();
217
218 Promise.all(downloads_in_progress).then(() => {
219 e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc)
220 editor.insertContent(e.content);
221 });
222 }
223 else{
224 e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc)
225 }
226 }); // fin editor.on('PastePreProcess'...
227 },
228 // upload d'image natif de tinymce avec le bouton "Insérer une image"
229 images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
230 const formData = new FormData();
231 formData.append("file", blobInfo.blob());
232
233 fetch("index.php?action=upload_image_tinymce", {
234 method: "POST",
235 body: formData
236 })
237 .then(response => response.json())
238 .then(data => {
239 if(data.location) {
240 resolve(data.location);
241 }
242 else {
243 reject("Erreur: Chemin d'image invalide");
244 }
245 })
246 .catch(error => {
247 reject("Erreur lors de l'upload");
248 });
249 }),
250 image_caption: true
251 });
240 } 252 }
241 else{ 253
242 document.querySelector(`#edit-${id}`).classList.remove('hidden'); 254 close(restore_old = true){
243 if(page != 'article'){ 255 tinymce.remove(`#${this.id}`); // avec un # comme dans querySelector
244 document.querySelector(`#position_up-${id}`).classList.remove('hidden'); 256 delete editors[this.id];
245 document.querySelector(`#position_down-${id}`).classList.remove('hidden'); 257
246 document.querySelector(`#delete-${id}`).classList.remove('hidden'); 258 // Restaurer le contenu d'origine de l'article
259 if(restore_old){
260 const original_content = document.getElementById(this.id).getAttribute('data-original-content');
261 document.getElementById(this.id).innerHTML = original_content;
247 } 262 }
248 }
249}
250 263
251function submitArticle(id, page = '', clone = null) 264 // boutons: "Nouvel article", Modifier", "Supprimer", "déplacer vers le haut", "déplacer vers le bas", "Annuler" et "Valider"
252{ 265 document.getElementById(`cancel-${this.id}`).classList.add('hidden');
253 var editor; 266 document.getElementById(`submit-${this.id}`).classList.add('hidden');
254 var content; 267
255 const params = new URL(document.location).searchParams; // "search" = ? et paramètres, searchParams = objet avec des getters 268 const radio = document.getElementById(`radio-${this.id}`);
256 269 if(radio){
257 // clic sur "Tout enregistrer" 270 document.querySelector('input[name="article_placement-' + this.id + '"]:checked').checked = false; // décoche l'option "en mémoire"
258 if(id[0] === 'n' && page === 'article'){ 271 radio.classList.add('hidden');
259 const prefixes = ['t', 'p', 'i', 'd']; 272 }
260 const allElemsWithId = document.querySelectorAll('.data'); 273
261 content = {}; 274 if(this.creation_mode){
262 var id_from_builder; 275 document.getElementById(`new-${this.id}`).classList.remove('hidden'); // id = new-new-id_node
263 276 }
264 allElemsWithId.forEach(element => { 277 else{
265 const first_letter = element.id.charAt(0).toLowerCase(); 278 document.getElementById(`edit-${this.id}`).classList.remove('hidden');
266 if(prefixes.includes(first_letter)){ 279 if(window.Config.page !== 'article'){
267 content[first_letter] = element.innerHTML; 280 document.getElementById(`position_up-${this.id}`).classList.remove('hidden');
268 if(first_letter === 'i'){ 281 document.getElementById(`position_down-${this.id}`).classList.remove('hidden');
269 id_from_builder = element.id; 282 document.getElementById(`delete-${this.id}`).classList.remove('hidden');
270 }
271 } 283 }
272 })
273 content['d'] = dateToISO(content['d']);
274 }
275 // champs à remplir des nouvelles "news"
276 else if(page === 'article' && params != null && params.get("id")[0] === 'n'){
277 closeEditor(id, page, false);
278 //makeNewArticleButtons(id, id, clone);
279 return;
280 }
281 // dans les autres cas, on doit pouvoir récupérer l'éditeur
282 else{
283 // l'éditeur correspond à l'article OU page "article" à un élément: titre, aperçu, article
284 editor = editors[id];
285 if(!editor) {
286 console.error('Éditeur non trouvé pour l\'article:', id);
287 return;
288 } 284 }
289 content = editor.getContent();
290 } 285 }
291 286
292 // Envoi AJAX au serveur 287 submit(clone = null){
293 fetch('index.php?action=editor_submit', { 288 //var editor;
294 method: 'POST', 289 var content;
295 headers: { 290 const params = new URL(document.location).searchParams; // "search" = ? et paramètres, searchParams = objet avec des getters
296 'Content-Type': 'application/json' 291 // à comparer avec: new URLSearchParams(window.location.search);
297 }, 292 // c'est pareil ou pas?
298 body: JSON.stringify({id: id, content: content}) 293
299 }) 294 // clic sur "Tout enregistrer" (ne devrait pas se situer dans Editor)
300 .then(response => response.json()) 295 if(this.creation_mode && window.Config.page === 'article'){
301 .then(data => { 296 const prefixes = ['t', 'p', 'i', 'd'];
302 if(data.success) { 297 const allElemsWithId = document.querySelectorAll('.data');
303 //console.log(data.article_id); 298 content = {};
304 if(id[0] === 'n' && page === 'article'){ 299 var id_from_builder;
305 console.log('données envoyées au serveur avec succès.'); 300
306 301 allElemsWithId.forEach(element => {
307 // redirection page de l'article 302 const first_letter = element.id.charAt(0).toLowerCase();
308 window.setTimeout(function(){ 303 if(prefixes.includes(first_letter)){
309 const url_params = new URLSearchParams(window.location.search); // le "$_GET" de javascript 304 content[first_letter] = element.innerHTML;
310 location.href = "index.php?page=article&id=" + data.article_id + "&from=" + url_params.get('from'); 305 if(first_letter === 'i'){
311 }, 0); 306 id_from_builder = element.id;
312 } 307 }
313 else{
314 // Fermer l'éditeur et mettre à jour le contenu de l'article
315 closeEditor(id, page, false);
316 if(id[0] === 'n'){
317 makeNewArticleButtons(id, data.article_id, clone);
318 } 308 }
319 } 309 })
310 content['d'] = dateToISO(content['d']);
320 } 311 }
312 // champs à remplir des nouvelles "news"
313 else if(window.Config.page === 'article' && params != null && params.get("id")[0] === 'n'){
314 this.close(false);
315 return;
316 }
317 // dans les autres cas, on doit pouvoir récupérer l'éditeur
321 else{ 318 else{
322 alert('Erreur lors de la sauvegarde de l\'article.'); 319 // l'éditeur correspond à l'article OU si page = "article" à un élément: titre, aperçu, article
320 //editor = editors[id];
321 if(!this.tiny_instance){
322 console.error("Éditeur non trouvé pour l'article:", this.id);
323 return;
324 }
325 content = this.tiny_instance.getContent();
323 } 326 }
324 }) 327
325 .catch(error => { 328 let fetch_params = {id: this.id, content: content};
326 console.error('Erreur:', error); 329 if(this.placement){
327 }); 330 fetch_params['placement'] = this.placement;
331 }
332
333 // Envoi AJAX au serveur
334 fetch('index.php?action=editor_submit', {
335 method: 'POST',
336 headers: {'Content-Type': 'application/json'},
337 body: JSON.stringify(fetch_params)
338 })
339 .then(response => response.json())
340 .then(data => {
341 if(data.success)
342 {
343 if(this.creation_mode && window.Config.page === 'article'){
344 console.log('données envoyées au serveur avec succès.');
345
346 // redirection page de l'article
347 window.setTimeout(function(){
348 const url_params = new URLSearchParams(window.location.search); // le "$_GET" de javascript
349 location.href = "index.php?page=article&id=" + data.article_id + "&from=" + url_params.get('from');
350 }, 0);
351 }
352 else{
353 // Fermer l'éditeur et mettre à jour le contenu de l'article
354 this.close(false);
355 if(this.creation_mode){
356 makeNewArticleButtons(this.id, data.article_id, clone, this.placement);
357 }
358 }
359 }
360 else{
361 alert('Erreur lors de la sauvegarde de l\'article.');
362 }
363 })
364 .catch(error => {
365 console.error('Erreur:', error);
366 });
367 }
368
369 //reopen(){}
370
371 /*destroy(){
372 this.close();
373 delete editors[this.id];
374 console.log(`Editor ${this.id} détruit.`);
375 }*/
328} 376}
329 377
330function makeNewArticleButtons(id, article_id, clone) 378
379
380
381
382// restera ici jusqu'à ce que la gestion des balises soient faite ailleurs
383function makeNewArticleButtons(id, article_id, clone, placement = 'last')
331{ 384{
332 var share_btn = document.querySelector(`.share.hidden`); // combinaison de deux classes 385 var share_btn = document.querySelector(`.share.hidden`); // combinaison de deux classes
333 var new_btn = document.querySelector(`#new-${id}`); 386 var new_btn = document.getElementById(`new-${id}`);
334 var edit_btn = document.querySelector(`#edit-${id}`); 387 var edit_btn = document.getElementById(`edit-${id}`);
335 var pos_up_btn = document.querySelector(`#position_up-${id}`); 388 var pos_up_btn = document.getElementById(`position_up-${id}`);
336 var pos_down_btn = document.querySelector(`#position_down-${id}`); 389 var pos_down_btn = document.getElementById(`position_down-${id}`);
337 var delete_btn = document.querySelector(`#delete-${id}`); 390 var delete_btn = document.getElementById(`delete-${id}`);
338 var cancel_btn = document.querySelector(`#cancel-${id}`); 391 var cancel_btn = document.getElementById(`cancel-${id}`);
339 var submit_btn = document.querySelector(`#submit-${id}`); 392 var submit_btn = document.getElementById(`submit-${id}`);
340 393
341 share_btn.classList.remove('hidden') 394 share_btn.classList.remove('hidden');
342 new_btn.classList.add('hidden'); 395 new_btn.classList.add('hidden');
343 edit_btn.classList.remove('hidden'); 396 edit_btn.classList.remove('hidden');
344 pos_up_btn.classList.remove('hidden'); 397 pos_up_btn.classList.remove('hidden');
@@ -348,7 +401,7 @@ function makeNewArticleButtons(id, article_id, clone)
348 //submit_btn.classList.add('hidden'); 401 //submit_btn.classList.add('hidden');
349 402
350 var article = document.getElementById(id); 403 var article = document.getElementById(id);
351 var parent = findParent(article, 'article'); 404 var article_elem_parent = findParentByTagName(article, 'article');
352 405
353 share_btn.setAttribute('onclick', "copyInClipBoard('" + window.location.href + article_id + "')"); // # de l'ancre ajouté au clic sur le lien ouvrant l'éditeur 406 share_btn.setAttribute('onclick', "copyInClipBoard('" + window.location.href + article_id + "')"); // # de l'ancre ajouté au clic sur le lien ouvrant l'éditeur
354 article.id = article_id; 407 article.id = article_id;
@@ -364,8 +417,16 @@ function makeNewArticleButtons(id, article_id, clone)
364 cancel_btn.querySelector('button').setAttribute('onclick', "closeEditor('" + article_id + "')"); 417 cancel_btn.querySelector('button').setAttribute('onclick', "closeEditor('" + article_id + "')");
365 submit_btn.id = 'submit-' + article_id; 418 submit_btn.id = 'submit-' + article_id;
366 submit_btn.querySelector('button').setAttribute('onclick', "submitArticle('" + article_id + "')"); 419 submit_btn.querySelector('button').setAttribute('onclick', "submitArticle('" + article_id + "')");
420
421 var section_child = article_elem_parent.parentNode.querySelector('.section_child'); // renommer section_child
422
423 // parentNode vise la balise section
424 article_elem_parent.parentNode.replaceChild(clone.cloneNode(true), article_elem_parent); // clone du squelette pour le garder intact
367 425
368 var next_div = parent.nextElementSibling.nextElementSibling; 426 if(placement === 'first'){
369 parent.parentNode.replaceChild(clone.cloneNode(true), parent); // clone du squelette pour le garder intact 427 section_child.insertBefore(article_elem_parent, section_child.firstChild);
370 next_div.appendChild(parent); 428 }
429 else{ // = 'last'
430 section_child.appendChild(article_elem_parent);
431 }
371} \ No newline at end of file 432} \ No newline at end of file