diff options
| author | polo <ordipolo@gmx.fr> | 2021-04-20 21:46:33 +0200 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2021-04-20 21:46:33 +0200 |
| commit | 87798e5554eb0330cd2de255e5034f0472d410a4 (patch) | |
| tree | acd9e26a7d912c7575cb6dd1c7b42cc3e9f52993 /view/template-ckeditor.php | |
| download | melaine-87798e5554eb0330cd2de255e5034f0472d410a4.tar.gz melaine-87798e5554eb0330cd2de255e5034f0472d410a4.tar.bz2 melaine-87798e5554eb0330cd2de255e5034f0472d410a4.zip | |
mot de passe
Diffstat (limited to 'view/template-ckeditor.php')
| -rw-r--r-- | view/template-ckeditor.php | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/view/template-ckeditor.php b/view/template-ckeditor.php new file mode 100644 index 0000000..48b673a --- /dev/null +++ b/view/template-ckeditor.php | |||
| @@ -0,0 +1,189 @@ | |||
| 1 | <?php | ||
| 2 | // view/template-ckeditor.php | ||
| 3 | |||
| 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: | ||
| 6 | // barre d'outils, zone de saisie, formulaire caché, bouton "valider" | ||
| 7 | |||
| 8 | // le formulaire est presque classique, en effet on utilise le ckeditor 5 dans sa version "Document" (ou DecoupledEditor): | ||
| 9 | // - avantage: plus de possibilité dans la barre d'outils (se rapproche d'un traitement de texte) | ||
| 10 | // - inconvénient: on ne peut utiliser la balise <textarea> qu'on remplace par une <div> | ||
| 11 | |||
| 12 | // pour pouvoir envoyer le contenu dans le POST, on a deux possibilité: | ||
| 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 | ||
| 14 | // - utiliser l'astuce du formulaire caché ! | ||
| 15 | |||
| 16 | // le javascript place les données dans le formulaire caché | ||
| 17 | // avec la fonction envoiDonnees(), les données se retrouvent dans une <input> et sont donc envoyées avec par la POST (haha) | ||
| 18 | |||
| 19 | // l'envoi d'image en revanche utilise nécessairement de l'AJAX et | ||
| 20 | // la bibliothèque "ckfinder" (en JS + PHP) me permet de ne pas coder moi-même un "upload adapter", ce sera l'objet d'une autre amélioration, et en plus certaines fonctionnalités sont payantes | ||
| 21 | // https://ckeditor.com/docs/ckeditor5/latest/framework/guides/deep-dive/upload-adapter.html | ||
| 22 | // le ckfinder communique avec le serveur au moyen de requêtes AJAX, | ||
| 23 | // le fichier est ainsi téléchargé sur le serveur avant même d'apparaître dans l'éditeur | ||
| 24 | // attention, le ckfinder nécessite php7.3, les extensions GD et FileInfo et le support du type MIME JSON sur le serveur (retenir php7.3 et GD) | ||
| 25 | // https://ckeditor.com/ckfinder/download/ | ||
| 26 | |||
| 27 | // variable $editeurHTML | ||
| 28 | ob_start(); | ||
| 29 | ?> | ||
| 30 | |||
| 31 | <div class="conteneur_article" > | ||
| 32 | <form action="index.php?page=<?= $page_actuelle ?>&article=<?= $numArticle ?>&action=submit" method="post" > | ||
| 33 | <textarea id="editor" name="contenu" ></textarea> | ||
| 34 | |||
| 35 | <?php | ||
| 36 | // falsification de requête inter-site | ||
| 37 | // on ajoute un formulaire caché avec une valeur aléatoire cryptée utilisable une seule fois (=jeton) | ||
| 38 | |||
| 39 | // "Vous pouvez rendre chaque jeton utilisable une seule fois et ainsi éviter de rejouer plusieurs fois la même requête. | ||
| 40 | // Les jetons sont stockés dans le back-office. | ||
| 41 | // Une rotation des jetons est effectuée quand le nombre maximum a été atteint, les plus vieux en premier. | ||
| 42 | // Chaque jeton peut être lié à une URL spécifique. | ||
| 43 | // Si un jeton est intercepté, il ne peut pas être utilisé dans un autre contexte. | ||
| 44 | // Si besoin, les jetons peuvent être attachés à une adresse IP spécifique. | ||
| 45 | // Depuis la version v2.1, les jetons peuvent être réutilisés (par exemple pour les requêtes AJAX). | ||
| 46 | // Si vous n’utilisez pas un framework qui gère la protection CSRF pour vous, jetez un oeil à Anti-CSRF." | ||
| 47 | |||
| 48 | // une bibli qui fait ça: https://github.com/paragonie/anti-csrf | ||
| 49 | ?> | ||
| 50 | |||
| 51 | <input class="boutonSubmitEditeur" type="submit" value="Valider" onclick="envoiDonnees();" /> | ||
| 52 | |||
| 53 | <script> | ||
| 54 | let editor; // variable utilisable depuis une fonction | ||
| 55 | |||
| 56 | // code exécuté à la validation du formulaire | ||
| 57 | function envoiDonnees() | ||
| 58 | { | ||
| 59 | // supprimer le positionnement absolu de l'iframe | ||
| 60 | //~ let balisesIframe = document.getElementsByTagName("iframe"); | ||
| 61 | //~ for(var i = 0; i < balisesIframe.length; i++) | ||
| 62 | //~ { | ||
| 63 | //~ alert(balisesIframe[i].getAttribute("style")); // affiche le CSS | ||
| 64 | //~ balisesIframe[i].removeAttribute("style"); | ||
| 65 | //~ alert(balisesIframe[i].getAttribute("style")); // affiche null | ||
| 66 | //~ } | ||
| 67 | } | ||
| 68 | |||
| 69 | // ATTENTION: si l'éditeur ne fonctionne pas, empêcher qu'on puisse cliquer sur Valider! | ||
| 70 | // Il y a aussi des paramètres dans le fichier de config: ckeditor/webpack.config.js | ||
| 71 | ClassicEditor | ||
| 72 | .create( document.querySelector( '#editor' ),{ | ||
| 73 | language: 'fr', | ||
| 74 | |||
| 75 | // barre d'outils à adapter au build | ||
| 76 | toolbar: { | ||
| 77 | items: [ 'undo', 'redo', 'selectAll', '|', 'heading', '|', 'alignment', 'bulletedList', 'numberedList', 'todoList', 'blockQuote', 'horizontalLine', '-', 'bold', 'italic', 'underline', | ||
| 78 | //'strikethrough', | ||
| 79 | '|', | ||
| 80 | //'fontFamily', | ||
| 81 | 'fontColor', 'fontSize', 'highlight', '|', 'imageInsert', 'link', | ||
| 82 | //'htmlEmbed', | ||
| 83 | //'mediaEmbed', | ||
| 84 | 'insertTable' | ||
| 85 | //'|', 'textPartLanguage' | ||
| 86 | ], | ||
| 87 | // multiligne automatique (le '-' dans la liste permet de choisir l'endroit où couper) | ||
| 88 | shouldNotGroupWhenFull: true | ||
| 89 | |||
| 90 | // noter que 'fontFamily' ne comporte que des polices microsoft => problèmes de droits? | ||
| 91 | // de plus, il faut que le navigateur connaisse toutes les polices | ||
| 92 | }, | ||
| 93 | |||
| 94 | // barre d'outils dans une image | ||
| 95 | image: { | ||
| 96 | toolbar: [ | ||
| 97 | 'imageTextAlternative', | ||
| 98 | 'imageStyle:full', | ||
| 99 | 'imageStyle:side', | ||
| 100 | 'linkImage' | ||
| 101 | ] | ||
| 102 | }, | ||
| 103 | |||
| 104 | // barre d'outils dans un tableau | ||
| 105 | table: { | ||
| 106 | contentToolbar: [ | ||
| 107 | 'tableColumn', | ||
| 108 | 'tableRow', | ||
| 109 | 'mergeTableCells', | ||
| 110 | //'tableCellProperties', | ||
| 111 | 'tableProperties' | ||
| 112 | ] | ||
| 113 | }, | ||
| 114 | |||
| 115 | // plugin code HTML | ||
| 116 | // pour coller le code HTML "embed" proposé par certains sites | ||
| 117 | // | ||
| 118 | |||
| 119 | // media embarqué (audio, vidéo, carte) | ||
| 120 | mediaEmbed: { | ||
| 121 | //previewsInData: true, | ||
| 122 | // vaut "false" par defaut, on crée la balise non standard <oembed url="" > // https://oembed.com/ | ||
| 123 | // qui nécessite un traitement (en JS ou côté serveur) en utilisant le lien à l'intérieur | ||
| 124 | // avec "true", on crée la balise <iframe> qui sert à insérer une page HTML dans une autre, | ||
| 125 | // notre "embarquement de média" devrit donc réussir quelque soit le site | ||
| 126 | // c'est plus simple, il ne reste plus qu'à ajuster le contenu avec du CSS (important) | ||
| 127 | // 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 | ||
| 128 | |||
| 129 | // en outre, le plugin mediaEmbed (dans l'éditeur), tout comme la balise "iframe" (hors éditeur), | ||
| 130 | // permettent d'afficher un aperçu (preview): une image avec un bouton lecture dessus | ||
| 131 | // cette image est envoyée imédiatement par le serveur, et le contenu après un clic dessus | ||
| 132 | // | ||
| 133 | }, | ||
| 134 | |||
| 135 | // images | ||
| 136 | // https://ckeditor.com/docs/ckeditor5/latest/features/image-upload/simple-upload-adapter.html | ||
| 137 | // le plugin "image upload" s'occupe est la partie graphique, il crée un objet "createLoader", | ||
| 138 | // le plugin "simple upload adapter" est la classe qui communique avec le serveur au moyen de requêtes AJAX | ||
| 139 | // il attend du serveur une réponse au format .json contenant l'adresse où est stockée l'image: | ||
| 140 | //{ | ||
| 141 | // "url": "https://example.com/images/foo.jpg" | ||
| 142 | //} | ||
| 143 | // cette url sert à deux choses: | ||
| 144 | // - à télécharger l'image avant de la placer dans l'éditeur | ||
| 145 | // - écrire le HTML qu'on enregistrera ensuite | ||
| 146 | // en effet, le fichier est téléchargé sur le serveur avant de revenir dans l'éditeur comme un téléchargement classique | ||
| 147 | |||
| 148 | simpleUpload: { | ||
| 149 | uploadUrl: 'imageAJAX.php?page=<?= $page_actuelle ?>', | ||
| 150 | // noter qu'il est possible (parce que souhaitable je ne pense pas) d'envoyer une requête AJAX | ||
| 151 | // en indiquant une adresse "statique" du type: fichier.txt ou .xml, jpg, png, etc | ||
| 152 | |||
| 153 | // Headers supplémentaires envoyés avec la requête | ||
| 154 | // c'est ici qu'on installe les mécanismes de sécurités comme l'authentification et la protection au CSRF | ||
| 155 | headers: { | ||
| 156 | 'X-CSRF-TOKEN': 'CSRF-Token', | ||
| 157 | Authorization: 'Bearer <JSON Web Token>' | ||
| 158 | } | ||
| 159 | }, | ||
| 160 | // formats acceptés par défaut: jpeg, png, gif, bmp, webp, tiff | ||
| 161 | // le svg n'est pas dans la liste, pour raison de sécurité il me semble, apparemment on peut mettre du javascript à l'intérieur | ||
| 162 | |||
| 163 | // ce plugin a l'intérêt de ne pas imposer l'utilisation de l'extension GD de PHP, | ||
| 164 | // Reste qu'il sera quand même intéressant de l'ajouter pour le redimensionnement des images trop lourdes, | ||
| 165 | // quoi que le système d'onglets (limiter l'affichge à 5 ou 10 articles par page) règle aussi le problème d'une autre manière | ||
| 166 | |||
| 167 | |||
| 168 | // plugin autosave | ||
| 169 | } ) | ||
| 170 | |||
| 171 | .then( newEditor => { | ||
| 172 | editor = newEditor; | ||
| 173 | |||
| 174 | // obtenir la liste des éléments disponibles pour la barre d'outils | ||
| 175 | //alert(Array.from( editor.ui.componentFactory.names() )); | ||
| 176 | // obtenir la liste des plugins disponibles: | ||
| 177 | //alert(ClassicEditor.builtinPlugins.map( plugin => plugin.pluginName )); | ||
| 178 | |||
| 179 | var initial = '<?= $initial ?>'; | ||
| 180 | editor.setData(initial); | ||
| 181 | } ) | ||
| 182 | .catch( error => { | ||
| 183 | console.error( error ); | ||
| 184 | } ); | ||
| 185 | </script> | ||
| 186 | </form> | ||
| 187 | </div> | ||
| 188 | <?php | ||
| 189 | $editeurHTML = ob_get_clean(); \ No newline at end of file | ||
