Premier dépôt du projet #1
henoc Gnaoule · il y a 3 h
4 fichiers concernés
cv_panneau.css Ajouté
+107 −0
| … | ||
| 1 | +/* ========================================================================== | |
| 2 | + Panneau CV — Eliora | |
| 3 | + Ouvre le CV de l'utilisateur dans un panneau à droite de la conversation. | |
| 4 | + Fonctionne avec js/script_cv_panneau.js. | |
| 5 | + --cv-w = largeur du panneau, réglée par le script (poignée de redimensionnement). | |
| 6 | + ========================================================================== */ | |
| 7 | + | |
| 8 | +:root { --cv-w: 46vw; } | |
| 9 | + | |
| 10 | +/* ---------- Le panneau ---------- */ | |
| 11 | +#cv-panneau { | |
| 12 | + position: fixed; top: 0; right: 0; bottom: 0; | |
| 13 | + width: var(--cv-w); | |
| 14 | + z-index: 1000; | |
| 15 | + display: none; flex-direction: column; | |
| 16 | + background-color: #ffffff; | |
| 17 | + border-left: 1px solid #dcdce0; | |
| 18 | + box-shadow: rgba(9, 30, 66, 0.12) -4px 0 12px -4px; | |
| 19 | + font-family: Helvetica, Arial, sans-serif; | |
| 20 | + box-sizing: border-box; | |
| 21 | +} | |
| 22 | +body.cv-ouvert #cv-panneau { display: flex; } | |
| 23 | +body.cv-plein #cv-panneau { width: 100%; border-left: none; } | |
| 24 | + | |
| 25 | +#cv-entete { | |
| 26 | + display: flex; align-items: center; gap: 12px; | |
| 27 | + padding: 10px 14px 10px 18px; | |
| 28 | + border-bottom: 1px solid #e5e5e7; | |
| 29 | + flex: none; | |
| 30 | +} | |
| 31 | +#cv-infos { flex: 1; min-width: 0; display: flex; flex-direction: column; } | |
| 32 | +#cv-nom { font-size: 15px; font-weight: bold; color: #222; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } | |
| 33 | +#cv-meta { font-size: 12px; color: gray; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } | |
| 34 | + | |
| 35 | +#cv-outils { display: flex; align-items: center; gap: 4px; flex: none; } | |
| 36 | +.cv-bouton { | |
| 37 | + min-width: 34px; height: 34px; padding: 0 8px; | |
| 38 | + border: none; border-radius: 50%; | |
| 39 | + background-color: transparent; color: #333; | |
| 40 | + font-family: Helvetica, Arial, sans-serif; font-size: 18px; | |
| 41 | + cursor: pointer; display: inline-flex; align-items: center; justify-content: center; | |
| 42 | +} | |
| 43 | +.cv-bouton:hover { background-color: #e5e5e7; } | |
| 44 | +.cv-bouton:disabled { opacity: 0.35; cursor: default; background-color: transparent; } | |
| 45 | +.cv-bouton:focus-visible, #cv-onglet:focus-visible, #cv-poignee:focus-visible { outline: 2px solid dodgerblue; outline-offset: 2px; } | |
| 46 | +#cv-zoom { min-width: 48px; text-align: center; font-size: 13px; color: gray; } | |
| 47 | +#cv-fermer { margin-left: 6px; background-color: #e5e5e7; } | |
| 48 | +#cv-fermer:hover { background-color: #d6d6da; } | |
| 49 | + | |
| 50 | +#cv-scene { flex: 1; min-height: 0; overflow: auto; background-color: #F0F0F2; padding: 18px 16px; } | |
| 51 | +#cv-pages { display: flex; flex-direction: column; gap: 14px; align-items: flex-start; --cv-zoom: 1; } | |
| 52 | +.cv-page { | |
| 53 | + display: block; flex: none; | |
| 54 | + width: calc(var(--cv-zoom) * 100%); max-width: none; height: auto; | |
| 55 | + margin-left: auto; margin-right: auto; | |
| 56 | + background-color: #ffffff; | |
| 57 | + box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px, rgba(9, 30, 66, 0.08) 0px 0px 0px 1px; | |
| 58 | +} | |
| 59 | +/* Aperçu des fichiers Word et texte : une feuille blanche, le zoom agit sur la taille du texte */ | |
| 60 | +.cv-feuille { | |
| 61 | + width: 100%; box-sizing: border-box; padding: 36px 40px; | |
| 62 | + font-family: Helvetica, Arial, sans-serif; font-size: calc(15px * var(--cv-zoom)); line-height: 1.5; color: #222; | |
| 63 | + overflow-wrap: anywhere; | |
| 64 | +} | |
| 65 | +.cv-texte { white-space: pre-wrap; } | |
| 66 | +.cv-feuille p { margin: 0 0 0.7em; } | |
| 67 | +.cv-feuille h1, .cv-feuille h2, .cv-feuille h3, .cv-feuille h4 { margin: 1em 0 0.4em; line-height: 1.25; } | |
| 68 | +.cv-feuille h1 { font-size: 1.6em; } .cv-feuille h2 { font-size: 1.3em; } .cv-feuille h3, .cv-feuille h4 { font-size: 1.1em; } | |
| 69 | +.cv-feuille ul, .cv-feuille ol { margin: 0 0 0.7em; padding-left: 1.4em; } | |
| 70 | +.cv-feuille table { border-collapse: collapse; width: 100%; margin: 0 0 0.7em; } | |
| 71 | +.cv-feuille td, .cv-feuille th { border: 1px solid #dcdce0; padding: 4px 8px; vertical-align: top; text-align: left; } | |
| 72 | +.cv-feuille img { max-width: 100%; height: auto; } | |
| 73 | + | |
| 74 | +#cv-note { margin: 0; padding: 30px 10px; text-align: center; font-size: 14px; color: gray; } | |
| 75 | + | |
| 76 | +/* ---------- Poignée de redimensionnement (bord gauche du panneau) ---------- */ | |
| 77 | +#cv-poignee { position: absolute; top: 0; bottom: 0; left: -5px; width: 10px; cursor: col-resize; touch-action: none; } | |
| 78 | +#cv-poignee:hover, body.cv-redim #cv-poignee { background-color: rgba(30, 144, 255, 0.35); } | |
| 79 | +body.cv-redim { cursor: col-resize; user-select: none; } | |
| 80 | +body.cv-plein #cv-poignee { display: none; } | |
| 81 | + | |
| 82 | +/* ---------- Onglet « Voir mon CV » quand le panneau est fermé ---------- */ | |
| 83 | +#cv-onglet { | |
| 84 | + position: fixed; right: 0; top: 80px; z-index: 900; | |
| 85 | + display: none; align-items: center; gap: 8px; | |
| 86 | + padding: 10px 14px 10px 12px; | |
| 87 | + border: none; border-radius: 20px 0 0 20px; | |
| 88 | + background-color: #ffffff; color: #333; | |
| 89 | + font-family: Helvetica, Arial, sans-serif; font-size: 14px; | |
| 90 | + box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px, rgba(9, 30, 66, 0.08) 0px 0px 0px 1px; | |
| 91 | + cursor: pointer; | |
| 92 | +} | |
| 93 | +#cv-onglet:hover { color: dodgerblue; } | |
| 94 | +body.cv-charge:not(.cv-ouvert) #cv-onglet { display: inline-flex; } | |
| 95 | + | |
| 96 | +/* ---------- La conversation se pousse à gauche quand le panneau est ouvert ---------- */ | |
| 97 | +body.cv-ouvert:not(.cv-plein) #visio { width: calc(100% - var(--cv-w)) !important; margin: 0 !important; } | |
| 98 | +body.cv-ouvert:not(.cv-plein) #affiche_message { max-width: calc(100% - 40px); } | |
| 99 | +body.cv-ouvert:not(.cv-plein) #boto, | |
| 100 | +body.cv-ouvert:not(.cv-plein) #label_text { | |
| 101 | + left: calc((100% - var(--cv-w)) / 2) !important; | |
| 102 | + max-width: calc(100% - var(--cv-w) - 40px); | |
| 103 | +} | |
| 104 | +body.cv-ouvert:not(.cv-plein) #boto textarea { max-width: 100%; } | |
| 105 | +body.cv-ouvert:not(.cv-plein) #pied-eliora { width: calc(100% - var(--cv-w)) !important; } | |
| 106 | +body.cv-ouvert:not(.cv-plein) #pied-eliora span { left: calc((100% - var(--cv-w)) / 2) !important; } | |
| 107 | + | |
eliora_chat_1.php Ajouté
+208 −0
| … | ||
| 1 | +<?php | |
| 2 | +error_reporting(0); | |
| 3 | + | |
| 4 | +$mobile = $_SERVER['HTTP_USER_AGENT']; | |
| 5 | + | |
| 6 | +if(preg_match("(iPhone|BlackBerry|Android|HTC|LG|MOT|Nokia|Palm|SAMSUNG|SonyEricsson)",$mobile)){ | |
| 7 | + header('Location:/eliora_chat_mobile.php');} | |
| 8 | +?> | |
| 9 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
| 10 | +<html xmlns="http://www.w3.org/1999/xhtml"> | |
| 11 | +<head> | |
| 12 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"/> | |
| 13 | +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |
| 14 | +<title>Eliora AI</title> | |
| 15 | + <link rel="icon" type="image/png" href="image/apv.ico"> | |
| 16 | + <link rel="shortcut icon" href="image/apvx.png"/> | |
| 17 | + <link rel="stylesheet" type="text/css" href="css/style.css"> | |
| 18 | + <link rel="stylesheet" type="text/css" href="css/message_form.css"> | |
| 19 | + <link rel="stylesheet" type="text/css" href="css/cv_panneau.css"> | |
| 20 | + <script type="text/javascript" src="js/jquery.js"></script> | |
| 21 | + <script type="text/javascript" src="js/script_form.js"></script> | |
| 22 | +</head> | |
| 23 | +<body style="background-color: #F0F0F2"> | |
| 24 | + | |
| 25 | + <div class="box" style="position:; background-color:#F0F0F2"> | |
| 26 | + <img src="image/apvx.png" width="30px" style="margin-left:20px; margin-top:10px; background-color:#F0F0F2; display:inline-block; float:left"/> | |
| 27 | + <button style="width:50px; height:50px; margin-top:15px; font-size:25px; font-family:Helvetica; border-radius:17px; border:none; cursor:pointer; | |
| 28 | + background-color:#F0F0F2; margin-left:5px; margin-top:5px">Eliora</button> | |
| 29 | + | |
| 30 | + </div> | |
| 31 | + | |
| 32 | + | |
| 33 | +<div id="visio" style="width: 100%; height:700px; border:none; margin: 0 auto; background-color:#F0F0F2; position:relative; overflow:auto"> | |
| 34 | + <div id="affiche_message" style="width: 730px; height:auto; border:none; margin: 0 auto; padding-bottom: 200px; padding-top:70px; background-color:#F0F0F2; position:relative; overflow:auto; display:flex; flex-direction: column"> | |
| 35 | + </div> | |
| 36 | + | |
| 37 | + </div> | |
| 38 | + | |
| 39 | + <div id="cv-statut" style="display:none; font-family:Helvetica; font-size:14px; color:gray; margin-top:8px;"></div> | |
| 40 | + <div id="label_text" style="width:500px; height:60px; border:none; position:fixed; background-color:#F0F0F2; bottom:62%; left: 50%; | |
| 41 | + transform: translateX(-50%); border-radius:20px; text-align:center"> | |
| 42 | + <span id="text_chang" style="font-family:Helvetica; font-size:30px">Hello <span style="font-family:Helvetica; font-size:30px;"><?php echo htmlspecialchars((string) ($_SESSION['prenom'] ?? ''), ENT_QUOTES, 'UTF-8'); ?></span></span> | |
| 43 | + </div> | |
| 44 | + | |
| 45 | + <div id="boto" style="width:750px; height:; border:none; position: fixed; background-color:white; bottom:45%; left: 50%; | |
| 46 | + transform: translateX(-50%); border-radius:20px; z-index:10; | |
| 47 | + box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px, rgba(9, 30, 66, 0.08) 0px 0px 0px 1px"> | |
| 48 | + | |
| 49 | + | |
| 50 | + <form method="POST" action="donnees.php" id="formulaire" > | |
| 51 | + | |
| 52 | + <button type="button" id="bouton-menu" onclick="toggleMenu()" style="position:absolute; left:10px; bottom:10px; width:36px; height:36px; border-radius:50%; border:none; background-color:#e5e5e7; color:#333; cursor:pointer; display:flex; align-items:center; justify-content:center; transition: transform 0.25s ease, background-color 0.2s;" aria-label="Ouvrir le menu des options"> | |
| 53 | + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="18" height="18" id="icone-menu"> | |
| 54 | + <line x1="12" y1="5" x2="12" y2="19"></line> | |
| 55 | + <line x1="5" y1="12" x2="19" y2="12"></line> | |
| 56 | + </svg> | |
| 57 | + </button> | |
| 58 | + <label for="mess" style="position:absolute; left:-9999px;">Poser une question</label> | |
| 59 | + <textarea id="mess" name="message" placeholder="Comment puis-je vous aider ?" maxlength="" style="width:720px; height:100px; | |
| 60 | + border-radius:20px; border:none; padding-top:20px; padding-left:20px; font-size:16px; font-family:Helvetica; | |
| 61 | + box-sizing:border-box;line-height:20px;overflow:hidden; padding-bottom:47px; display:block" ></textarea> | |
| 62 | + | |
| 63 | + | |
| 64 | + <button type="submit" id="publier" disabled onclick="gre()" style="position:absolute; right:10px; bottom:10px; width:36px; height:36px; border-radius:50%; border:none; background-color:dodgerblue; color:gray; cursor:pointer; display:flex; align-items:center; justify-content:center; transition: background-color 0.2s;" aria-label="Envoyer le message"> | |
| 65 | + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="18" height="18"> | |
| 66 | + <line x1="12" y1="19" x2="12" y2="5"></line> | |
| 67 | + <polyline points="5 12 12 5 19 12"></polyline> | |
| 68 | + </svg> | |
| 69 | + </button> | |
| 70 | + <div id="menu-options" style="display:none; position:absolute; left:10px; bottom:55px; background:#fff; border:1px solid #ddd; border-radius:10px; box-shadow:0 2px 10px rgba(0,0,0,0.1); padding:8px; min-width:160px; z-index:20;"> | |
| 71 | + <div class="option-menu" style="padding:8px 12px; cursor:pointer; border-radius:6px; font-size:14px; font-family:helvetica" onclick="professionnel()">Professionnel</div> | |
| 72 | + <div class="option-menu" style="padding:8px 12px; cursor:pointer; border-radius:6px; font-size:14px; font-family:helvetica" onclick="finance()">Finance</div> | |
| 73 | + </div> | |
| 74 | + </form> | |
| 75 | + | |
| 76 | +<form method="POST" action="donnees_professionnelles.php" id="formulairepro" style="display:none" > | |
| 77 | + | |
| 78 | + <button type="button" id="pro-menu" onclick="proMenu()" style="position:absolute; left:10px; bottom:10px; width:36px; height:36px; border-radius:50%; border:none; background-color:#e5e5e7; color:#333; cursor:pointer; display:flex; align-items:center; justify-content:center; transition: transform 0.25s ease, background-color 0.2s;" aria-label="Ouvrir le menu des options"> | |
| 79 | + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="18" height="18" id="icone-menu-pro"> | |
| 80 | + <line x1="12" y1="5" x2="12" y2="19"></line> | |
| 81 | + <line x1="5" y1="12" x2="19" y2="12"></line> | |
| 82 | + </svg> | |
| 83 | + </button> | |
| 84 | + <label for="professionnel" style="position:absolute; left:-9999px;">Rechercher un professionnel</label> | |
| 85 | + <textarea id="professionnel" name="messagepro" placeholder="Rechercher un professionnel" maxlength="" style="width:720px; height:100px; | |
| 86 | + border-radius:20px; border:none; padding-top:20px; padding-left:20px; font-size:16px; font-family:Helvetica; | |
| 87 | + box-sizing:border-box;line-height:20px;overflow:hidden; padding-bottom:47px; display:block" ></textarea> | |
| 88 | + | |
| 89 | + | |
| 90 | + <button type="submit" id="envoipro" disabled onclick="gre()" style="position:absolute; right:10px; bottom:10px; width:36px; height:36px; border-radius:50%; border:none; background-color:dodgerblue; color:gray; cursor:pointer; display:flex; align-items:center; justify-content:center; transition: background-color 0.2s;" aria-label="Envoyer la recherche"> | |
| 91 | + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="18" height="18"> | |
| 92 | + <line x1="12" y1="19" x2="12" y2="5"></line> | |
| 93 | + <polyline points="5 12 12 5 19 12"></polyline> | |
| 94 | + </svg> | |
| 95 | + </button> | |
| 96 | + <div id="pro-options" style="display:none; position:absolute; left:10px; bottom:55px; background:#fff; border:1px solid #ddd; border-radius:10px; box-shadow:0 2px 10px rgba(0,0,0,0.1); padding:8px; min-width:160px; z-index:20;"> | |
| 97 | + <div class="option-menu" style="padding:8px 12px; cursor:pointer; border-radius:6px; font-size:14px; font-weight:bold; font-family:helvetica" onclick="professionnel()">Professionnel</div> | |
| 98 | + <div class="option-menu" style="padding:8px 12px; cursor:pointer; border-radius:6px; font-size:14px; font-family:helvetica" onclick="finance()">Finance</div> | |
| 99 | + </div> | |
| 100 | + <button id="profe-pro" style="width:130px; height:30px; font-family:Helvetica; border-radius:20px; margin-left:60px; position:fixed; bottom:5px; border:1.5px solid #F0F0F2; background-color:transparent; color:gray; cursor:pointer" disabled> | |
| 101 | + professionnel | |
| 102 | + <img src="image/ferm.png" width="20" style="margin-left:px; margin-top:px; display:inline-block;vertical-align: middle" onclick="ferm_pro()"/> | |
| 103 | + </button> | |
| 104 | + </form> | |
| 105 | + | |
| 106 | +<form method="POST" action="donnees_finances.php" id="formulairefin" style="display:none" > | |
| 107 | + | |
| 108 | + <button type="button" id="fin-menu" onclick="finMenu()" style="position:absolute; left:10px; bottom:10px; width:36px; height:36px; border-radius:50%; border:none; background-color:#e5e5e7; color:#333; cursor:pointer; display:flex; align-items:center; justify-content:center; transition: transform 0.25s ease, background-color 0.2s;" aria-label="Ouvrir le menu des options"> | |
| 109 | + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="18" height="18" id="icone-menu-fin"> | |
| 110 | + <line x1="12" y1="5" x2="12" y2="19"></line> | |
| 111 | + <line x1="5" y1="12" x2="19" y2="12"></line> | |
| 112 | + </svg> | |
| 113 | + </button> | |
| 114 | + <label for="finance" style="position:absolute; left:-9999px;">Entrer votre revenu</label> | |
| 115 | + <textarea id="finance" name="messagefin" placeholder="Entrer votre revenu" maxlength="" style="width:720px; height:100px; | |
| 116 | + border-radius:20px; border:none; padding-top:20px; padding-left:20px; font-size:16px; font-family:Helvetica; | |
| 117 | + box-sizing:border-box;line-height:20px;overflow:hidden; padding-bottom:47px; display:block" ></textarea> | |
| 118 | + | |
| 119 | + | |
| 120 | + <button type="submit" id="okfin" disabled onclick="gre()" style="position:absolute; right:10px; bottom:10px; width:36px; height:36px; border-radius:50%; border:none; background-color:dodgerblue; color:gray; cursor:pointer; display:flex; align-items:center; justify-content:center; transition: background-color 0.2s;" aria-label="Envoyer"> | |
| 121 | + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="18" height="18"> | |
| 122 | + <line x1="12" y1="19" x2="12" y2="5"></line> | |
| 123 | + <polyline points="5 12 12 5 19 12"></polyline> | |
| 124 | + </svg> | |
| 125 | + </button> | |
| 126 | + <div id="fin-options" style="display:none; position:absolute; left:10px; bottom:55px; background:#fff; border:1px solid #ddd; border-radius:10px; box-shadow:0 2px 10px rgba(0,0,0,0.1); padding:8px; min-width:160px; z-index:20;"> | |
| 127 | + <div class="option-menu" style="padding:8px 12px; cursor:pointer; border-radius:6px; font-size:14px; font-family:helvetica" onclick="professionnel()">Professionnel</div> | |
| 128 | + <div class="option-menu" style="padding:8px 12px; cursor:pointer; border-radius:6px; font-size:14px; font-weight:bold; font-family:helvetica" onclick="finance()">Finance</div> | |
| 129 | + </div> | |
| 130 | + | |
| 131 | + | |
| 132 | + <button id="profe-fin" style="width:155px; height:30px; font-family:Helvetica; border-radius:20px; margin-left:60px; position:fixed; bottom:5px; border:1.5px solid #F0F0F2; background-color:transparent; color:gray; cursor:pointer" onmouseover="ax()" onmouseout="az()" disabled> | |
| 133 | + budget & analyse | |
| 134 | + <img src="image/ferm.png" width="20" style="margin-left:px; margin-top:px; display:inline-block;vertical-align: middle" onclick="ferm_fin()"/> | |
| 135 | + </button> | |
| 136 | + | |
| 137 | + </form> | |
| 138 | + | |
| 139 | + </div> | |
| 140 | + <div id="pied-eliora" style="width:100%; height:40px; position:fixed; bottom:0px; background-color:#F0F0F2; color:; font-family:Helvetica; border:none"> | |
| 141 | + <center><span class="" style="font-family:Helvetica; font-size:12px; position:fixed; bottom:10px; | |
| 142 | + left: 50%; transform: translateX(-50%); ">En utilisant Eliora, vous acceptez les <a href="conditioniaweb.php" style="text-decoration:none; | |
| 143 | + color:skyblue">conditions d'utilisation.</a></span></center> | |
| 144 | + </div> | |
| 145 | + | |
| 146 | + <script type="text/javascript" src="js/script_bouton_ok.js"></script> | |
| 147 | + <script type="text/javascript" src="js/script_cv.js"></script> | |
| 148 | + | |
| 149 | + <script> | |
| 150 | + $(document).ready(function () { | |
| 151 | + | |
| 152 | + // --- Validation factorisée : une seule fonction réutilisée | |
| 153 | + // pour les 3 champs (message général, professionnel, finance) | |
| 154 | + // au lieu de 3 blocs quasi identiques dupliqués. | |
| 155 | + function brancherValidation(champId, boutonId) { | |
| 156 | + var minuteur = null; | |
| 157 | + | |
| 158 | + function verifierSaisie() { | |
| 159 | + var input = $('#' + champId).val(); | |
| 160 | + $.ajax({ | |
| 161 | + method: "POST", | |
| 162 | + url: 'testervaleur.php', | |
| 163 | + data: { gen: input }, | |
| 164 | + dataType: "text", | |
| 165 | + success: function (result) { | |
| 166 | + var ok = (result.trim() === "true"); | |
| 167 | + $('#' + boutonId).prop('disabled', !ok); | |
| 168 | + $('#' + boutonId).css({ | |
| 169 | + backgroundColor: ok ? "skyblue" : "#F0F0F2", | |
| 170 | + color: ok ? "white" : "gray" | |
| 171 | + }); | |
| 172 | + } | |
| 173 | + }); | |
| 174 | + } | |
| 175 | + | |
| 176 | + $('#' + champId).on('input', function () { | |
| 177 | + clearTimeout(minuteur); | |
| 178 | + minuteur = setTimeout(verifierSaisie, 250); | |
| 179 | + }); | |
| 180 | + | |
| 181 | + // Une <textarea> ne soumet pas le formulaire sur Entrée par défaut | |
| 182 | + // (contrairement à un <input type="text">) — elle insère un saut de ligne. | |
| 183 | + // On intercepte donc la touche Entrée pour déclencher l'envoi à la place. | |
| 184 | + $('#' + champId).on('keydown', function (e) { | |
| 185 | + if (e.key === 'Enter' && !e.shiftKey) { | |
| 186 | + e.preventDefault(); | |
| 187 | + gre(); | |
| 188 | + if (!$('#' + boutonId).prop('disabled')) { | |
| 189 | + $('#' + champId).closest('form').trigger('submit'); | |
| 190 | + } | |
| 191 | + } | |
| 192 | + }); | |
| 193 | + } | |
| 194 | + | |
| 195 | + brancherValidation('mess', 'publier'); | |
| 196 | + brancherValidation('professionnel', 'envoipro'); | |
| 197 | + brancherValidation('finance', 'okfin'); | |
| 198 | + | |
| 199 | + }); | |
| 200 | + </script> | |
| 201 | + | |
| 202 | +<?php include __DIR__ . '/eliora_cv_widget.php'; ?> | |
| 203 | + | |
| 204 | + <!-- Panneau CV : ouvre le CV choisi dans un panneau à droite de la conversation --> | |
| 205 | + <script type="text/javascript" src="js/script_cv_panneau.js"></script> | |
| 206 | +</body> | |
| 207 | +</html> | |
| 208 | + | |
README.md Ajouté
+4 −0
| … | ||
| 1 | +# SKYNET | |
| 2 | + | |
| 3 | +Skynet est un projet qui pour but de developper une Intelligence artificielle générale | |
| 4 | + | |
script_cv_panneau.js Ajouté
+360 −0
| … | ||
| 1 | +/* ========================================================================== | |
| 2 | + Panneau CV — Eliora | |
| 3 | + Quand l'utilisateur choisit son CV dans un champ <input type="file"> de | |
| 4 | + la page (ici #ecv-fichier, le champ de eliora_cv_widget.php), le fichier | |
| 5 | + s'ouvre dans un panneau à droite de la conversation. | |
| 6 | + Formats affichés : PDF, Word (.docx), texte (.txt), PNG et JPG. | |
| 7 | + L'envoi du CV vers eliora_cv.php n'est pas modifié : ce script se | |
| 8 | + contente d'afficher le fichier, il n'envoie rien. | |
| 9 | + | |
| 10 | + Appel direct possible depuis un autre script : | |
| 11 | + ElioraCV.ouvrir(fichier); // fichier = objet File | |
| 12 | + ElioraCV.fermer(); | |
| 13 | + | |
| 14 | + Styles : css/cv_panneau.css | |
| 15 | + ========================================================================== */ | |
| 16 | +(function () { | |
| 17 | + 'use strict'; | |
| 18 | + | |
| 19 | + var CONFIG = { | |
| 20 | + // Lecteurs chargés seulement au premier CV ouvert. Pour ne pas dépendre | |
| 21 | + // des CDN, copier ces fichiers dans js/ et remplacer les adresses. | |
| 22 | + pdfJs: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js', | |
| 23 | + pdfWorker: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js', | |
| 24 | + mammoth: 'https://cdn.jsdelivr.net/npm/mammoth@1.6.0/mammoth.browser.min.js', // lecteur Word | |
| 25 | + tailleMax: 3 * 1024 * 1024, // même limite que le widget (3 Mo) : au-delà, le panneau ne s'ouvre pas | |
| 26 | + pagesMax: 20, // nombre maximal de pages PDF affichées | |
| 27 | + largeurMin: 360, // largeur minimale du panneau (px) | |
| 28 | + conversationMin: 480, // largeur minimale laissée à la conversation (px) | |
| 29 | + seuilPleinEcran: 900 // sous cette largeur de fenêtre, le panneau prend tout l'écran | |
| 30 | + }; | |
| 31 | + var ZOOMS = [0.5, 0.75, 1, 1.25, 1.5, 2]; | |
| 32 | + var CLE_LARGEUR = 'eliora-cv-largeur'; | |
| 33 | + | |
| 34 | + var panneau, scene, pages, note, nomEl, metaEl, zoomEl, btnMoins, btnPlus, btnFermer, poignee, onglet; | |
| 35 | + var courant = null; // document affiché | |
| 36 | + var indexZoom = 2; | |
| 37 | + var largeurVoulue = null; | |
| 38 | + var scriptsCharges = {}; | |
| 39 | + | |
| 40 | + /* ---------- Construction du panneau ---------- */ | |
| 41 | + function construire() { | |
| 42 | + panneau = document.createElement('div'); | |
| 43 | + panneau.id = 'cv-panneau'; | |
| 44 | + panneau.setAttribute('role', 'complementary'); | |
| 45 | + panneau.setAttribute('aria-label', 'Aperçu du CV'); | |
| 46 | + panneau.innerHTML = | |
| 47 | + '<div id="cv-poignee" role="separator" aria-orientation="vertical" aria-label="Largeur du panneau CV" tabindex="0"></div>' + | |
| 48 | + '<div id="cv-entete">' + | |
| 49 | + '<div id="cv-infos"><span id="cv-nom"></span><span id="cv-meta"></span></div>' + | |
| 50 | + '<div id="cv-outils">' + | |
| 51 | + '<button type="button" class="cv-bouton" id="cv-moins" aria-label="Réduire">−</button>' + | |
| 52 | + '<span id="cv-zoom" aria-live="polite">100 %</span>' + | |
| 53 | + '<button type="button" class="cv-bouton" id="cv-plus" aria-label="Agrandir">+</button>' + | |
| 54 | + '<button type="button" class="cv-bouton" id="cv-fermer" aria-label="Fermer l\'aperçu du CV">×</button>' + | |
| 55 | + '</div>' + | |
| 56 | + '</div>' + | |
| 57 | + '<div id="cv-scene"><p id="cv-note"></p><div id="cv-pages"></div></div>'; | |
| 58 | + document.body.appendChild(panneau); | |
| 59 | + | |
| 60 | + onglet = document.createElement('button'); | |
| 61 | + onglet.type = 'button'; | |
| 62 | + onglet.id = 'cv-onglet'; | |
| 63 | + onglet.innerHTML = | |
| 64 | + '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="18" height="18" aria-hidden="true">' + | |
| 65 | + '<path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"></path><path d="M14 3v5h5M9 13h6M9 17h4"></path></svg>' + | |
| 66 | + 'Voir mon CV'; | |
| 67 | + document.body.appendChild(onglet); | |
| 68 | + | |
| 69 | + scene = document.getElementById('cv-scene'); | |
| 70 | + pages = document.getElementById('cv-pages'); | |
| 71 | + note = document.getElementById('cv-note'); | |
| 72 | + nomEl = document.getElementById('cv-nom'); | |
| 73 | + metaEl = document.getElementById('cv-meta'); | |
| 74 | + zoomEl = document.getElementById('cv-zoom'); | |
| 75 | + btnMoins = document.getElementById('cv-moins'); | |
| 76 | + btnPlus = document.getElementById('cv-plus'); | |
| 77 | + btnFermer = document.getElementById('cv-fermer'); | |
| 78 | + poignee = document.getElementById('cv-poignee'); | |
| 79 | + | |
| 80 | + btnFermer.addEventListener('click', fermer); | |
| 81 | + onglet.addEventListener('click', function () { montrer(); btnFermer.focus(); }); | |
| 82 | + btnMoins.addEventListener('click', function () { if (indexZoom > 0) { indexZoom--; appliquerZoom(); } }); | |
| 83 | + btnPlus.addEventListener('click', function () { if (indexZoom < ZOOMS.length - 1) { indexZoom++; appliquerZoom(); } }); | |
| 84 | + document.addEventListener('keydown', function (e) { | |
| 85 | + if (e.key === 'Escape' && document.body.classList.contains('cv-ouvert')) { fermer(); } | |
| 86 | + }); | |
| 87 | + brancherPoignee(); | |
| 88 | + window.addEventListener('resize', ajusterLargeur); | |
| 89 | + | |
| 90 | + try { | |
| 91 | + var memo = parseInt(localStorage.getItem(CLE_LARGEUR), 10); | |
| 92 | + if (memo > 0) { largeurVoulue = memo; } | |
| 93 | + } catch (e) {} | |
| 94 | + appliquerZoom(); | |
| 95 | + ajusterLargeur(); | |
| 96 | + } | |
| 97 | + | |
| 98 | + /* ---------- Ouverture / fermeture ---------- */ | |
| 99 | + function montrer() { document.body.classList.add('cv-ouvert'); ajusterLargeur(); } | |
| 100 | + function fermer() { | |
| 101 | + if (!document.body.classList.contains('cv-ouvert')) { return; } | |
| 102 | + document.body.classList.remove('cv-ouvert'); | |
| 103 | + if (courant) { onglet.focus(); } | |
| 104 | + } | |
| 105 | + function ecrireNote(texte) { note.textContent = texte || ''; note.style.display = texte ? 'block' : 'none'; } | |
| 106 | + | |
| 107 | + function appliquerZoom() { | |
| 108 | + var z = ZOOMS[indexZoom]; | |
| 109 | + pages.style.setProperty('--cv-zoom', z); | |
| 110 | + zoomEl.textContent = Math.round(z * 100) + ' %'; | |
| 111 | + btnMoins.disabled = indexZoom === 0; | |
| 112 | + btnPlus.disabled = indexZoom === ZOOMS.length - 1; | |
| 113 | + } | |
| 114 | + | |
| 115 | + /* ---------- Largeur du panneau ---------- */ | |
| 116 | + function ajusterLargeur() { | |
| 117 | + var fenetre = window.innerWidth; | |
| 118 | + var plein = fenetre < CONFIG.seuilPleinEcran; | |
| 119 | + document.body.classList.toggle('cv-plein', plein); | |
| 120 | + if (plein) { return; } | |
| 121 | + var voulue = largeurVoulue || Math.round(fenetre * 0.46); | |
| 122 | + var max = Math.max(CONFIG.largeurMin, fenetre - CONFIG.conversationMin); | |
| 123 | + var w = Math.max(CONFIG.largeurMin, Math.min(voulue, max)); | |
| 124 | + document.documentElement.style.setProperty('--cv-w', w + 'px'); | |
| 125 | + poignee.setAttribute('aria-valuenow', Math.round(w / fenetre * 100)); | |
| 126 | + } | |
| 127 | + function memoriserLargeur() { try { localStorage.setItem(CLE_LARGEUR, String(largeurVoulue)); } catch (e) {} } | |
| 128 | + | |
| 129 | + function brancherPoignee() { | |
| 130 | + var actif = false; | |
| 131 | + poignee.addEventListener('pointerdown', function (e) { | |
| 132 | + actif = true; poignee.setPointerCapture(e.pointerId); | |
| 133 | + document.body.classList.add('cv-redim'); e.preventDefault(); | |
| 134 | + }); | |
| 135 | + poignee.addEventListener('pointermove', function (e) { | |
| 136 | + if (!actif) { return; } | |
| 137 | + largeurVoulue = Math.round(window.innerWidth - e.clientX); | |
| 138 | + ajusterLargeur(); | |
| 139 | + }); | |
| 140 | + function fin() { | |
| 141 | + if (!actif) { return; } | |
| 142 | + actif = false; document.body.classList.remove('cv-redim'); memoriserLargeur(); | |
| 143 | + } | |
| 144 | + poignee.addEventListener('pointerup', fin); | |
| 145 | + poignee.addEventListener('pointercancel', fin); | |
| 146 | + poignee.addEventListener('keydown', function (e) { | |
| 147 | + if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') { return; } | |
| 148 | + e.preventDefault(); | |
| 149 | + largeurVoulue = Math.round(panneau.getBoundingClientRect().width + (e.key === 'ArrowLeft' ? 32 : -32)); | |
| 150 | + ajusterLargeur(); memoriserLargeur(); | |
| 151 | + }); | |
| 152 | + } | |
| 153 | + | |
| 154 | + /* ---------- Lecture du fichier ---------- */ | |
| 155 | + function typeDe(fichier) { | |
| 156 | + var n = (fichier.name || '').toLowerCase(); | |
| 157 | + if (fichier.type === 'application/pdf' || /\.pdf$/.test(n)) { return 'pdf'; } | |
| 158 | + if (/\.docx$/.test(n)) { return 'docx'; } | |
| 159 | + if (/\.txt$/.test(n)) { return 'texte'; } | |
| 160 | + if (fichier.type === 'image/png' || fichier.type === 'image/jpeg' || /\.(png|jpe?g)$/.test(n)) { return 'image'; } | |
| 161 | + return null; | |
| 162 | + } | |
| 163 | + function taille(octets) { | |
| 164 | + if (octets < 1024 * 1024) { return Math.max(1, Math.round(octets / 1024)) + ' ko'; } | |
| 165 | + return (octets / (1024 * 1024)).toFixed(1).replace('.', ',') + ' Mo'; | |
| 166 | + } | |
| 167 | + | |
| 168 | + // Charge un script externe une seule fois et renvoie l'objet global qu'il définit. | |
| 169 | + function chargerScript(adresse, nomGlobal) { | |
| 170 | + if (window[nomGlobal]) { return Promise.resolve(window[nomGlobal]); } | |
| 171 | + if (!scriptsCharges[adresse]) { | |
| 172 | + scriptsCharges[adresse] = new Promise(function (ok, echec) { | |
| 173 | + var s = document.createElement('script'); | |
| 174 | + s.src = adresse; | |
| 175 | + s.onload = function () { | |
| 176 | + if (window[nomGlobal]) { ok(window[nomGlobal]); } | |
| 177 | + else { delete scriptsCharges[adresse]; echec(new Error('LECTEUR')); } | |
| 178 | + }; | |
| 179 | + s.onerror = function () { delete scriptsCharges[adresse]; echec(new Error('LECTEUR')); }; | |
| 180 | + document.head.appendChild(s); | |
| 181 | + }); | |
| 182 | + } | |
| 183 | + return scriptsCharges[adresse]; | |
| 184 | + } | |
| 185 | + function chargerPdfJs() { | |
| 186 | + return chargerScript(CONFIG.pdfJs, 'pdfjsLib').then(function (pdfjs) { | |
| 187 | + pdfjs.GlobalWorkerOptions.workerSrc = pdfjs.GlobalWorkerOptions.workerSrc || CONFIG.pdfWorker; | |
| 188 | + return pdfjs; | |
| 189 | + }); | |
| 190 | + } | |
| 191 | + | |
| 192 | + function ajouterPage(doc, noeud) { | |
| 193 | + if (courant !== doc) { return; } // un autre CV a été choisi entre-temps | |
| 194 | + pages.appendChild(noeud); | |
| 195 | + } | |
| 196 | + | |
| 197 | + function afficherPdf(fichier, doc) { | |
| 198 | + return chargerPdfJs().then(function (pdfjs) { | |
| 199 | + return fichier.arrayBuffer().then(function (tampon) { | |
| 200 | + return pdfjs.getDocument({ data: new Uint8Array(tampon), isEvalSupported: false }).promise; | |
| 201 | + }); | |
| 202 | + }).then(function (pdf) { | |
| 203 | + var total = pdf.numPages, affichees = Math.min(total, CONFIG.pagesMax); | |
| 204 | + var dpr = Math.min(window.devicePixelRatio || 1, 2); | |
| 205 | + var cible = Math.min(1800, Math.max(1000, (scene.clientWidth || 700) * dpr * 1.25)); | |
| 206 | + doc.pages = total; doc.tronque = total > affichees; | |
| 207 | + var suite = Promise.resolve(); | |
| 208 | + for (var i = 1; i <= affichees; i++) { | |
| 209 | + (function (numero) { | |
| 210 | + suite = suite.then(function () { | |
| 211 | + if (courant !== doc) { return null; } | |
| 212 | + return pdf.getPage(numero).then(function (page) { | |
| 213 | + var base = page.getViewport({ scale: 1 }); | |
| 214 | + var vue = page.getViewport({ scale: cible / base.width }); | |
| 215 | + var c = document.createElement('canvas'); | |
| 216 | + c.className = 'cv-page'; | |
| 217 | + c.width = Math.round(vue.width); c.height = Math.round(vue.height); | |
| 218 | + c.setAttribute('role', 'img'); | |
| 219 | + c.setAttribute('aria-label', 'Page ' + numero + ' sur ' + total); | |
| 220 | + return page.render({ canvasContext: c.getContext('2d'), viewport: vue }).promise.then(function () { | |
| 221 | + ajouterPage(doc, c); | |
| 222 | + }); | |
| 223 | + }); | |
| 224 | + }); | |
| 225 | + })(i); | |
| 226 | + } | |
| 227 | + return suite; | |
| 228 | + }); | |
| 229 | + } | |
| 230 | + | |
| 231 | + function afficherImage(fichier, doc) { | |
| 232 | + return new Promise(function (ok, echec) { | |
| 233 | + var img = new Image(); | |
| 234 | + img.className = 'cv-page'; | |
| 235 | + img.alt = 'CV : ' + fichier.name; | |
| 236 | + img.onload = function () { doc.pages = 1; ajouterPage(doc, img); ok(); }; | |
| 237 | + img.onerror = function () { echec(new Error('IMAGE')); }; | |
| 238 | + img.src = URL.createObjectURL(fichier); | |
| 239 | + }); | |
| 240 | + } | |
| 241 | + | |
| 242 | + function feuille() { | |
| 243 | + var f = document.createElement('div'); | |
| 244 | + f.className = 'cv-page cv-feuille'; | |
| 245 | + return f; | |
| 246 | + } | |
| 247 | + | |
| 248 | + function afficherTexte(fichier, doc) { | |
| 249 | + return fichier.text().then(function (texte) { | |
| 250 | + var f = feuille(); | |
| 251 | + f.classList.add('cv-texte'); | |
| 252 | + f.textContent = texte; | |
| 253 | + ajouterPage(doc, f); | |
| 254 | + }); | |
| 255 | + } | |
| 256 | + | |
| 257 | + // Le HTML produit à partir du fichier Word n'est pas inséré tel quel : on ne garde | |
| 258 | + // que des balises de mise en forme, sans attribut, sans lien et sans script. | |
| 259 | + var BALISES_OK = { P: 1, H1: 1, H2: 1, H3: 1, H4: 1, H5: 1, H6: 1, UL: 1, OL: 1, LI: 1, STRONG: 1, EM: 1, B: 1, I: 1, U: 1, S: 1, | |
| 260 | + SUP: 1, SUB: 1, BR: 1, TABLE: 1, THEAD: 1, TBODY: 1, TR: 1, TD: 1, TH: 1, IMG: 1, SPAN: 1, DIV: 1 }; | |
| 261 | + function nettoyer(source, cible) { | |
| 262 | + for (var i = 0; i < source.childNodes.length; i++) { | |
| 263 | + var n = source.childNodes[i]; | |
| 264 | + if (n.nodeType === 3) { cible.appendChild(document.createTextNode(n.nodeValue)); continue; } | |
| 265 | + if (n.nodeType !== 1) { continue; } | |
| 266 | + var nom = n.tagName.toUpperCase(); | |
| 267 | + if (nom === 'SCRIPT' || nom === 'STYLE' || nom === 'IFRAME' || nom === 'OBJECT' || nom === 'EMBED') { continue; } | |
| 268 | + if (!BALISES_OK[nom]) { nettoyer(n, cible); continue; } // balise inconnue (lien, etc.) : on garde seulement son texte | |
| 269 | + var copie = document.createElement(nom); | |
| 270 | + if (nom === 'IMG') { | |
| 271 | + var src = n.getAttribute('src') || ''; | |
| 272 | + if (!/^data:image\/(png|jpe?g|gif);base64,/i.test(src)) { continue; } | |
| 273 | + copie.setAttribute('src', src); | |
| 274 | + copie.setAttribute('alt', ''); | |
| 275 | + } | |
| 276 | + if (nom === 'TD' || nom === 'TH') { | |
| 277 | + var c = parseInt(n.getAttribute('colspan'), 10), r = parseInt(n.getAttribute('rowspan'), 10); | |
| 278 | + if (c > 1) { copie.setAttribute('colspan', c); } | |
| 279 | + if (r > 1) { copie.setAttribute('rowspan', r); } | |
| 280 | + } | |
| 281 | + nettoyer(n, copie); | |
| 282 | + cible.appendChild(copie); | |
| 283 | + } | |
| 284 | + } | |
| 285 | + | |
| 286 | + function afficherDocx(fichier, doc) { | |
| 287 | + return chargerScript(CONFIG.mammoth, 'mammoth').then(function (mammoth) { | |
| 288 | + return fichier.arrayBuffer().then(function (tampon) { | |
| 289 | + return mammoth.convertToHtml({ arrayBuffer: tampon }); | |
| 290 | + }); | |
| 291 | + }).then(function (resultat) { | |
| 292 | + var brut = new DOMParser().parseFromString('<div>' + (resultat.value || '') + '</div>', 'text/html'); | |
| 293 | + var f = feuille(); | |
| 294 | + nettoyer(brut.body, f); | |
| 295 | + ajouterPage(doc, f); | |
| 296 | + }); | |
| 297 | + } | |
| 298 | + | |
| 299 | + function messageErreur(err) { | |
| 300 | + if (err && err.message === 'LECTEUR') { return 'Le lecteur de documents ne s\'est pas chargé. Vérifiez votre connexion puis choisissez à nouveau votre CV.'; } | |
| 301 | + if (err && err.name === 'PasswordException') { return 'Ce PDF est protégé par un mot de passe : l\'aperçu n\'est pas possible.'; } | |
| 302 | + return 'L\'aperçu de ce fichier n\'est pas possible : il est illisible ou endommagé.'; | |
| 303 | + } | |
| 304 | + | |
| 305 | + /* ---------- Point d'entrée ---------- */ | |
| 306 | + function ouvrir(fichier) { | |
| 307 | + if (!fichier) { return false; } | |
| 308 | + var type = typeDe(fichier); | |
| 309 | + if (!type) { return false; } // format sans aperçu : on ne touche à rien | |
| 310 | + if (fichier.size > CONFIG.tailleMax) { return false; } // refusé par le widget : pas de panneau | |
| 311 | + | |
| 312 | + var doc = { nom: fichier.name, pages: 0, tronque: false }; | |
| 313 | + courant = doc; | |
| 314 | + document.body.classList.add('cv-charge'); | |
| 315 | + pages.replaceChildren(); | |
| 316 | + nomEl.textContent = fichier.name; | |
| 317 | + metaEl.textContent = taille(fichier.size); | |
| 318 | + scene.scrollTop = 0; scene.scrollLeft = 0; | |
| 319 | + montrer(); | |
| 320 | + | |
| 321 | + ecrireNote('Ouverture du CV…'); | |
| 322 | + | |
| 323 | + var rendu = type === 'pdf' ? afficherPdf(fichier, doc) | |
| 324 | + : type === 'docx' ? afficherDocx(fichier, doc) | |
| 325 | + : type === 'texte' ? afficherTexte(fichier, doc) | |
| 326 | + : afficherImage(fichier, doc); | |
| 327 | + rendu.then(function () { | |
| 328 | + if (courant !== doc) { return; } | |
| 329 | + ecrireNote(''); | |
| 330 | + var detail = type === 'pdf' ? doc.pages + (doc.pages > 1 ? ' pages' : ' page') | |
| 331 | + : type === 'docx' ? 'Word' | |
| 332 | + : type === 'texte' ? 'Texte' : 'Image'; | |
| 333 | + metaEl.textContent = detail + ' · ' + taille(fichier.size) + | |
| 334 | + (doc.tronque ? ' · ' + CONFIG.pagesMax + ' premières pages affichées' : '') + | |
| 335 | + (type === 'docx' ? ' · aperçu simplifié, la mise en page peut différer' : ''); | |
| 336 | + }).catch(function (err) { | |
| 337 | + if (courant !== doc) { return; } | |
| 338 | + pages.replaceChildren(); | |
| 339 | + ecrireNote(messageErreur(err)); | |
| 340 | + }); | |
| 341 | + return true; | |
| 342 | + } | |
| 343 | + | |
| 344 | + function demarrer() { | |
| 345 | + construire(); | |
| 346 | + // Écoute tous les champs « fichier » de la page, y compris ceux ajoutés plus tard. | |
| 347 | + document.addEventListener('change', function (e) { | |
| 348 | + var champ = e.target; | |
| 349 | + if (champ && champ.tagName === 'INPUT' && champ.type === 'file' && champ.files && champ.files[0]) { | |
| 350 | + ouvrir(champ.files[0]); | |
| 351 | + } | |
| 352 | + }, true); | |
| 353 | + } | |
| 354 | + | |
| 355 | + window.ElioraCV = { ouvrir: ouvrir, fermer: fermer }; | |
| 356 | + | |
| 357 | + if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', demarrer); } | |
| 358 | + else { demarrer(); } | |
| 359 | +})(); | |
| 360 | + | |