User Tools

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
lxplan [2026/01/25 18:11] – [js version] ssm2017lxplan [2026/01/27 12:47] (current) – [js version] ssm2017
Line 1924: Line 1924:
     <meta charset="UTF-8">     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Lecteur XML avec XPath</title+    <title>Lxplan lib builder</title>
-    <script src="https://cdn.jsdelivr.net/npm/xmldom@0.6.0/xmldom.js"></script> +
-    <script src="https://cdn.jsdelivr.net/npm/xpath@0.0.3/xpath.js"></script>+
     <style>     <style>
         body {         body {
Line 1951: Line 1949:
         button:hover {         button:hover {
             background-color: #0056b3;             background-color: #0056b3;
 +        }
 +
 +        .test-result>span {
 +            font-weight: bold;
 +            padding: 5px;
 +        }
 +
 +        .valid {
 +            color: white;
 +            background-color: green;
 +        }
 +
 +        .invalid {
 +            color: white;
 +            background-color: red;
 +        }
 +
 +        .no-answer {
 +            color: black;
 +            background-color: white;
 +        }
 +
 +        .container {
 +            border: 1px solid black;
 +            border-radius: 5px;
 +            margin: 5px;
 +            padding: 10px;
         }         }
     </style>     </style>
Line 1957: Line 1982:
 <body> <body>
     <h1>Lxplan lib builder</h1>     <h1>Lxplan lib builder</h1>
-    <div>+    <div class="container">
         <details>         <details>
-            <summary>Cliquer pour la doc</summary>+            <summary>Cliquer içi pour lire la doc</summary>
             <p>Pour créer une librairie, il faut : <br />             <p>Pour créer une librairie, il faut : <br />
             <ul>             <ul>
Line 1974: Line 1999:
         </details>         </details>
     </div>     </div>
-    <div>+    <div class="container">
         <h2>Charger le fichier lxxplot</h2>         <h2>Charger le fichier lxxplot</h2>
         <p>Sélectionnez un fichier llxplot sur votre appareil :</p>         <p>Sélectionnez un fichier llxplot sur votre appareil :</p>
-        <input type="file" id="fileInput" accept=".lxxplot" onclick="resetResults()" />+        <input type="file" id="fileInput" accept=".lxxplot" onclick="resetChecks()" />
     </div>     </div>
-    <div> +    <div class="container"
-        <h2>Tests</h2> +        <h2>Tester le fichier lxxplot</h2> 
-        <div>Le fichier est il un lxxplot ? : <span id="isLxxplot">Sans avis</span></div> +        <div>Le fichier est il un lxxplot ? : <span id="isLxxplot" class="test-result">...</span></div> 
-        <div>Le fichier possede t il une shape sur le premier layer ? :<span id="hasShape">Sans avis</span></div> +        <div>Le fichier possede t il une shape sur le premier layer ? :<span id="hasShape
-        <div>La shape, commence t elle par un groupe ? :<span id="hasGroup">Sans avis</span></div>+                class="test-result">...</span></div> 
 +        <div>La shape, commence t elle par un groupe ? :<span id="hasGroup" class="test-result">...</span></div>
         <button onclick="loadFile()">Tester le fichier</button>         <button onclick="loadFile()">Tester le fichier</button>
     </div>     </div>
-    <div id="data_fields"> +    <div id="dataFieldsclass="container" hidden
-        <h2>Données</h2>+        <h2>Données de la librairie</h2>
         <div class="form-section">         <div class="form-section">
-            <select id="dataType"> 
-                <option value="">Sélectionnez un type d'appareil</option> 
-            </select> 
- 
             <div id="mandatoryFields">             <div id="mandatoryFields">
 +                <h3>Champs obligatoires</h3>
                 <div>                 <div>
                     <label for="name">Type</label>                     <label for="name">Type</label>
                     <input type="text" id="name" name="name" required />                     <input type="text" id="name" name="name" required />
                 </div>                 </div>
-                <div><label for="fname">Full Name</label>+                <div> 
 +                    <label for="fname">Full Name</label>
                     <input type="text" id="fname" name="fname" required />                     <input type="text" id="fname" name="fname" required />
                 </div>                 </div>
-                <div><label for="id">Id</label>+                <div> 
 +                    <label for="id">Id</label>
                     <input type="text" id="id" name="id" required />                     <input type="text" id="id" name="id" required />
 +                </div>
 +                <div>
 +                    <label for="dataType">Type d'appareil</label>
 +                    <select id="dataType">
 +                        <option value="">Sélectionner un type d'appareil</option>
 +                    </select>
                 </div>                 </div>
             </div>             </div>
-            <details+            <div id="optionalFields"
-                <summary+                <h3>Champs optionnels</h3> 
-                    Cliquer pour editer les champs optionnels +                <details
-                </summary> +                    <summary> 
-                <div id="dynamicFields"></div> +                        Cliquer içi pour editer les champs optionnels 
-            </details> +                    </summary> 
- +                    <div id="dynamicFields">Selectionner d'abord un type d'appareil</div> 
-            <button id="saveButton" onclick="buildOutput()">Sauvegarder</button>+                </details> 
 +            </div> 
 +            <button id="saveButton" onclick="buildOutput()">Créer la librairie</button>
         </div>         </div>
     </div>     </div>
  
     <script>     <script>
-        // Charger le fichier XML sélectionné+        // declaration des variables
         var xmlInputContent = "";         var xmlInputContent = "";
         var xmlOutputContent = "";         var xmlOutputContent = "";
Line 2024: Line 2057:
         var hasShape = false;         var hasShape = false;
         var hasGroup = false;         var hasGroup = false;
 +        var filledOptionalFields = undefined;
 +        var filledFields = [];
         var isLxxplotDiv = document.getElementById("isLxxplot");         var isLxxplotDiv = document.getElementById("isLxxplot");
         var hasShapeDiv = document.getElementById("hasShape");         var hasShapeDiv = document.getElementById("hasShape");
         var hasGroupDiv = document.getElementById("hasGroup");         var hasGroupDiv = document.getElementById("hasGroup");
 +        var dataFields = document.getElementById("dataFields");
         var dataTypeSelect = document.getElementById('dataType');         var dataTypeSelect = document.getElementById('dataType');
         var dynamicFields = document.getElementById('dynamicFields');         var dynamicFields = document.getElementById('dynamicFields');
  
-        document.addEventListener('DOMContentLoaded', () => { 
-            fillSelectOptions(); 
-        }); 
         // Tableau des options de la liste de sélection         // Tableau des options de la liste de sélection
         const selectOptions = [         const selectOptions = [
-            { id: "ers;eko", label: "ERS", fields: "sid;have;lamp;watts;frame;beam;cd;abm;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" }, +            { id: "ers", label: "ERS", fields: "sid;have;lamp;watts;frame;beam;cd;abm;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" }, 
-            { id: "zers;Zoom Leko", label: "Zoom Leko / ERS", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" }, +            { id: "zers", label: "Zoom Leko / ERS", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" }, 
-            { id: "fres;Fresnel", label: "Fresnel / PC", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },+            { id: "fres", label: "Fresnel / PC", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },
             { id: "par", label: "PAR", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },             { id: "par", label: "PAR", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },
             { id: "fl", label: "Flood", fields: "sid;have;lamp;watts;frame;beam;cd;abm;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },             { id: "fl", label: "Flood", fields: "sid;have;lamp;watts;frame;beam;cd;abm;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },
Line 2051: Line 2084:
             { id: "led7", label: "Color Mixing Rectangular Beam", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;note;scroll;dmode;mixtype;d_adj_x;d_adj_y;d_adj_z" },             { id: "led7", label: "Color Mixing Rectangular Beam", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;note;scroll;dmode;mixtype;d_adj_x;d_adj_y;d_adj_z" },
             { id: "led7s", label: "Color Mixing Striplight", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;cpf;lpc;dbl;note;scroll;dmode;mixtype;d_adj_x;d_adj_y;d_adj_z" },             { id: "led7s", label: "Color Mixing Striplight", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;cpf;lpc;dbl;note;scroll;dmode;mixtype;d_adj_x;d_adj_y;d_adj_z" },
-            { id: "cmers;Color Mixing Leko", label: "Color Mixing Leko / ERS", fields: "sid;have;lamp;watts;frame;beam;cd;abm;wt;note;scroll;dmode;mixtype;d_mk;d_adj_x;d_adj_y;d_adj_z" }, +            { id: "cmers", label: "Color Mixing Leko / ERS", fields: "sid;have;lamp;watts;frame;beam;cd;abm;wt;note;scroll;dmode;mixtype;d_mk;d_adj_x;d_adj_y;d_adj_z" }, 
-            { id: "cmzers;Color Mixing Zoom ERS", label: "Color Mixing Zoom ERS", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;scroll;dmode;mixtype;d_mk;d_adj_x;d_adj_y;d_adj_z" },+            { id: "cmzers", label: "Color Mixing Zoom ERS", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;scroll;dmode;mixtype;d_mk;d_adj_x;d_adj_y;d_adj_z" },
             { id: "cmscroll", label: "Color Mixing DMX Device", fields: "sid;have;note;scroll;dmode;mixtype;d_mk" },             { id: "cmscroll", label: "Color Mixing DMX Device", fields: "sid;have;note;scroll;dmode;mixtype;d_mk" },
             { id: "netnode", label: "Network Device", fields: "sid;have;note;dmode" },             { id: "netnode", label: "Network Device", fields: "sid;have;note;dmode" },
Line 2096: Line 2129:
         ];         ];
  
 +        // reinitialise les resultats du test de fichier
 +        function resetChecks() {
 +            let content = '<span class="no-answer">Sans avis</span>';
 +            isLxxplotDiv.innerHTML = content;
 +            hasShapeDiv.innerHTML = content;
 +            hasGroupDiv.innerHTML = content;
 +            dataFields.hidden = true;
 +        }
 +
 +        // action quand le document est bien chargé
 +        document.addEventListener('DOMContentLoaded', () => {
 +            resetChecks();
 +            fillSelectOptions();
 +        });
 +
 +        // Remplit la liste déroulante de type d'appareil
 +        function fillSelectOptions() {
 +            dataTypeSelect.innerHTML = '<option value="">Sélectionner un type d\'appareil</option>';
 +            selectOptions.forEach((option) => {
 +                const optElement = document.createElement("option");
 +                optElement.value = option.id;
 +                optElement.textContent = option.label;
 +                dataTypeSelect.appendChild(optElement);
 +            });
 +        }
 +
 +        // ecoute si le type d'appareil est changé
 +        dataTypeSelect.addEventListener("change", () => {
 +            const selectedOptionId = dataTypeSelect.value;
 +            displayDynamicFields(selectedOptionId);
 +        });
 +
 +        // Affiche les champs optionnels en fonction du type d'appareil sélectionné
 +        function displayDynamicFields(selectedOptionId) {
 +            dynamicFields.innerHTML = "";// Efface les champs précédents
 +
 +            // Trouve l'option sélectionnée
 +            const selectedOption = selectOptions.find((option) => option.id === selectedOptionId);
 +
 +            if (!selectedOption || !selectedOption.fields) return;
 +
 +            // Récupère les IDs des champs à afficher
 +            const fieldIds = selectedOption.fields.split(";");
 +
 +            // Affiche chaque champ
 +            fieldIds.forEach((fieldId) => {
 +
 +                const field = availableFields.find((f) => f.id === fieldId);
 +
 +                if (field) {
 +                    const fieldDiv = document.createElement("div");
 +                    fieldDiv.innerHTML = `
 +        <label for="${field.id}">${field.label}:</label>
 +        <input type="${field.type}" id="${field.id}" name="${field.id}" />
 +      `;
 +                    dynamicFields.appendChild(fieldDiv);
 +                }
 +            });
 +        }
 +
 +        // charge le fichier lxxplot
         function loadFile() {         function loadFile() {
             const fileInput = document.getElementById('fileInput');             const fileInput = document.getElementById('fileInput');
Line 2107: Line 2201:
             reader.onload = function (e) {             reader.onload = function (e) {
                 xmlInputContent = e.target.result;                 xmlInputContent = e.target.result;
-                runChecks(); +                dataFields.hidden = !runChecks();
-                /*if (runChecks()) { +
-                    buildOutput(); +
-                }*/+
             };             };
             reader.readAsText(file);             reader.readAsText(file);
         }         }
  
-        function resetResults() { +        // verifie le contenu du fichier lxxplot
-            isLxxplotDiv.textContent = "Sans avis"; +
-            hasShapeDiv.textContent = "Sans avis"; +
-            hasGroupDiv.textContent = "Sans avis"; +
-        } +
         function runChecks() {         function runChecks() {
             isLxxplot = checkIfValidPath("/lxplot", 'isLxxplot');             isLxxplot = checkIfValidPath("/lxplot", 'isLxxplot');
             hasShape = checkIfValidPath("/lxplot/layers/layer/shape", 'hasShape');             hasShape = checkIfValidPath("/lxplot/layers/layer/shape", 'hasShape');
 +            if (hasShape) {
 +                getShape();
 +            }
             hasGroup = checkIfValidPath("/lxplot/layers/layer/shape/class[text() = 'LXGroup']", 'hasGroup');             hasGroup = checkIfValidPath("/lxplot/layers/layer/shape/class[text() = 'LXGroup']", 'hasGroup');
             return (isLxxplot && hasShape && hasGroup);             return (isLxxplot && hasShape && hasGroup);
         }         }
  
-        function buildOutput() { +        // petit utilitaire pour tester le contenu du fichier lxxplot
-            console.log("todo"); +
-            buildXmlOutput(); +
-            //generateTextFile(xmlInputContent); +
-        } +
- +
-        function buildXmlOutput() { +
-    // 1. Create a new XML document +
-    const xml = new DOMParser().parseFromString('<key></key>', 'application/xml'); +
-    const root = xml.documentElement; +
- +
-    // 2. Create and append elements +
-    const kentryElement = xml.createElement('kentry'); +
-    const kindElement = xml.createElement("kind"); +
-    kindElement.textContent = "ers"; +
-    const nameElement = xml.createElement("name"); +
-    const fnameElement = xml.createElement("fname"); +
-    const idElement = xml.createElement("id"); +
-    const customElement = xml.createElement("custom"); +
-    const symbolElement = xml.createElement("symbol"); +
-    const groupElement = xml.createElement("group"); +
-    const shapeElement = xml.createElement("shape"); +
-    shapeElement.textContent = shape; +
- +
-    groupElement.appendChild(shapeElement); +
-    symbolElement.appendChild(groupElement); +
-    customElement.appendChild(symbolElement); +
-    kentryElement.appendChild(kindElement); +
-    kentryElement.appendChild(nameElement); +
-    kentryElement.appendChild(fnameElement); +
-    kentryElement.appendChild(idElement); +
-    kentryElement.appendChild(symbolElement); +
-    root.appendChild(kentryElement); +
- +
-    // 3. Serialize to string +
-    const xmlString = new XMLSerializer().serializeToString(xml); +
- +
-    // 4. Create a Blob and URL for download +
-    const blob = new Blob([xmlString], { type: 'application/xml' }); +
-    const url = URL.createObjectURL(blob); +
- +
-    // 5. Trigger download +
-    const a = document.createElement('a'); +
-    a.href = url; +
-    a.download = 'users.xml'; +
-    a.click(); +
- +
-    // Clean up +
-    URL.revokeObjectURL(url); +
-}    +
- +
         function checkIfValidPath(xpathQuery, resultDiv) {         function checkIfValidPath(xpathQuery, resultDiv) {
             resultDiv = document.getElementById(resultDiv);             resultDiv = document.getElementById(resultDiv);
-            resultDiv.textContent = parseXml(xpathQuery).status ? "oui": "non"; +            let status = parseXml(xpathQuery).status; 
-            console.log(xpathQuery, parseXml(xpathQuery).data); +            resultDiv.innerHTML = status ? '<span class="valid">oui</span>' '<span class="invalid">non</span>'
-            shape = parseXml("/lxplot/layers/layer/shape").data;+            return status;
         }         }
  
 +        // petit utilitaire permettant de tester le xml du fichier lxxplot
         function parseXml(xpathQuery) {         function parseXml(xpathQuery) {
             try {             try {
Line 2211: Line 2250:
                 // Afficher le résultat                 // Afficher le résultat
                 if (result.length > 0) {                 if (result.length > 0) {
-                    return {"status":true, "data": result};+                    return { "status": true, "data": result };
                 } else {                 } else {
-                    return {"status":false, "data": "Not found"};+                    return { "status": false, "data": "Not found" };
                 }                 }
             } catch (e) {             } catch (e) {
-                //resultDiv.textContent = "Erreur : " + e.message; +                console.error("error parsing xml", e.message); 
-                console.error("error parsing xml",e.message); +                return { "status": false, "data": "Error " + e.message };
-                return {"status":false, "data": "Error"+ e.message};+
             }             }
         }         }
  
-        function generateTextFile(content, filename = "my_lib.lxkey") { +        // reuperer la shape depuis le fichier lxxplot 
-            /*const blob = new Blob([content]{ type: "text/xml;charset=utf-8}); +        function getShape() { 
-            const link = document.createElement("a"); +            try { 
-            link.href = URL.createObjectURL(blob); +                /Parser le XML 
-            link.download = filename; +                const parser = new DOMParser(); 
-            document.body.appendChild(link); +                const xmlDoc = parser.parseFromString(xmlInputContent, "text/xml"); 
-            link.click()+ 
-            document.body.removeChild(link); +                // Exécuter la requête XPath 
-            URL.revokeObjectURL(link.href);*/ +                const xpathResult = document.evaluate( 
-            const blob = new Blob([content], type'application/xml;charset=utf-8' })+                    "/lxplot/layers/layer/shape", 
-const url = URL.createObjectURL(blob); +                    xmlDoc, 
-const a = document.createElement('a'); +                    null, 
-a.href = url; +                    XPathResult.FIRST_ORDERED_NODE_TYPE, 
-a.download = 'my_lib.lxkey'; +                    null 
-a.click(); +                ); 
-URL.revokeObjectURL(url);   + 
 +                shape = xpathResult.singleNodeValue
 +            } catch (e{ 
 +                console.error("error parsing xml", e.message); 
 +                return "status"false, "data": "Error : " + e.message }; 
 +            }
         }         }
  
-        // Remplit la liste déroulante avec les options +        // action quand on appuie sur le bouton "creer la librairie" 
-        function fillSelectOptions() { +        function buildOutput() { 
-            //const dataTypeSelect = document.getElementById("dataType")+            if (checkFilledFields()) { 
-            dataTypeSelect.innerHTML = '<option value="">Sélectionnez un type d\'appareil</option>'; +                buildXmlOutput(); 
-            selectOptions.forEach((option=> +            }
-                const optElement = document.createElement("option"); +
-                optElement.value = option.id; +
-                optElement.textContent = option.label; +
-                dataTypeSelect.appendChild(optElement); +
-            });+
         }         }
  
-        dataTypeSelect.addEventListener("change", () => +        // verifier que les champs soient bien remplis 
-            const selectedOptionId dataTypeSelect.value+        function checkFilledFields() { 
-            displayDynamicFields(selectedOptionId); +            filledFields []
-        })+            getFilledChildren('mandatoryFields'); 
-        // Affiche les champs dynamiques en fonction de l'option sélectionnée +            if (Object.keys(filledFields).length < 3 || dataTypeSelect.value === '') { 
-        function displayDynamicFields(selectedOptionId{ +                alert("Les 4 champs obligatoires doivent être remplis.")
-            dynamicFields.innerHTML = "";// Efface les champs précédents+                return false; 
 +            
 +            getFilledChildren('dynamicFields'); 
 +            return true; 
 +        }
  
-            // Trouve l'option sélectionnée +        function getFilledChildren(id) { 
-            const selectedOption selectOptions.find((option) => option.id === selectedOptionId);+            // recupere les champs 
 +            const divElement document.getElementById(id)
 +            const inputNodes divElement.getElementsByTagName('input');
  
-            if (!selectedOption || !selectedOption.fieldsreturn;+            // teste les champs un par un 
 +            for (let i = 0; i < inputNodes.length; i++) { 
 +                if (inputNodes[i].value.trim() !== '') { 
 +                    filledFields.push({ "id": inputNodes[i].id, "value": inputNodes[i].value }); 
 +                } 
 +            } 
 +        }
  
-            // Récupère les IDs des champs à afficher +        // fabrique le fichier de sortie et l'envoie a l'utilisateur 
-            const fieldIds selectedOption.fields.split(";");+        function buildXmlOutput() { 
 +            // creation du document xml 
 +            const xmlDoc new DOMParser().parseFromString('<key></key>', 'application/xml')
 +            const root = xmlDoc.documentElement;
  
-            // Affiche chaque champ +            // creation des elements basiques 
-            fieldIds.forEach((fieldId) => {+            const kentryElement = xmlDoc.createElement('kentry'); 
 +            const customElement = xmlDoc.createElement("custom")
 +            const symbolElement xmlDoc.createElement("symbol"); 
 +            const groupElement = xmlDoc.createElement("group"); 
 +            const kindElement = xmlDoc.createElement("kind"); 
 +            kindElement.textContent = dataTypeSelect.value;
  
-                const field = availableFields.find((f=> f.id === fieldId);+            // ajout des elements basiques dans l'arbre xml 
 +            groupElement.appendChild(shape); 
 +            symbolElement.appendChild(groupElement)
 +            customElement.appendChild(symbolElement); 
 +            kentryElement.appendChild(kindElement);
  
-                if (field) { +            // ajout de chaque champ rempli 
-                    const fieldDiv document.createElement("div"); +            filledFields.forEach((item=> 
-                    fieldDiv.innerHTML +                const newItem xmlDoc.createElement(item.id); 
-        <label for="${field.id}">${field.label}:</label> +                newItem.textContent item.value
-        <input type="${field.type}" id="${field.id}" name="${field.id}" /> +                kentryElement.appendChild(newItem);
-      `+
-                    dynamicFields.appendChild(fieldDiv); +
-                }+
             });             });
-        } 
  
 +            kentryElement.appendChild(customElement);
 +            root.appendChild(kentryElement);
 +
 +            // conversion en chaine de characteres
 +            const xmlString = "<?xml version='1.0' encoding='utf-8'?>\n" + new XMLSerializer().serializeToString(xmlDoc);
 +            console.log(xmlString);
 +
 +            // creation fichier
 +            const blob = new Blob([xmlString], { type: 'application/xml;charset=utf-8' });
 +            const url = URL.createObjectURL(blob);
 +
 +            // envoi du fichier
 +            const a = document.createElement('a');
 +            a.href = url;
 +            a.download = 'mylib.lxkey';
 +            a.click();
 +
 +            // nettoyage
 +            URL.revokeObjectURL(url);
 +        }
     </script>     </script>
 </body> </body>

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also, you acknowledge that you have read and understand our Privacy Policy. If you do not agree, please leave the website.

More information