diff options
author | polo <ordipolo@gmx.fr> | 2022-02-17 18:13:00 +0100 |
---|---|---|
committer | polo <ordipolo@gmx.fr> | 2022-02-17 18:13:00 +0100 |
commit | 787d03e48471ba62cd830379428f04d996f0b74b (patch) | |
tree | e9f98c7b9288c4530b50985688dd82622106ba2d /view/template-formulaires.php | |
parent | 29df6f1362745eabf4fbcaedf309eb63795152fa (diff) | |
download | melaine-787d03e48471ba62cd830379428f04d996f0b74b.zip |
model update
Diffstat (limited to 'view/template-formulaires.php')
-rw-r--r-- | view/template-formulaires.php | 375 |
1 files changed, 177 insertions, 198 deletions
diff --git a/view/template-formulaires.php b/view/template-formulaires.php index e864719..a3dc9cd 100644 --- a/view/template-formulaires.php +++ b/view/template-formulaires.php | |||
@@ -1,199 +1,178 @@ | |||
1 | <?php | 1 | <?php |
2 | // view/template-formulaire.php | 2 | // view/template-formulaire.php |
3 | 3 | ||
4 | // voici la partie HTML et javascript du ckeditor, | 4 | // voici la partie HTML et javascript du ckeditor: |
5 | // elle permette d'insérer l'éditeur dans la page avec un formulaire qui comporte 4 éléments: | 5 | // on crée un formulaire <form> avec zones de saisie et boutons |
6 | // barre d'outils, zone de saisie, formulaire caché, bouton "valider" | 6 | // l'éditeur est inséré par lib/ckeditor5/build/ckeditor.js |
7 | 7 | // en remplaçant les balises <textarea> | |
8 | // le formulaire est presque classique, en effet on utilise le ckeditor 5 dans sa version "Document" (ou DecoupledEditor): | 8 | |
9 | // - avantage: plus de possibilité dans la barre d'outils (se rapproche d'un traitement de texte) | 9 | // il est en version "Classic" customizée pour pouvoir ressembler à la version "DecoupledEditor", on peut le créer ici: |
10 | // - inconvénient: on ne peut utiliser la balise <textarea> qu'on remplace par une <div> | 10 | // https://ckeditor.com/ckeditor-5/online-builder/ |
11 | 11 | // la version DecoupledEditor ne peut remplacer une <textarea>, il faut une <div>, ce qui interdit la méthode 1) ci-dessous | |
12 | // pour pouvoir envoyer le contenu dans le POST, on a deux possibilité: | 12 | |
13 | // - savoir coder en javascript ! et donc faire de l'AJAX, dans ce cas on n'a même plus besoin de formulaire, le contenu est envoyé au serveur au fur et à mesure! ce sera l'objet d'une future amélioration | 13 | // pour envoyer les données au serveur, on a trois méthodes: |
14 | // - utiliser l'astuce du formulaire caché ! | 14 | // 1) facile: le JS de la bibliothèque remplace la <textarea> par l'éditeur, noter que c'est impossible avec la version DecoupledEditor du ckeditor5, d'ou le choix la "custom" |
15 | 15 | // 2) moins facile; technique du formulaire caché (l'éditeur remplace une <div>), à la validation, du JS (appelé avec onload="") place les données dans l'<input> caché duquel part le POST | |
16 | // le javascript place les données dans le formulaire caché | 16 | // 3) méthode AJAX (compliquée): le formulaire ni le bouton "valider" ne sont plus nécessaires et l'enregistrement des données est immédiat |
17 | // avec la fonction envoiDonnees(), les données se retrouvent dans une <input> et sont donc envoyées avec par la POST (haha) | 17 | |
18 | 18 | ||
19 | 19 | // falsification de requête inter-site - CSRF | |
20 | // variable $inputsAlbum (page discographie uniquement) | 20 | // à faire plus tard |
21 | // note: on ne peut préremplir le champ input texte | 21 | |
22 | // solution: on affiche le nom du fichier, si l'utilisateur en télécharge un autre, on le remplace | 22 | |
23 | ob_start(); | 23 | // variable $inputsAlbum (page discographie uniquement) |
24 | ?> | 24 | // attention: on ne peut préremplir le champ input file |
25 | <p><i>Infos qui seront affichées sur cette page:</i></p> | 25 | // solution: on affiche le nom du fichier, si l'utilisateur en télécharge un autre, on le remplace; |
26 | <label for="titre" >Titre</label> | 26 | // il devient donc impossible de n'avoir aucun fichier |
27 | <input type="text" name="titre" value="<?= $vignette[0] ?>" required ><br /> | 27 | ob_start(); |
28 | <label for="annee" >Année</label> | 28 | ?> |
29 | <input type="text" name="annee" value="<?= $vignette[1] ?>" required ><br /> | 29 | <img class="imageFormulaire" src="<?= $imageFormulaire ?>" > |
30 | <label for="pochette" >Pochette du disque (jpg ou png) : <?= $vignette[2] ?></label><br/> | 30 | <br/> |
31 | <input type="file" name="upload" > | 31 | <p><i>Infos qui seront affichées sur cette page:</i></p> |
32 | <br /><br /> | 32 | <label for="titre" >Titre</label> |
33 | <?php | 33 | <input type="text" name="titre" value="<?= $vignette[0] ?>" required ><br /> |
34 | $inputsAlbum = ob_get_clean(); | 34 | <label for="annee" >Année</label> |
35 | 35 | <input type="text" name="annee" value="<?= $vignette[1] ?>" required ><br /> | |
36 | 36 | <label for="pochette" >Pochette du disque (jpg ou png) : <?= $vignette[2] ?></label><br/> | |
37 | // variable $editeurHTML | 37 | <input type="file" name="upload" ><br /><br /><br /> |
38 | ob_start(); | 38 | <?php |
39 | ?> | 39 | $inputsAlbum = ob_get_clean(); |
40 | 40 | ||
41 | <div class="conteneur_article" > | 41 | |
42 | <form action="index.php?page=<?= $page_actuelle ?>&article=<?= $album_code ?>&action=submit" method="post" enctype="multipart/form-data" > | 42 | // variable $editeurHTML |
43 | <?php | 43 | ob_start(); |
44 | if($page_actuelle == 'discographie') | 44 | ?> |
45 | { | 45 | |
46 | echo($inputsAlbum . "<p><i>Infos qui seront affichées dans la page spécifique à cet album:</i></p>"); | 46 | <div class="conteneur_article" > |
47 | } | 47 | <form action="index.php?page=<?= $page_actuelle ?><?= $fileCodeArgument ?>&action=submit" method="post" enctype="multipart/form-data" > |
48 | ?> | 48 | <?php |
49 | 49 | if($page_actuelle == 'discographie') | |
50 | <textarea id="editor" name="contenu" ></textarea> | 50 | { |
51 | <?php | 51 | echo($inputsAlbum . "<p><i>Infos qui seront affichées dans la page spécifique à cet album:</i></p>"); |
52 | // falsification de requête inter-site | 52 | } |
53 | // on ajoute un formulaire caché avec une valeur aléatoire cryptée utilisable une seule fois (=jeton) | 53 | ?> |
54 | 54 | ||
55 | // "Vous pouvez rendre chaque jeton utilisable une seule fois et ainsi éviter de rejouer plusieurs fois la même requête. | 55 | <textarea id="editor" name="contenu" ></textarea> |
56 | // Les jetons sont stockés dans le back-office. | 56 | <input class="boutonSubmitEditeur" type="submit" value="Valider" /> |
57 | // Une rotation des jetons est effectuée quand le nombre maximum a été atteint, les plus vieux en premier. | 57 | <a class="boutonAnnuler" href="index.php?page=<?= $page_actuelle ?>" > |
58 | // Chaque jeton peut être lié à une URL spécifique. | 58 | <input type="button" value="Annuler" /> |
59 | // Si un jeton est intercepté, il ne peut pas être utilisé dans un autre contexte. | 59 | </a> |
60 | // Si besoin, les jetons peuvent être attachés à une adresse IP spécifique. | 60 | |
61 | // Depuis la version v2.1, les jetons peuvent être réutilisés (par exemple pour les requêtes AJAX). | 61 | <script> |
62 | // Si vous n’utilisez pas un framework qui gère la protection CSRF pour vous, jetez un oeil à Anti-CSRF." | 62 | let editor; // variable utilisable depuis une fonction |
63 | 63 | ||
64 | // une bibli qui fait ça: https://github.com/paragonie/anti-csrf | 64 | // ATTENTION: si l'éditeur ne fonctionne pas, empêcher qu'on puisse cliquer sur Valider! |
65 | ?> | 65 | // Il y a aussi des paramètres dans le fichier de config: ckeditor/webpack.config.js |
66 | 66 | ClassicEditor | |
67 | <input class="boutonSubmitEditeur" type="submit" value="Valider" onclick="envoiDonnees();" /> | 67 | .create( document.querySelector( '#editor' ),{ |
68 | 68 | language: 'fr', | |
69 | <script> | 69 | |
70 | let editor; // variable utilisable depuis une fonction | 70 | // barre d'outils à adapter au "custom build" |
71 | 71 | toolbar: { | |
72 | // code exécuté à la validation du formulaire | 72 | items: [ 'undo', 'redo', 'selectAll', '|', 'heading', '|', 'alignment', 'bulletedList', 'numberedList', 'todoList', 'blockQuote', 'horizontalLine', '-', 'bold', 'italic', 'underline', |
73 | function envoiDonnees() | 73 | //'strikethrough', |
74 | { | 74 | '|', |
75 | // supprimer le positionnement absolu de l'iframe | 75 | //'fontFamily', |
76 | //~ let balisesIframe = document.getElementsByTagName("iframe"); | 76 | 'fontColor', 'fontSize', 'highlight', '|', 'imageInsert', 'link', |
77 | //~ for(var i = 0; i < balisesIframe.length; i++) | 77 | //'htmlEmbed', |
78 | //~ { | 78 | //'mediaEmbed', |
79 | //~ alert(balisesIframe[i].getAttribute("style")); // affiche le CSS | 79 | 'insertTable' |
80 | //~ balisesIframe[i].removeAttribute("style"); | 80 | //'|', 'textPartLanguage' |
81 | //~ alert(balisesIframe[i].getAttribute("style")); // affiche null | 81 | ], |
82 | //~ } | 82 | // multiligne automatique (le '-' dans la liste permet de choisir l'endroit où couper) |
83 | } | 83 | shouldNotGroupWhenFull: true |
84 | 84 | ||
85 | // ATTENTION: si l'éditeur ne fonctionne pas, empêcher qu'on puisse cliquer sur Valider! | 85 | // noter que 'fontFamily' ne comporte que des polices microsoft => problèmes de droits? |
86 | // Il y a aussi des paramètres dans le fichier de config: ckeditor/webpack.config.js | 86 | // de plus, il faut que le navigateur connaisse toutes les polices |
87 | ClassicEditor | 87 | }, |
88 | .create( document.querySelector( '#editor' ),{ | 88 | |
89 | language: 'fr', | 89 | // barre d'outils dans une image |
90 | 90 | image: { | |
91 | // barre d'outils à adapter au build | 91 | toolbar: [ |
92 | toolbar: { | 92 | 'imageTextAlternative', |
93 | items: [ 'undo', 'redo', 'selectAll', '|', 'heading', '|', 'alignment', 'bulletedList', 'numberedList', 'todoList', 'blockQuote', 'horizontalLine', '-', 'bold', 'italic', 'underline', | 93 | 'imageStyle:full', |
94 | //'strikethrough', | 94 | 'imageStyle:side', |
95 | '|', | 95 | 'linkImage' |
96 | //'fontFamily', | 96 | ] |
97 | 'fontColor', 'fontSize', 'highlight', '|', 'imageInsert', 'link', | 97 | }, |
98 | //'htmlEmbed', | 98 | |
99 | //'mediaEmbed', | 99 | // barre d'outils dans un tableau |
100 | 'insertTable' | 100 | table: { |
101 | //'|', 'textPartLanguage' | 101 | contentToolbar: [ |
102 | ], | 102 | 'tableColumn', |
103 | // multiligne automatique (le '-' dans la liste permet de choisir l'endroit où couper) | 103 | 'tableRow', |
104 | shouldNotGroupWhenFull: true | 104 | 'mergeTableCells', |
105 | 105 | //'tableCellProperties', | |
106 | // noter que 'fontFamily' ne comporte que des polices microsoft => problèmes de droits? | 106 | 'tableProperties' |
107 | // de plus, il faut que le navigateur connaisse toutes les polices | 107 | ] |
108 | }, | 108 | }, |
109 | 109 | ||
110 | // barre d'outils dans une image | 110 | // plugin code HTML |
111 | image: { | 111 | // pour coller le code HTML "embed" proposé par certains sites |
112 | toolbar: [ | 112 | |
113 | 'imageTextAlternative', | 113 | // media embarqué (audio, vidéo, carte) |
114 | 'imageStyle:full', | 114 | //mediaEmbed: { |
115 | 'imageStyle:side', | 115 | //previewsInData: true, |
116 | 'linkImage' | 116 | // vaut "false" par defaut, on crée la balise non standard <oembed url="" > // https://oembed.com/ |
117 | ] | 117 | // qui nécessite un traitement (en JS ou côté serveur) en utilisant le lien à l'intérieur |
118 | }, | 118 | // avec "true", on crée la balise <iframe> qui sert à insérer une page HTML dans une autre, |
119 | 119 | // notre "embarquement de média" devrit donc réussir quelque soit le site | |
120 | // barre d'outils dans un tableau | 120 | // c'est plus simple, il ne reste plus qu'à ajuster le contenu avec du CSS (important) |
121 | table: { | 121 | // on doit supprimer le positionnement absolu qui fait que l'iframe se place par dessus le reste et adapter la taille de l'élément |
122 | contentToolbar: [ | 122 | |
123 | 'tableColumn', | 123 | // en outre, le plugin mediaEmbed (dans l'éditeur), tout comme la balise "iframe" (hors éditeur), |
124 | 'tableRow', | 124 | // permettent d'afficher un aperçu (preview): une image avec un bouton lecture dessus |
125 | 'mergeTableCells', | 125 | // cette image est envoyée imédiatement par le serveur, et le contenu après un clic dessus |
126 | //'tableCellProperties', | 126 | // |
127 | 'tableProperties' | 127 | //}, |
128 | ] | 128 | |
129 | }, | 129 | // images |
130 | 130 | // https://ckeditor.com/docs/ckeditor5/latest/features/image-upload/simple-upload-adapter.html | |
131 | // plugin code HTML | 131 | // le plugin "image upload" s'occupe est la partie graphique, il crée un objet "createLoader", |
132 | // pour coller le code HTML "embed" proposé par certains sites | 132 | // le plugin "simple upload adapter" est la classe qui communique avec le serveur au moyen de requêtes AJAX |
133 | 133 | // il attend du serveur une réponse au format .json contenant l'adresse où est stockée l'image: | |
134 | // media embarqué (audio, vidéo, carte) | 134 | //{ |
135 | //mediaEmbed: { | 135 | // "url": "https://example.com/images/foo.jpg" |
136 | //previewsInData: true, | 136 | //} |
137 | // vaut "false" par defaut, on crée la balise non standard <oembed url="" > // https://oembed.com/ | 137 | // cette url sert à deux choses: |
138 | // qui nécessite un traitement (en JS ou côté serveur) en utilisant le lien à l'intérieur | 138 | // - à télécharger immédiatement l'image envoyée pour la placer dans l'éditeur |
139 | // avec "true", on crée la balise <iframe> qui sert à insérer une page HTML dans une autre, | 139 | // - à inclure l'adresse de l'image dans le HTML produit par l'éditeur |
140 | // notre "embarquement de média" devrit donc réussir quelque soit le site | 140 | simpleUpload: { |
141 | // c'est plus simple, il ne reste plus qu'à ajuster le contenu avec du CSS (important) | 141 | uploadUrl: 'index.php?action=upload_image&page=<?= $page_actuelle ?>', |
142 | // on doit supprimer le positionnement absolu qui fait que l'iframe se place par dessus le reste et adapter la taille de l'élément | 142 | // noter qu'il est possible (parce que souhaitable je ne pense pas) d'envoyer une requête AJAX |
143 | 143 | // en indiquant une adresse "statique" du type: fichier.txt ou .xml, jpg, png, etc, | |
144 | // en outre, le plugin mediaEmbed (dans l'éditeur), tout comme la balise "iframe" (hors éditeur), | 144 | |
145 | // permettent d'afficher un aperçu (preview): une image avec un bouton lecture dessus | 145 | // Headers supplémentaires envoyés avec la requête |
146 | // cette image est envoyée imédiatement par le serveur, et le contenu après un clic dessus | 146 | // c'est ici qu'on installe les mécanismes de sécurités comme l'authentification et la protection au CSRF |
147 | // | 147 | headers: { |
148 | //}, | 148 | 'X-CSRF-TOKEN': 'CSRF-Token', |
149 | 149 | Authorization: 'Bearer <JSON Web Token>' | |
150 | // images | 150 | } |
151 | // https://ckeditor.com/docs/ckeditor5/latest/features/image-upload/simple-upload-adapter.html | 151 | }, |
152 | // le plugin "image upload" s'occupe est la partie graphique, il crée un objet "createLoader", | 152 | // formats acceptés par défaut: jpeg, png, gif, bmp, webp, tiff |
153 | // le plugin "simple upload adapter" est la classe qui communique avec le serveur au moyen de requêtes AJAX | 153 | // le svg n'est pas dans la liste, pour raison de sécurité apparemment, il parait qu'on peut mettre du javascript à l'intérieur |
154 | // il attend du serveur une réponse au format .json contenant l'adresse où est stockée l'image: | 154 | // ce plugin est simple (JS pur) et n'oblige pas le serveur à disposer de l'extension GD |
155 | //{ | 155 | // niveau perfs, on garde le choix d'utiler GD ou imagemagick ou un système d'onglets |
156 | // "url": "https://example.com/images/foo.jpg" | 156 | |
157 | //} | 157 | // plugin autosave |
158 | // cette url sert à deux choses: | 158 | } ) |
159 | // - à télécharger immédiatement l'image envoyée pour la placer dans l'éditeur | 159 | |
160 | // - à inclure l'adresse de l'image dans le HTML produit par l'éditeur | 160 | .then( newEditor => { |
161 | simpleUpload: { | 161 | editor = newEditor; |
162 | uploadUrl: 'index.php?action=upload_image&page=<?= $page_actuelle ?>', | 162 | |
163 | // noter qu'il est possible (parce que souhaitable je ne pense pas) d'envoyer une requête AJAX | 163 | // obtenir la liste des éléments disponibles pour la barre d'outils |
164 | // en indiquant une adresse "statique" du type: fichier.txt ou .xml, jpg, png, etc, | 164 | //alert(Array.from( editor.ui.componentFactory.names() )); |
165 | 165 | // obtenir la liste des plugins disponibles: | |
166 | // Headers supplémentaires envoyés avec la requête | 166 | //alert(ClassicEditor.builtinPlugins.map( plugin => plugin.pluginName )); |
167 | // c'est ici qu'on installe les mécanismes de sécurités comme l'authentification et la protection au CSRF | 167 | |
168 | headers: { | 168 | var initial = '<?= $texte ?>'; |
169 | 'X-CSRF-TOKEN': 'CSRF-Token', | 169 | editor.setData(initial); |
170 | Authorization: 'Bearer <JSON Web Token>' | 170 | } ) |
171 | } | 171 | .catch( error => { |
172 | }, | 172 | console.error( error ); |
173 | // formats acceptés par défaut: jpeg, png, gif, bmp, webp, tiff | 173 | } ); |
174 | // le svg n'est pas dans la liste, pour raison de sécurité apparemment, il parait qu'on peut mettre du javascript à l'intérieur | 174 | </script> |
175 | // ce plugin est simple (JS pur) et n'oblige pas le serveur à disposer de l'extension GD | 175 | </form> |
176 | // niveau perfs, on garde le choix d'utiler GD ou imagemagick ou un système d'onglets | 176 | </div> |
177 | 177 | <?php | |
178 | // plugin autosave | ||
179 | } ) | ||
180 | |||
181 | .then( newEditor => { | ||
182 | editor = newEditor; | ||
183 | |||
184 | // obtenir la liste des éléments disponibles pour la barre d'outils | ||
185 | //alert(Array.from( editor.ui.componentFactory.names() )); | ||
186 | // obtenir la liste des plugins disponibles: | ||
187 | //alert(ClassicEditor.builtinPlugins.map( plugin => plugin.pluginName )); | ||
188 | |||
189 | var initial = '<?= $texte ?>'; | ||
190 | editor.setData(initial); | ||
191 | } ) | ||
192 | .catch( error => { | ||
193 | console.error( error ); | ||
194 | } ); | ||
195 | </script> | ||
196 | </form> | ||
197 | </div> | ||
198 | <?php | ||
199 | $editeurHTML = ob_get_clean(); \ No newline at end of file | 178 | $editeurHTML = ob_get_clean(); \ No newline at end of file |