- Ajout dépendance TinyMCE.
- Ajout composant TinyMceFieldEditor. - Intégration de TinyMCE en remplacement du v-text-field dans le composant MovieComponentForm & MovieCommentList.
Showing
8 changed files
with
167 additions
and
33 deletions
| @@ -9,4 +9,6 @@ | @@ -9,4 +9,6 @@ | ||
| 9 | - Ajout composant MovieCommentForm. | 9 | - Ajout composant MovieCommentForm. |
| 10 | - Ajout model + interface MovieComment. | 10 | - Ajout model + interface MovieComment. |
| 11 | - Ajout composant MovieCommentForm. | 11 | - Ajout composant MovieCommentForm. |
| 12 | -- Ajout composant MovieCommentList. | 12 | +- Ajout composant MovieCommentList. |
| 13 | +- Ajout dépendance TinyMCE. | ||
| 14 | +- Ajout composant TinyMceFieldEditor. |
| 1 | -<script setup lang="ts"> | 1 | +<script lang="ts" setup> |
| 2 | //#region --Import--. | 2 | //#region --Import--. |
| 3 | import type { MovieCommentInterface } from "~/interfaces/movieComment"; | 3 | import type { MovieCommentInterface } from "~/interfaces/movieComment"; |
| 4 | import { MessageSquareIcon } from "lucide-vue-next"; | 4 | import { MessageSquareIcon } from "lucide-vue-next"; |
| 5 | //#endregion | 5 | //#endregion |
| 6 | 6 | ||
| 7 | //#region --Props--. | 7 | //#region --Props--. |
| 8 | -defineProps({ | 8 | +const props = defineProps({ |
| 9 | comments: { | 9 | comments: { |
| 10 | type: Array<MovieCommentInterface>, | 10 | type: Array<MovieCommentInterface>, |
| 11 | required: true, | 11 | required: true, |
| 12 | - nullable: false | 12 | + nullable: false, |
| 13 | }, | 13 | }, |
| 14 | }); | 14 | }); |
| 15 | //#endregion | 15 | //#endregion |
| 16 | + | ||
| 17 | +//#region --Watch--. | ||
| 18 | +watch( | ||
| 19 | + () => props.comments, | ||
| 20 | + (comments) => { | ||
| 21 | + nextTick(() => { | ||
| 22 | + if (comments.length) { | ||
| 23 | + comments.forEach((comment, index) => { | ||
| 24 | + const element = document.getElementById(`message${index}`) as HTMLParagraphElement; | ||
| 25 | + console.log(element); | ||
| 26 | + element.innerHTML = comment.message; | ||
| 27 | + }); | ||
| 28 | + } | ||
| 29 | + }); | ||
| 30 | + }, | ||
| 31 | +); | ||
| 32 | +//#endregion | ||
| 16 | </script> | 33 | </script> |
| 17 | 34 | ||
| 18 | <template> | 35 | <template> |
| @@ -20,11 +37,7 @@ defineProps({ | @@ -20,11 +37,7 @@ defineProps({ | ||
| 20 | <!-- Liste des commentaires --> | 37 | <!-- Liste des commentaires --> |
| 21 | <section v-if="comments.length > 0" class="mt-10"> | 38 | <section v-if="comments.length > 0" class="mt-10"> |
| 22 | <h2>Commentaires publiés</h2> | 39 | <h2>Commentaires publiés</h2> |
| 23 | - <div | 40 | + <div v-for="(comment, index) in comments" :key="index" class="bg-gray-800 rounded-lg p-6 mb-4"> |
| 24 | - v-for="(comment, index) in comments" | ||
| 25 | - :key="index" | ||
| 26 | - class="bg-gray-800 rounded-lg p-6 mb-4" | ||
| 27 | - > | ||
| 28 | <div class="flex justify-between items-start mb-2"> | 41 | <div class="flex justify-between items-start mb-2"> |
| 29 | <section> | 42 | <section> |
| 30 | <h4 class="font-bold text-lg">Par {{ comment.username }}</h4> | 43 | <h4 class="font-bold text-lg">Par {{ comment.username }}</h4> |
| @@ -34,7 +47,7 @@ defineProps({ | @@ -34,7 +47,7 @@ defineProps({ | ||
| 34 | {{ comment.rating }} | 47 | {{ comment.rating }} |
| 35 | </section> | 48 | </section> |
| 36 | </div> | 49 | </div> |
| 37 | - <p class="text-gray-300">{{ comment.message }}</p> | 50 | + <p :id="`message${index}`" class="text-gray-300">{{ comment.message }}</p> |
| 38 | </div> | 51 | </div> |
| 39 | </section> | 52 | </section> |
| 40 | <!-- Si aucun commentaire --> | 53 | <!-- Si aucun commentaire --> |
| @@ -45,6 +58,4 @@ defineProps({ | @@ -45,6 +58,4 @@ defineProps({ | ||
| 45 | </section> | 58 | </section> |
| 46 | </template> | 59 | </template> |
| 47 | 60 | ||
| 48 | -<style scoped> | 61 | +<style scoped></style> |
| 49 | - | ||
| 50 | -</style> |
| @@ -6,7 +6,7 @@ import type { Comment } from "~/type/commentForm"; | @@ -6,7 +6,7 @@ import type { Comment } from "~/type/commentForm"; | ||
| 6 | //#endregion | 6 | //#endregion |
| 7 | 7 | ||
| 8 | //#region --Emit--. | 8 | //#region --Emit--. |
| 9 | -const emit = defineEmits(['event:submit']); | 9 | +const emit = defineEmits(["event:submit"]); |
| 10 | //#endregion | 10 | //#endregion |
| 11 | 11 | ||
| 12 | //#region --Props--. | 12 | //#region --Props--. |
| @@ -58,7 +58,7 @@ const v$ = useVuelidate(rules, formData); | @@ -58,7 +58,7 @@ const v$ = useVuelidate(rules, formData); | ||
| 58 | 58 | ||
| 59 | //#region --Function--. | 59 | //#region --Function--. |
| 60 | async function submitComment() { | 60 | async function submitComment() { |
| 61 | - emit('event:submit', formData); | 61 | + emit("event:submit", formData); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | function clear() { | 64 | function clear() { |
| @@ -68,6 +68,29 @@ function clear() { | @@ -68,6 +68,29 @@ function clear() { | ||
| 68 | formData.rating = initialState.rating; | 68 | formData.rating = initialState.rating; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | +function handleMessageEvent(event: string) { | ||
| 72 | + formData.message = event; | ||
| 73 | + v$.value.message.$touch(); | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +/* | ||
| 77 | + | ||
| 78 | + if (event.length < 3) { | ||
| 79 | + v$.value.message.$errors[0] = { | ||
| 80 | + $propertyPath: "username", | ||
| 81 | + $property: "username", | ||
| 82 | + $validator: "required", | ||
| 83 | + $uid: "username-required", | ||
| 84 | + $message: rules.message.minLength as unknown as string, | ||
| 85 | + $params: { | ||
| 86 | + type:"required" | ||
| 87 | + }, | ||
| 88 | + $response: false, | ||
| 89 | + $pending: false, | ||
| 90 | + }; | ||
| 91 | + } | ||
| 92 | + */ | ||
| 93 | + | ||
| 71 | //#endregion | 94 | //#endregion |
| 72 | </script> | 95 | </script> |
| 73 | 96 | ||
| @@ -76,25 +99,16 @@ function clear() { | @@ -76,25 +99,16 @@ function clear() { | ||
| 76 | <VForm> | 99 | <VForm> |
| 77 | <v-text-field | 100 | <v-text-field |
| 78 | v-model="formData.username" | 101 | v-model="formData.username" |
| 79 | - :error-messages="v$.username.$errors.map((e) => e.$message)" | 102 | + :error-messages="v$.username.$errors.map((e) => e.$message) as readonly string[]" |
| 80 | label="nom d'utilisateur" | 103 | label="nom d'utilisateur" |
| 81 | placeholder="nom d'utilisateur" | 104 | placeholder="nom d'utilisateur" |
| 82 | required | 105 | required |
| 83 | @blur="v$.username.$touch()" | 106 | @blur="v$.username.$touch()" |
| 84 | @input="v$.username.$touch()" | 107 | @input="v$.username.$touch()" |
| 85 | /> | 108 | /> |
| 86 | - <v-textarea | ||
| 87 | - v-model="formData.message" | ||
| 88 | - :error-messages="v$.message.$errors.map((e) => e.$message)" | ||
| 89 | - label="message" | ||
| 90 | - placeholder="Saisissez votre commentaire" | ||
| 91 | - required | ||
| 92 | - @blur="v$.message.$touch" | ||
| 93 | - @input="v$.message.$touch" | ||
| 94 | - /> | ||
| 95 | <v-text-field | 109 | <v-text-field |
| 96 | v-model="formData.rating" | 110 | v-model="formData.rating" |
| 97 | - :error-messages="v$.rating.$errors.map((e) => e.$message)" | 111 | + :error-messages="v$.rating.$errors.map((e) => e.$message) as readonly string[]" |
| 98 | label="Note (1-10)" | 112 | label="Note (1-10)" |
| 99 | placeholder="" | 113 | placeholder="" |
| 100 | required | 114 | required |
| @@ -102,6 +116,11 @@ function clear() { | @@ -102,6 +116,11 @@ function clear() { | ||
| 102 | @blur="v$.rating.$touch" | 116 | @blur="v$.rating.$touch" |
| 103 | @input="v$.rating.$touch" | 117 | @input="v$.rating.$touch" |
| 104 | /> | 118 | /> |
| 119 | + <ui-components-tiny-mce-field-editor | ||
| 120 | + :error-message="v$?.message?.$errors[0]?.$message ? (v$.message.$errors[0].$message as string) : ''" | ||
| 121 | + :model-value="formData.message" | ||
| 122 | + @update:model-value="handleMessageEvent" | ||
| 123 | + /> | ||
| 105 | <v-btn | 124 | <v-btn |
| 106 | class="mt-6 mr-4" | 125 | class="mt-6 mr-4" |
| 107 | color="primary" | 126 | color="primary" |
| @@ -120,7 +139,7 @@ function clear() { | @@ -120,7 +139,7 @@ function clear() { | ||
| 120 | </span> | 139 | </span> |
| 121 | <span v-else>Publier le commentaire</span> | 140 | <span v-else>Publier le commentaire</span> |
| 122 | </v-btn> | 141 | </v-btn> |
| 123 | - <v-btn class="mt-6 mr-4" color="primary" @click="clear"> effacer </v-btn> | 142 | + <v-btn class="mt-6 mr-4" color="primary" @click="clear"> effacer</v-btn> |
| 124 | </VForm> | 143 | </VForm> |
| 125 | </section> | 144 | </section> |
| 126 | </template> | 145 | </template> |
| 1 | +<script lang="ts" setup> | ||
| 2 | +//#region --Import--. | ||
| 3 | +import Editor from "@tinymce/tinymce-vue"; | ||
| 4 | +import { ref, watch } from "vue"; | ||
| 5 | +//#endregion | ||
| 6 | + | ||
| 7 | +//#region --Declaration--. | ||
| 8 | +const runtimeConfig = useRuntimeConfig(); | ||
| 9 | +//#endregion | ||
| 10 | + | ||
| 11 | +//#region --Emit--. | ||
| 12 | +const emit = defineEmits<{ | ||
| 13 | + (e: "update:modelValue", value: string): void; | ||
| 14 | +}>(); | ||
| 15 | +//#endregion | ||
| 16 | + | ||
| 17 | +//#region --Props--. | ||
| 18 | +const props = defineProps<{ | ||
| 19 | + modelValue: string; | ||
| 20 | + errorMessage: string; | ||
| 21 | +}>(); | ||
| 22 | +//#endregion | ||
| 23 | + | ||
| 24 | +//#region --Data/ref--. | ||
| 25 | +const content = ref(props.modelValue); | ||
| 26 | +const init = { | ||
| 27 | + height: 300, | ||
| 28 | + menubar: false, | ||
| 29 | + plugins: [ | ||
| 30 | + // Core editing features | ||
| 31 | + "advlist", | ||
| 32 | + "autolink", | ||
| 33 | + "lists", | ||
| 34 | + "link", | ||
| 35 | + "image", | ||
| 36 | + "charmap", | ||
| 37 | + "preview", | ||
| 38 | + "anchor", | ||
| 39 | + "searchreplace", | ||
| 40 | + "visualblocks", | ||
| 41 | + "code", | ||
| 42 | + "fullscreen", | ||
| 43 | + "insertdatetime", | ||
| 44 | + "media", | ||
| 45 | + "table", | ||
| 46 | + "code", | ||
| 47 | + "help", | ||
| 48 | + "wordcount", | ||
| 49 | + ], | ||
| 50 | + toolbar: | ||
| 51 | + "undo redo | blocks | bold italic underline strikethrough |" + | ||
| 52 | + "bold italic forecolor | alignleft aligncenter " + | ||
| 53 | + "alignright alignjustify | bullist numlist outdent indent | " + | ||
| 54 | + "removeformat | help", | ||
| 55 | + content_style: "body { font-family:Helvetica,Arial,sans-serif; font-size:14px }", | ||
| 56 | + skin: "oxide-dark", | ||
| 57 | + content_css: "dark", | ||
| 58 | +}; | ||
| 59 | +//#endregion | ||
| 60 | + | ||
| 61 | +//#region --Watch--. | ||
| 62 | +watch(content, (newValue) => { | ||
| 63 | + emit("update:modelValue", newValue); | ||
| 64 | +}); | ||
| 65 | + | ||
| 66 | +watch( | ||
| 67 | + () => props.modelValue, | ||
| 68 | + (newValue) => { | ||
| 69 | + if (newValue !== content.value) { | ||
| 70 | + content.value = newValue; | ||
| 71 | + } | ||
| 72 | + }, | ||
| 73 | +); | ||
| 74 | +//#endregion | ||
| 75 | +</script> | ||
| 76 | + | ||
| 77 | +<template> | ||
| 78 | + <div> | ||
| 79 | + <editor v-model="content" :api-key="runtimeConfig.public.apiTinyMceSecret" :init="init" /> | ||
| 80 | + </div> | ||
| 81 | + <div v-if="errorMessage" class="text-red-500 text-sm mt-1"> | ||
| 82 | + {{ errorMessage }} | ||
| 83 | + </div> | ||
| 84 | +</template> | ||
| 85 | + | ||
| 86 | +<style scoped></style> |
| @@ -68,8 +68,8 @@ export default defineNuxtConfig({ | @@ -68,8 +68,8 @@ export default defineNuxtConfig({ | ||
| 68 | // Keys within public are also exposed client-side. | 68 | // Keys within public are also exposed client-side. |
| 69 | public: { | 69 | public: { |
| 70 | apiTMDBSecret: process.env.NUXT_ENV_TMDB_API_KEY, | 70 | apiTMDBSecret: process.env.NUXT_ENV_TMDB_API_KEY, |
| 71 | - apiTMDBBearer: process.env.NUXT_ENV_TMDB_BEARER, | ||
| 72 | apiTMDBUrl: process.env.NUXT_ENV_TMDB_URL, | 71 | apiTMDBUrl: process.env.NUXT_ENV_TMDB_URL, |
| 72 | + apiTinyMceSecret: process.env.NUXT_ENV_TINY_MCE_API_KEY, | ||
| 73 | }, | 73 | }, |
| 74 | }, | 74 | }, |
| 75 | 75 |
| @@ -17,6 +17,7 @@ | @@ -17,6 +17,7 @@ | ||
| 17 | "@nuxt/ui": "^2.22.0", | 17 | "@nuxt/ui": "^2.22.0", |
| 18 | "@pinia-orm/nuxt": "^1.10.2", | 18 | "@pinia-orm/nuxt": "^1.10.2", |
| 19 | "@pinia/nuxt": "^0.9.0", | 19 | "@pinia/nuxt": "^0.9.0", |
| 20 | + "@tinymce/tinymce-vue": "^5.1.1", | ||
| 20 | "@types/vuelidate": "^0.7.22", | 21 | "@types/vuelidate": "^0.7.22", |
| 21 | "@unhead/vue": "^2.0.8", | 22 | "@unhead/vue": "^2.0.8", |
| 22 | "@vuelidate/core": "^2.0.3", | 23 | "@vuelidate/core": "^2.0.3", |
| @@ -4566,6 +4567,18 @@ | @@ -4566,6 +4567,18 @@ | ||
| 4566 | "vue": "^2.7.0 || ^3.0.0" | 4567 | "vue": "^2.7.0 || ^3.0.0" |
| 4567 | } | 4568 | } |
| 4568 | }, | 4569 | }, |
| 4570 | + "node_modules/@tinymce/tinymce-vue": { | ||
| 4571 | + "version": "5.1.1", | ||
| 4572 | + "resolved": "https://registry.npmjs.org/@tinymce/tinymce-vue/-/tinymce-vue-5.1.1.tgz", | ||
| 4573 | + "integrity": "sha512-iO57HOWesFOhsaqjA5Ea6sDvQBmJJH3/dq00Uvg7metlct2kLF+ctRgoDsetLt6gmeZ7COPftr814/XzqnJ/dg==", | ||
| 4574 | + "license": "MIT", | ||
| 4575 | + "dependencies": { | ||
| 4576 | + "tinymce": "^6.0.0 || ^5.5.1" | ||
| 4577 | + }, | ||
| 4578 | + "peerDependencies": { | ||
| 4579 | + "vue": "^3.0.0" | ||
| 4580 | + } | ||
| 4581 | + }, | ||
| 4569 | "node_modules/@trysound/sax": { | 4582 | "node_modules/@trysound/sax": { |
| 4570 | "version": "0.2.0", | 4583 | "version": "0.2.0", |
| 4571 | "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", | 4584 | "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", |
| @@ -16204,6 +16217,12 @@ | @@ -16204,6 +16217,12 @@ | ||
| 16204 | "url": "https://github.com/sponsors/SuperchupuDev" | 16217 | "url": "https://github.com/sponsors/SuperchupuDev" |
| 16205 | } | 16218 | } |
| 16206 | }, | 16219 | }, |
| 16220 | + "node_modules/tinymce": { | ||
| 16221 | + "version": "6.8.5", | ||
| 16222 | + "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-6.8.5.tgz", | ||
| 16223 | + "integrity": "sha512-qAL/FxL7cwZHj4BfaF818zeJJizK9jU5IQzTcSLL4Rj5MaJdiVblEj7aDr80VCV1w9h4Lak9hlnALhq/kVtN1g==", | ||
| 16224 | + "license": "MIT" | ||
| 16225 | + }, | ||
| 16207 | "node_modules/tmp": { | 16226 | "node_modules/tmp": { |
| 16208 | "version": "0.2.3", | 16227 | "version": "0.2.3", |
| 16209 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", | 16228 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", |
| @@ -23,6 +23,7 @@ | @@ -23,6 +23,7 @@ | ||
| 23 | "@nuxt/ui": "^2.22.0", | 23 | "@nuxt/ui": "^2.22.0", |
| 24 | "@pinia-orm/nuxt": "^1.10.2", | 24 | "@pinia-orm/nuxt": "^1.10.2", |
| 25 | "@pinia/nuxt": "^0.9.0", | 25 | "@pinia/nuxt": "^0.9.0", |
| 26 | + "@tinymce/tinymce-vue": "^5.1.1", | ||
| 26 | "@types/vuelidate": "^0.7.22", | 27 | "@types/vuelidate": "^0.7.22", |
| 27 | "@unhead/vue": "^2.0.8", | 28 | "@unhead/vue": "^2.0.8", |
| 28 | "@vuelidate/core": "^2.0.3", | 29 | "@vuelidate/core": "^2.0.3", |
| @@ -9,15 +9,11 @@ import { Credit } from "~/models/credit"; | @@ -9,15 +9,11 @@ import { Credit } from "~/models/credit"; | ||
| 9 | import type { CreditsResponse } from "~/interfaces/credit"; | 9 | import type { CreditsResponse } from "~/interfaces/credit"; |
| 10 | import type { MovieCommentInterface } from "~/interfaces/movieComment"; | 10 | import type { MovieCommentInterface } from "~/interfaces/movieComment"; |
| 11 | import { MovieComment } from "~/models/movieComment"; | 11 | import { MovieComment } from "~/models/movieComment"; |
| 12 | -// Infos sur le composable date de Vuetify : https://vuetifyjs.com/en/features/dates/ | 12 | +import type { WhereSecondaryClosure } from "pinia-orm"; |
| 13 | -// Et l'api date : https://vuetifyjs.com/en/api/use-date/#exposed | ||
| 14 | -import { useDate } from "vuetify"; | ||
| 15 | -import { WhereSecondaryClosure } from "pinia-orm"; | ||
| 16 | //#endregion | 13 | //#endregion |
| 17 | 14 | ||
| 18 | //#region --Declaration--. | 15 | //#region --Declaration--. |
| 19 | const { fetchMovieDetails, fetchMovieCredits } = useTMDB(); | 16 | const { fetchMovieDetails, fetchMovieCredits } = useTMDB(); |
| 20 | -const { date, parseISO, toISO, toJsDate, format, locale } = useDate(); | ||
| 21 | //#endregion | 17 | //#endregion |
| 22 | 18 | ||
| 23 | //#region --Declaration--. | 19 | //#region --Declaration--. |
-
Please register or login to post a comment