From 4ae5561154fa4b48685b82f8cbdaaaebea003401 Mon Sep 17 00:00:00 2001 From: Philippe <83185129+phil3838@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:53:53 -0500 Subject: [PATCH] clean HTMLtoImgtoPDF --- .../DownloadQuizModal/DownloadQuizModal.tsx | 95 +++- .../components/DownloadQuizModal/preview.html | 461 ++++++++++++++++++ package-lock.json | 6 + 3 files changed, 544 insertions(+), 18 deletions(-) create mode 100644 client/src/components/DownloadQuizModal/preview.html create mode 100644 package-lock.json diff --git a/client/src/components/DownloadQuizModal/DownloadQuizModal.tsx b/client/src/components/DownloadQuizModal/DownloadQuizModal.tsx index b676304..44f9ccd 100644 --- a/client/src/components/DownloadQuizModal/DownloadQuizModal.tsx +++ b/client/src/components/DownloadQuizModal/DownloadQuizModal.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; + import { Dialog, DialogTitle, DialogActions, Button, Tooltip, IconButton } from '@mui/material'; import { FileDownload } from '@mui/icons-material'; @@ -6,6 +7,10 @@ import { QuizType } from '../../Types/QuizType'; import ApiService from '../../services/ApiService'; import jsPDF from 'jspdf'; +import html2canvas from 'html2canvas'; +import { parse } from 'gift-pegjs'; +import DOMPurify from 'dompurify'; +import Template, { ErrorTemplate } from '../GiftTemplate/templates'; interface DownloadQuizModalProps { quiz: QuizType; @@ -59,32 +64,86 @@ const DownloadQuizModal: React.FC = ({ quiz }) => { const selectedQuiz = await ApiService.getQuiz(quiz._id) as QuizType; if (!selectedQuiz) throw new Error('Quiz not found'); - const doc = new jsPDF(); - doc.setFont("helvetica", "bold"); - doc.setFontSize(25); - doc.text(selectedQuiz.title, 10, 15); - let yPosition = 40; - doc.setFont("helvetica", "normal"); - doc.setFontSize(16); + let previewHTML = ''; + selectedQuiz.content.forEach((giftQuestion) => { + try { + const question = parse(giftQuestion); - selectedQuiz.content.forEach((question, index) => { - const formattedQuestion = withAnswers - ? question - : question.replace(/\{[^}]+\}/g, ''); - - const wrappedText = doc.splitTextToSize(`${index + 1}. ${formattedQuestion}`, 180); - - doc.text(wrappedText, 10, yPosition); - - yPosition += wrappedText.length * 10; + previewHTML += Template(question[0], { + preview: true, + theme: 'light', + }); + } catch (error) { + if (error instanceof Error) { + previewHTML += ErrorTemplate(giftQuestion + '\n' + error.message); + } else { + previewHTML += ErrorTemplate(giftQuestion + '\n' + 'Erreur inconnue'); + } + } }); + if (!withAnswers) { + const svgRegex = /]*>([\s\S]*?)<\/svg>/gi; + previewHTML = previewHTML.replace(svgRegex, ''); + const placeholderRegex = /(placeholder=")[^"]*(")/gi; + previewHTML = previewHTML.replace(placeholderRegex, '$1$2'); + const feedbackContainerRegex = /<(div|span)[^>]*class="feedback-container"[^>]*>[\s\S]*?<\/div>/gi; + previewHTML = previewHTML.replace(feedbackContainerRegex, ''); + const answerClassRegex = /<(div|span)[^>]*class="[^"]*answer[^"]*"[^>]*>[\s\S]*?<\/\1>/gi; + previewHTML = previewHTML.replace(answerClassRegex, ''); + const bonneReponseRegex = /]*>[^<]*bonne réponse[^<]*<\/p>/gi; + previewHTML = previewHTML.replace(bonneReponseRegex, ''); + const AllAnswersFieldRegex = /<(p|span)[^>]*>\s*Réponse:\s*<\/\1>\s*]*>/gi + previewHTML = previewHTML.replace(AllAnswersFieldRegex, ''); + + } + + const sanitizedHTML = DOMPurify.sanitize(previewHTML); + + console.log('previewHTML:', sanitizedHTML); + + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = sanitizedHTML; + document.body.appendChild(tempDiv); + + const canvas = await html2canvas(tempDiv, { scale: 2 }); + + document.body.removeChild(tempDiv); + + const pdf = new jsPDF('p', 'mm', 'a4'); + const pageWidth = pdf.internal.pageSize.width; + const pageHeight = pdf.internal.pageSize.height; + const margin = 10; + const imgWidth = pageWidth - 2 * margin; + + let yOffset = 0; + + while (yOffset < canvas.height) { + const pageCanvas = document.createElement('canvas'); + pageCanvas.width = canvas.width; + pageCanvas.height = Math.min(canvas.height - yOffset, (pageHeight - 2 * margin) * (canvas.width / imgWidth)); + + const pageCtx = pageCanvas.getContext('2d'); + if (pageCtx) { + pageCtx.drawImage(canvas, 0, yOffset, canvas.width, pageCanvas.height, 0, 0, pageCanvas.width, pageCanvas.height); + } + + const pageImgData = pageCanvas.toDataURL('image/png'); + + if (yOffset > 0) pdf.addPage(); + + pdf.addImage(pageImgData, 'PNG', margin, margin, imgWidth, (pageCanvas.height * imgWidth) / pageCanvas.width); + + yOffset += pageCanvas.height; + } + + const filename = withAnswers ? `${selectedQuiz.title}_avec_reponses.pdf` : `${selectedQuiz.title}_sans_reponses.pdf`; - doc.save(filename); + pdf.save(filename); } catch (error) { console.error('Error exporting quiz as PDF:', error); } diff --git a/client/src/components/DownloadQuizModal/preview.html b/client/src/components/DownloadQuizModal/preview.html new file mode 100644 index 0000000..8c166a2 --- /dev/null +++ b/client/src/components/DownloadQuizModal/preview.html @@ -0,0 +1,461 @@ +
+
+ + (Sans titre) + + + Choix multiple + +
+ +
+ +

+ Quelle ville est la capitale du Canada? +

+
+
+Choisir une réponse: +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + +
+
+ + (Sans titre) + + + Réponse courte + +
+ +
+ +

+ Avec quoi ouvre-t-on une porte? +

+
+
+ +
+ Réponse: +
+
+
+ + (Sans titre) + + + Numérique + +
+ +
+ +

+ Quel est un nombre de 1 à 5 ? +

+
+
+

Réponse:

+
+ + (Sans titre) + + + Numérique + +
+ +
+ +

+ Quel est un nombre de 1 à 5 ? +

+
+
+

Réponse:

+
+ + (Sans titre) + + + Numérique + +
+ +
+ +

+ Quand est né Ulysses S. Grant ? +

+
+
+

Réponse:

Réponse:

+
+ + (Sans titre) + + + Vrai/Faux + +
+ +
+ +

+ 2+2 = 4 ? +

+
+
+Choisir une réponse: +
+ + + + + + +
+ +
+ + + + + + +
+
+
+ + (Sans titre) + + + Choix multiple + +
+ +
+ +

+ Quelles villes trouve-t-on au Canada? +

+
+
+Choisir une réponse ou plusieurs: +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
+ +
\ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a33957e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "EvalueTonSavoir", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}