Bonjour,

Je cherche a générer un pdf à partir d'un formulaire. J'ai bien avancé en m'inspirant du site de l'attestation de déplacement, mais étant novice en js j'ai du louper quelque chose.

Je n'ai pas d'erreur dans la console mais lorsque je clic sur le bouton mon pdf ne ce générer pas.

J'ai mis mon projet sur GitHub pour plus de facilité

https://github.com/JefNewTech/Generateur_conge.git

sinon voici le
Code HTML : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<!DOCTYPE html>
<html lang="fr">
 
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="./conge.css">
 
    <link rel="apple-touch-icon" sizes="180x180" href="./favicons/apple-icon-180x180.png">
    <link rel="icon" type="image/png" sizes="32x32" href="./favicons/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="./favicons/favicon-16x16.png">
    <link rel="mask-icon" href="./favicons/safari-pinned-tab.svg" color="#21bf73">
 
</head>
 
<body>
    <form>
        <h2>Générateur de feuille de congé.</h2>
        <form id="form-conge" action="#">
            <p><i>Complétez le formulaire. Les champs marqué par </i><em>*</em> sont <em>obligatoires</em></p>
            <fieldset>
                <legend>Contact</legend>
                <label for="Nom et Prénom">Nom et prénom <em>*</em></label>
                <input id="field-nom" name="name" placeholder="Dupont Jean" autofocus="" required="">
            </fieldset>
            <fieldset>
                <legend>Date du(des) congé(s) </legend>
                <label for="Début">Date de début <em>*</em></label>
                <input id="field-debut" name="debut" type="text" required="">
                <p>
                    <label for="Fin">Date de fin </label>
                    <input id="field-fin" name="fin" type="text">
            </fieldset>
            <fieldset>
                <legend>Choisissez un motif de congé</legend>
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-VaAn" value="VaAn" checked>
                    <label class="form-check-label" for="radio-VaAn">Vacances Annuelles</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-ReHs" value="ReHs">
                    <label class="form-check-label" for="radio-ReHs">Récupération d'heures supplémentaires</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-CoCi" value="CoCi">
                    <label class="form-check-label" for="radio-CoCi">Congé de Circonstance</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-CoFmp" value="CoFmp">
                    <label class="form-check-label" for="radio-CoFmp">Congé pour force majeur payé ( 4jours)</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-CoFmNp" value="CoFmNp">
                    <label class="form-check-label" for="radio-CoFmNp">Congé pour force majeur non payé ( 6jours)</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-COMiC" value="COMiC">
                    <label class="form-check-label" for="radio-COMiC">Congé pour motif imperieux (Contractuel)</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-COMIS" value="COMIS">
                    <label class="form-check-label" for="radio-COMIS">Congé pour motif imperieux (Statutaire)</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-CoSy" value="CoSy">
                    <label class="form-check-label" for="radio-CoSy">Congé Syndical</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-CoPa" value="CoPa">
                    <label class="form-check-label" for="radio-CoPa">Congé de Paternité</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-DisCm" value="DisCm">
                    <label class="form-check-label" for="radio-DisCm">Dispense de Service Convocation médical</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-DisDo" value="DisDo">
                    <label class="form-check-label" for="radio-DisDo">Dispense de Service Don de moelle, Organe</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-DisDp" value="DisDp">
                    <label class="form-check-label" for="radio-DisDp">Dispense de Service Don de plaquettes</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-DisDs" value="DisDs">
                    <label class="form-check-label" for="radio-DisDs">Dispense de Service Don de Sang</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-DisRm" value="DisRm">
                    <label class="form-check-label" for="radio-DisRm">Dispense de Service RDV médical Service</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-EnGr" value="EnGr">
                    <label class="form-check-label" for="radio-EnGr">En Grève</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-FoPr" value="FoPr">
                    <label class="form-check-label" for="radio-FoPr">Formation professionnelle </label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-JoVe" value="JoVe">
                    <label class="form-check-label" for="radio-JoVe">Jour(s) Vert(s)</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-Mala" value="Mala">
                    <label class="form-check-label" for="radio-Mala">Maladie</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-MiEx" value="MiEx">
                    <label class="form-check-label" for="radio-MiEx">Mission extérieure</label>
                </div>
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-MiTme" value="MiTme">
                    <label class="form-check-label" for="radio-MiTme">Mi-Temps médical</label>
                </div>
 
 
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="field-reason" id="radio-none" value="">
                    <label class="form-check-label" for="radio-none">Aucun (remplissage manuel)</label>
                </div>
            </fieldset>
            <fieldset>
                <legend>Signature</legend>
                <div class="form-group">
                    <label>Dessinez votre signature dans la case ci-dessous.</label>
                    <canvas id="field-signature" width=360 height=240 aria-describedby="help-signature"></canvas>
                    <button id="reset-signature" type="button" class="btn btn-link btn-sm float-right">Effacer la signature</button>
                    <br><br>
                </div>
            </fieldset>
            <p><input type="button" id="generate-btn" value="Générer la feuille de congé"></p>
        </form>
    </form>
    <script src="https://cdn.jsdelivr.net/npm/signature_pad@2.3.2/dist/signature_pad.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/pdf-lib@1.4.1/dist/pdf-lib.js"></script>
    <script src="conge.js"></script>
 
</body>
 
</html>

Et le Js :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
const {
    PDFDocument,
    StandardFonts
} = PDFLib
const $ = (...args) => document.querySelector(...args)
const $$ = (...args) => document.querySelectorAll(...args)
 
 
function getProfile() {
    const fields = {}
    for (const field of $$('#form-conge input')) {
        if (field.id == 'field-debut') {
            const debut = field.value.split('-')
            fields[field.id.substring('field-'.length)] = '${debut[2]}/${debut[1]}'
        } else {
            fields[field.id.substring('field-'.length)] = field.value
        }
    }
    return fields
}
 
async function generatePdf(profile, reason) {
    const pdfBase = 'Conge.pdf'
    const creationInstant = new Date()
    const creationDate = creationInstant.toLocaleDateString('fr-FR')
 
    const {
        name,
        debut,
        fin
    } = profile
 
    const existingPdfBytes = await fetch(pdfBase).then((res) => res.arrayBuffer())
 
    const pdfDoc = await PDFDocument.load(existingPdfBytes)
    const page = pdfDoc.getPages()[0]
 
    const font = await pdfDoc.embedFont(StandardFonts.Helvetica)
    const drawText = (text, x, y, size = 11) => {
        page.drawText(text, {
            x,
            y,
            size,
            font
        })
    }
 
    drawText(profile.name, 180, 235, 12)
    if (profile.fin !== '') {
        drawText(`Du ${profile.debut}`, 25, 180)
        drawText(`au ${profile.fin}`, 120, 180)
    } else {
        drawText(`Le ${profile.debut}`, 25, 180)
    }
 
    switch (reason) {
        case 'VaAn':
            drawText('de vacance annuelle', 25, 200, 15)
            break
        case 'ReHs':
            drawText('de récupération d heures supplémentaires', 25, 200, 15)
            break
        case 'CoCi':
            drawText('d un congé de Circonstance', 25, 200, 15)
            break
        case 'CoFmp':
            drawText('d un congé pour force majeur payé ( 4jours)', 25, 200, 15)
            break
        case 'CoFmNp':
            drawText('d un congé pour force majeur non payé ( 6jours)', 25, 200, 15)
            break
        case 'COMiC':
            drawText('d un congé pour motif imperieux (Contractuel)', 25, 200, 15)
            break
        case 'COMIS':
            drawText('d un congé pour motif imperieux (Statutaire)', 25, 200, 15)
            break
        case 'CoPa':
            drawText('d un congé Syndical', 25, 200, 15)
            break
        case 'DisCm':
            drawText('d une dispense de Service Convocation médical', 25, 200, 15)
            break
        case 'DisDo':
            drawText('d une dispense de Service Don de moelle, Organe', 25, 200, 15)
            break
        case 'DisDp':
            drawText('d une dispense de Service Don de plaquettes', 25, 200, 15)
            break
        case 'DisDs':
            drawText('d une dispense de Service Don de Sang', 25, 200, 15)
            break
        case 'DisRm':
            drawText('d une dispense de Service RDV médical Service', 25, 200, 15)
            break
        case 'EnGr':
            drawText('d un congé pour greve', 25, 200, 15)
            break
        case 'FoPr':
            drawText('d un congé pour formation professionnelle', 25, 200, 15)
            break
        case 'JoVe':
            drawText('d un jour vert', 25, 200, 15)
            break
        case 'Mala':
            drawText('d un congé pour maladie', 25, 200, 15)
            break
        case 'MiEx':
            drawText('d un congé pour mission exterieur', 25, 200, 15)
            break
        case 'MiTime':
            drawText('d un congé pour mi-temps médical', 25, 200, 15)
            break
    }
 
    if (reason !== '') {
        const date = [
      String((new Date).getDate()).padStart(2, '0'),
      String((new Date).getMonth() + 1).padStart(2, '0'),
      String((new Date).getFullYear()),
    ].join('/')
 
        drawText(date, 405, 354)
    }
    const pdfBytes = await pdfDoc.save()
    return new Blob([pdfBytes], {
        type: 'application/pdf'
    })
}
 
function downloadBlob(blob, fileName) {
    const link = document.createElement('a')
    var url = URL.createObjectURL(blob)
    link.href = url
    link.download = fileName
    link.click()
}
 
function getReason() {
    const val = $('input[name="field-reason"]:checked').value
    return val
}
 
const snackbar = $('#snackbar')
 
$('#generate-btn').addEventListener('click', async (event) => {
    event.preventDefault()
    const invalid = validateAriaFields()
    if (invalid) return
 
    const reason = getReason()
    const pdfBlob = await generatePdf(getProfile(), reason)
 
    const creationInstant = new Date()
    const creationDate = creationInstant.toLocaleDateString('fr-CA')
    const creationHour = creationInstant
        .toLocaleTimeString('fr-FR', {
            hour: '2-digit',
            minute: '2-digit'
        })
        .replace(':', '-')
    downloadBlob(pdfBlob, `Feuille-${creationDate}_${creationHour}.pdf`)
 
    snackbar.classList.remove('d-none')
    setTimeout(() => snackbar.classList.add('show'), 100)
 
    setTimeout(function () {
        snackbar.classList.remove('show')
        setTimeout(() => snackbar.classList.add('d-none'), 500)
    }, 6000)
})
 
$$('input').forEach((input) => {
    const exempleElt = input.parentNode.parentNode.querySelector('.exemple')
    const validitySpan = input.parentNode.parentNode.querySelector('.validity')
    if (input.placeholder && exempleElt) {
        input.addEventListener('input', (event) => {
            if (input.value) {
                exempleElt.innerHTML = 'ex.&nbsp;: ' + input.placeholder
                validitySpan.removeAttribute('hidden')
            } else {
                exempleElt.innerHTML = ''
            }
        })
    }
})
 
const conditions = {
    '#field-nom': {
        condition: 'length',
    },
    '#field-debut': {
        condition: 'pattern',
        pattern: /\d{4}-\d{2}-\d{2}/g,
    },
    '#field-fin': {
        condition: 'pattern',
        pattern: /\d{4}-\d{2}-\d{2}/g,
    },
}
 
function validateAriaFields() {
    return Object.keys(conditions).map(field => {
        if (conditions[field].condition === 'pattern') {
            const pattern = conditions[field].pattern
            if ($(field).value.match(pattern)) {
                $(field).setAttribute('aria-invalid', 'false')
                return 0
            } else {
                $(field).setAttribute('aria-invalid', 'true')
                $(field).focus()
                return 1
            }
        }
        if (conditions[field].condition === 'length') {
            if ($(field).value.length > 0) {
                $(field).setAttribute('aria-invalid', 'false')
                return 0
            } else {
                $(field).setAttribute('aria-invalid', 'true')
                $(field).focus()
                return 1
            }
        }
    }).some(x => x === 1)
}
Merci pour vos lumières