PageSourceSearch

https://louisdecharson.github.io/deplacement-covid/script.js

js louisdecharson.github.io collected 2026-10-03 09:32:10 UTC 8,483 bytes, 263 lines download raw bytes

1const {PDFDocument, StandardFonts} = PDFLib;
2
3const $ = (...args) => document.querySelector(...args);
4const $$ = (...args) => [...document.querySelectorAll(...args)];
5let profil = {};
6
7// Changement langue
8function changeLangue(langue) {
9    for (const _ of document.getElementsByClassName('langue')) {
10        _.classList.remove('actif');
11    }
12    document.getElementById(langue).classList.add('actif');
13    for (const champ of document.getElementsByClassName('texte')) {
14        if (Object.keys(langues).indexOf(langue) > -1) {
15            let idChamp = champ.id,
16                traductionChamp = langues[langue][idChamp];
17            champ.innerHTML = traductionChamp;
18            // Change aussi le placeholder s'il existe et n'est pas une date
19            if (idChamp.includes('label') &&
20                champ.parentElement.nextElementSibling.hasAttribute('placeholder') &&
21                champ.parentElement.nextElementSibling.getAttribute('type') != 'date') {
22                champ.parentElement.nextElementSibling.setAttribute('placeholder', traductionChamp);
23            }
24        }
25    }
26    localStorage.setItem('langue', langue);
27    
28}
29for (const el of document.getElementsByClassName('langue')) {
30    el.addEventListener('click', () => changeLangue(el.id));
31}
32// Changement automatique de la langue
33if (localStorage.getItem('langue')) {
34    changeLangue(localStorage.getItem('langue'));
35} else {
36    // Détection de la langue du navigateur
37    // https://stackoverflow.com/questions/1043339/javascript-for-detecting-browser-language-preference
38    let lang = window.navigator.languages ? window.navigator.languages[0] : null;
39    lang = lang || window.navigator.language || window.navigator.browserLanguage || window.navigator.userLanguage;
40    let shortLang = lang;
41    if (shortLang.indexOf('-') !== -1)
42        shortLang = shortLang.split('-')[0];
43    if (shortLang.indexOf('_') !== -1)
44        shortLang = shortLang.split('_')[0];
45    if (Object.keys(langues).indexOf(shortLang) > -1)
46        changeLangue(shortLang);
47}
48
49// Formattage Date
50function pad (str) {
51    return String(str).padStart(2, '0');
52}
53
54function getFormattedDate (date) {
55    const year = date.getFullYear();
56    const month = pad(date.getMonth() + 1);
57    const day = pad(date.getDate());
58    return `${year}-${month}-${day}`;
59}
60document.addEventListener('DOMContentLoaded', setReleaseDateTime);
61function setReleaseDateTime () {
62    const releaseDateInput = $('#date_sortie');
63    const loadedDate = new Date();
64    releaseDateInput.value = getFormattedDate(loadedDate);
65
66    const hour = pad(loadedDate.getHours());
67    const minute = pad(loadedDate.getMinutes());
68
69    const releaseTimeInput = $('#heure_sortie');
70    releaseTimeInput.value = `${hour}:${minute}`;
71}
72
73// QR Code
74const generateQR = async (text) => {
75  try {
76    const opts = {
77      errorCorrectionLevel: 'M',
78      type: 'image/png',
79      quality: 0.92,
80      margin: 1,
81    }
82      return await QRCode.toDataURL(text, opts);
83  } catch (err) {
84      console.error(err);
85  }
86}
87
88// Création PDF
89function idealFontSize (font, text, maxWidth, minSize, defaultSize) {
90    let currentSize = defaultSize;
91    let textWidth = font.widthOfTextAtSize(text, defaultSize);
92    while (textWidth > maxWidth && currentSize > minSize) {
93        textWidth = font.widthOfTextAtSize(text, --currentSize);
94    }
95    return textWidth > maxWidth ? null : currentSize;
96}
97async function generatePdf (profile, reasons) {
98    const creationInstant = new Date();
99    const creationDate = creationInstant.toLocaleDateString('fr-FR');
100    const creationHour = creationInstant
101          .toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })
102          .replace(':', 'h');
103
104    const {
105        adresse,
106        code_postal,
107        date_naissance,
108        date_sortie,
109        heure_sortie,
110        lieu_naissance,
111        nom,
112        prenom,
113        ville,
114    } = profile;
115    const releaseHours = String(heure_sortie).substring(0, 2);
116    const releaseMinutes = String(heure_sortie).substring(3, 5);
117
118  const data = [
119      `Cree le: ${creationDate} a ${creationHour}`,
120      `Nom: ${nom}`,
121      `Prenom: ${prenom}`,
122      `Naissance: ${date_naissance} a ${lieu_naissance}`,
123      `Adresse: ${adresse} ${code_postal} ${ville}`,
124      `Sortie: ${date_sortie} a ${releaseHours}h${releaseMinutes}`,
125      `Motifs: ${reasons}`,
126  ].join('; ');
127
128    const existingPdfBytes = await fetch('./certificate.pdf').then((res) => res.arrayBuffer())
129
130    const pdfDoc = await PDFDocument.load(existingPdfBytes);
131    const page1 = pdfDoc.getPages()[0];
132
133    const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
134    const drawText = (text, x, y, size = 11) => {
135        page1.drawText(text, { x, y, size, font });
136    };
137    
138    drawText(`${prenom} ${nom}`, 123, 686);
139    drawText(date_naissance, 123, 661);
140    drawText(lieu_naissance, 92, 638);
141    drawText(`${adresse} ${code_postal} ${ville}`, 134, 613);
142
143    if (reasons.includes('travail')) {
144        drawText('x', 76, 527, 19);
145    }
146    if (reasons.includes('courses')) {
147        drawText('x', 76, 478, 19);
148    }
149    if (reasons.includes('sante')) {
150        drawText('x', 76, 436, 19);
151    }
152    if (reasons.includes('famille')) {
153        drawText('x', 76, 400, 19);
154    }
155    if (reasons.includes('sport')) {
156        drawText('x', 76, 345, 19);
157    }
158    if (reasons.includes('judiciaire')) {
159        drawText('x', 76, 298, 19);
160    }
161    if (reasons.includes('missions')) {
162        drawText('x', 76, 260, 19);
163    }
164    let locationSize = idealFontSize(font, ville, 83, 7, 11);
165
166    if (!locationSize) {
167        alert(
168            'Le nom de la ville risque de ne pas être affiché correctement en raison de sa longueur. ' +
169                'Essayez d\'utiliser des abréviations ("Saint" en "St." par exemple) quand cela est possible.',
170        );
171        locationSize = 7;
172    }
173    drawText(ville, 111, 226, locationSize);
174    if (reasons !== '') {
175        // Date sortie
176        drawText(`${date_sortie}`, 92, 200);
177        drawText(releaseHours, 200, 201);
178        drawText(releaseMinutes, 220, 201);
179    }
180
181    // Date création
182    drawText('Date de création:', 464, 150, 7);
183    drawText(`${creationDate} à ${creationHour}`, 455, 144, 7);
184
185    const generatedQR = await generateQR(data);
186
187    const qrImage = await pdfDoc.embedPng(generatedQR);
188
189    page1.drawImage(qrImage, {
190        x: page1.getWidth() - 170,
191        y: 155,
192        width: 100,
193        height: 100,
194    });
195
196    pdfDoc.addPage()
197    const page2 = pdfDoc.getPages()[1];
198    page2.drawImage(qrImage, {
199        x: 50,
200        y: page2.getHeight() - 350,
201        width: 300,
202        height: 300,
203    });
204
205    const pdfBytes = await pdfDoc.save();
206
207    return new Blob([pdfBytes], { type: 'application/pdf' });
208}
209
210
211// Télécharger attestation
212function downloadBlob (blob, fileName) {
213    const link = document.createElement('a');
214    const url = URL.createObjectURL(blob);
215    link.href = url;
216    link.download = fileName;
217    document.body.appendChild(link);
218    link.click();
219}
220
221function getMotifs () {
222    return $$('input[name="motif"]:checked')
223        .map((x) => x.value)
224        .join('-');
225}
226function saveProfil () {
227    const champs = {};
228    for (const field of $$('#champs-profil input')) {
229        if (field.id === 'date_sortie-label') {
230            const dateSortie = field.value.split('-');
231            champs[dateSortie] = `${dateSortie[2]}/${dateSortie[1]}/${dateSortie[0]}`;
232        } else if (! field.id.includes('checkbox')) {
233             champs[field.id] = field.value;
234        }
235    }
236    localStorage.setItem("profil",JSON.stringify(champs));
237    return champs;
238}
239// Sauvegarder Profile 
240// Générer attestation
241$('#generer-attestation').addEventListener('click', async (event) => {
242    event.preventDefault();
243
244    profil = saveProfil();
245    
246    const reasons = getMotifs();
247    const pdfBlob = await generatePdf(profil, reasons);
248
249    const creationInstant = new Date();
250    const creationDate = creationInstant.toLocaleDateString('fr-CA');
251    const creationHour = creationInstant
252          .toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })
253          .replace(':', '-');
254    downloadBlob(pdfBlob, `attestation-${creationDate}_${creationHour}.pdf`);
255
256});
257
258if (localStorage.getItem('profil')) {
259    profil = JSON.parse(localStorage.getItem('profil'));
260    for (const champ of Object.keys(profil)) {
261        $(`#${champ}`).value = profil[champ];
262    }
263}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.