diff --git a/README.md b/README.md index d68b9d5..056ee58 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ La première version se contente de récupérer et parser des données présente Les données trouvées sont affichées dans un tableau. En option, des colonnes peuvent être indiquées par filtrer les données. Pour parser les données CSV, [Papa Parse](https://www.papaparse.com/) est utilisé. -Cette première version est fonctionnelle, même s'il reste à revoir le classement par ordre alphabétique des filtres pouvant poser un souci si des colonnes contiennent des nombres, des dates, etc. Toujours pour les filtres, il faudra prévoir le cas où plusieurs valeurs sont disponibles dans une même colonne (Exemple : liste de mots-clés) qui seront donc à extraire. +Cette première version est fonctionnelle, même s'il reste à revoir le classement par ordre alphabétique des filtres pouvant poser un souci si des colonnes contiennent des nombres, des dates, etc. Ensuite ajouter la possibilité de classement sur certaines colonnes et la pagination, le tout en options, le développeur final devant pouvoir adapter le module à son besoin. Et puis s'attaquer aux autres sources/formats possibles pour les données... diff --git a/package.json b/package.json index fe56dc9..3458abf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "freedatas2html", - "version": "0.3.1", + "version": "0.3.2", "description": "Visualization of data from various sources (CSV, API, HTML...) with filters, classification, pagination, etc.", "main": "index.js", "scripts": { diff --git a/public/datas/elements-chimiques+tags.csv b/public/datas/elements-chimiques+tags.csv new file mode 100644 index 0000000..45dfdee --- /dev/null +++ b/public/datas/elements-chimiques+tags.csv @@ -0,0 +1,119 @@ +Z (numéro atomique),Élément,Symbole,Famille,Abondance des éléments dans la croûte terrestre (μg/k),Étiquettes +1,Hydrogène,H,Non-métal,> 100000,Exemple1 +2,Hélium,He,Gaz noble,> 1 et < 100 000,Exemple2 +3,Lithium,Li,Métal alcalin,> 1 et < 100 000,Exemple2|Exemple1 +4,Béryllium,Be,Métal alcalino-terreux,> 1 et < 100 000,Exemple3 +5,Bore,B,Métalloïde,> 1 et < 100 000,Exemple5 +6,Carbone,C,Non-métal,> 100000,Exemple5|Exemple2 +7,Azote,N,Non-métal,> 1 et < 100 000,Exemple4 +8,Oxygène,O,Non-métal,> 100000,Exemple1 +9,Fluor,F,Halogène,> 100000,Exemple2|Exemple1 +10,Néon,Ne,Gaz noble,> 1 et < 100 000,Exemple2|Exemple2 +11,Sodium,Na,Métal alcalin,> 100000,Exemple2|Exemple3 +12,Magnésium,Mg,Métal alcalino-terreux,> 100000,Exemple2|Exemple4 +13,Aluminium,Al,Métal pauvre,> 100000,Exemple1 +14,Silicium,Si,Métalloïde,> 100000,Exemple2 +15,Phosphore,P,Non-métal,> 100000,Exemple2|Exemple0 +16,Soufre,S,Non-métal,> 100000,Exemple5|Exemple2 +17,Chlore,Cl,Halogène,> 100000,Exemple5|Exemple3 +18,Argon,Ar,Gaz noble,> 1 et < 100 000,Exemple5|Exemple4 +19,Potassium,K,Métal alcalin,> 100000,Exemple5|Exemple5 +20,Calcium,Ca,Métal alcalino-terreux,> 100000,Exemple5|Exemple6 +21,Scandium,Sc,Métal de transition,> 1 et < 100 000,Exemple5|Exemple7 +22,Titane,Ti,Métal de transition,> 100000,Exemple4 +23,Vanadium,V,Métal de transition,> 100000,Exemple1 +24,Chrome,Cr,Métal de transition,> 100000,Exemple4 +25,Manganèse,Mn,Métal de transition,> 100000,Exemple3 +26,Fer,Fe,Métal de transition,> 100000,Exemple2 +27,Cobalt,Co,Métal de transition,> 1 et < 100 000,Exemple1 +28,Nickel,Ni,Métal de transition,> 1 et < 100 000,Exemple2 +29,Cuivre,Cu,Métal de transition,> 1 et < 100 000,Exemple0|Exemple9|Exemple1 +30,Zinc,Zn,Métal pauvre,> 1 et < 100 000,Exemple0|Exemple9|Exemple2 +31,Gallium,Ga,Métal pauvre,> 1 et < 100 000,Exemple0|Exemple9|Exemple3 +32,Germanium,Ge,Métalloïde,> 1 et < 100 000,Exemple9|Exemple8 +33,Arsenic,As,Métalloïde,> 1 et < 100 000,Exemple9|Exemple7 +34,Sélénium,Se,Non-métal,> 1 et < 100 000,Exemple9|Exemple6 +35,Brome,Br,Halogène,> 1 et < 100 000,Exemple9|Exemple5 +36,Krypton,Kr,gaz rare,≤ 1,Exemple1 +37,Rubidium,Rb,Métal alcalin,> 1 et < 100 000,Exemple2 +38,Strontium,Sr,Métal alcalino-terreux,> 100000,Exemple2|Exemple1 +39,Yttrium,Y,Métal de transition,> 1 et < 100 000,Exemple3 +40,Zirconium,Zr,Métal de transition,> 100000,Exemple5 +41,Niobium,Nb,Métal de transition,> 1 et < 100 000,Exemple5|Exemple2 +42,Molybdène,Mo,Métal de transition,> 1 et < 100 000,Exemple4 +43,Technétium,Tc,Métal de transition,Traces ,Exemple1 +44,Ruthénium,Ru,Métal de transition,≤ 1,Exemple2|Exemple1 +45,Rhodium,Rh,Métal de transition,≤ 1,Exemple2|Exemple2 +46,Palladium,Pd,Métal de transition,> 1 et < 100 000,Exemple2|Exemple3 +47,Argent,Ag,Métal de transition,> 1 et < 100 000,Exemple2|Exemple4 +48,Cadmium,Cd,Métal pauvre,> 1 et < 100 000,Exemple1 +49,Indium,In,Métal pauvre,> 1 et < 100 000,Exemple2 +50,Étain,Sn,Métal pauvre,> 1 et < 100 000,Exemple2|Exemple0 +51,Antimoine,Sb,Métalloïde,> 1 et < 100 000,Exemple5|Exemple2 +52,Tellure,Te,Métalloïde,≤ 1,Exemple5|Exemple3 +53,Iode,I,Halogène,> 1 et < 100 000,Exemple5|Exemple4 +54,Xénon,Xe,gaz rare,≤ 1,Exemple5|Exemple5 +55,Césium,Cs,Métal alcalin,> 1 et < 100 000,Exemple5|Exemple6 +56,Baryum,Ba,Métal alcalino-terreux,> 100000,Exemple5|Exemple7 +57,Lanthane,La,Lanthanide,> 1 et < 100 000,Exemple4 +58,Cérium,Ce,Lanthanide,> 1 et < 100 000,Exemple1 +59,Praséodyme,Pr,Lanthanide,> 1 et < 100 000,Exemple4 +60,Néodyme,Nd,Lanthanide,> 1 et < 100 000,Exemple3 +61,Prométhium,Pm,Lanthanide,Traces ,Exemple2 +62,Samarium,Sm,Lanthanide,> 1 et < 100 000,Exemple1 +63,Europium,Eu,Lanthanide,> 1 et < 100 000,Exemple2 +64,Gadolinium,Gd,Lanthanide,> 1 et < 100 000,Exemple0|Exemple9|Exemple1 +65,Terbium,Tb,Lanthanide,> 1 et < 100 000,Exemple0|Exemple9|Exemple2 +66,Dysprosium,Dy,Lanthanide,> 1 et < 100 000,Exemple0|Exemple9|Exemple3 +67,Holmium,Ho,Lanthanide,> 1 et < 100 000,Exemple9|Exemple8 +68,Erbium,Er,Lanthanide,> 1 et < 100 000,Exemple9|Exemple7 +69,Thulium,Tm,Lanthanide,> 1 et < 100 000,Exemple9|Exemple6 +70,Ytterbium,Yb,Lanthanide,> 1 et < 100 000,Exemple9|Exemple5 +71,Lutécium,Lu,Lanthanide,> 1 et < 100 000,Exemple2 +72,Hafnium,Hf,Métal de transition,> 1 et < 100 000,Exemple0|Exemple9|Exemple1 +73,Tantale,Ta,Métal de transition,> 1 et < 100 000,Exemple0|Exemple9|Exemple2 +74,Tungstène,W,Métal de transition,> 1 et < 100 000,Exemple0|Exemple9|Exemple3 +75,Rhénium,Re,Métal de transition,≤ 1,Exemple9|Exemple8 +76,Osmium,Os,Métal de transition,> 1 et < 100 000,Exemple9|Exemple7 +77,Iridium,Ir,Métal de transition,≤ 1,Exemple9|Exemple6 +78,Platine,Pt,Métal de transition,> 1 et < 100 000,Exemple9|Exemple5 +79,Or,Au,Métal de transition,> 1 et < 100 000,Exemple2 +80,Mercure,Hg,Métal pauvre,> 1 et < 100 000,Exemple0|Exemple9|Exemple1 +81,Thallium,Tl,Métal pauvre,> 1 et < 100 000,Exemple0|Exemple9|Exemple2 +82,Plomb,Pb,Métal pauvre,> 1 et < 100 000,Exemple0|Exemple9|Exemple3 +83,Bismuth,Bi,Métal pauvre,> 1 et < 100 000,Exemple9|Exemple8 +84,Polonium,Po,Métal pauvre,≤ 1,Exemple9|Exemple7 +85,Astate,At,Métalloïde,Traces ,Exemple9|Exemple6 +86,Radon,Rn,Gaz noble,≤ 1,Exemple9|Exemple5 +87,Francium,Fr,Métal alcalin,Traces ,Exemple2 +88,Radium,Ra,Métal alcalino-terreux,≤ 1,Exemple0|Exemple9|Exemple1 +89,Actinium,Ac,Actinide,≤ 1,Exemple0|Exemple9|Exemple2 +90,Thorium,Th,Actinide,> 1 et < 100 000,Exemple0|Exemple9|Exemple3 +91,Protactinium,Pa,Actinide,≤ 1,Exemple9|Exemple8 +92,Uranium,U,Actinide,> 1 et < 100 000,Exemple9|Exemple7 +93,Neptunium,Np,Actinide,Traces ,Exemple9|Exemple6 +94,Plutonium,Pu,Actinide,Traces ,Exemple9|Exemple5 +95,Américium,Am,Actinide,Inexistant,Exemple2 +96,Curium,Cm,Actinide,Inexistant,Exemple0|Exemple9|Exemple1 +97,Berkélium,Bk,Actinide,Inexistant,Exemple0|Exemple9|Exemple2 +98,Californium,Cf,Actinide,Inexistant,Exemple0|Exemple9|Exemple3 +99,Einsteinium,Es,Actinide,Inexistant,Exemple9|Exemple8 +100,Fermium,Fm,Actinide,Inexistant,Exemple9|Exemple7 +101,Mendélévium,Md,Actinide,Inexistant,Exemple9|Exemple6 +102,Nobélium,No,Actinide,Inexistant,Exemple9|Exemple5 +103,Lawrencium,Lr,Actinide,Inexistant,Exemple2 +104,Rutherfordium,Rf,Métal de transition,Inexistant,Exemple0|Exemple9|Exemple1 +105,Dubnium,Db,Métal de transition,Inexistant,Exemple0|Exemple9|Exemple2 +106,Seaborgium,Sg,Métal de transition,Inexistant,Exemple0|Exemple9|Exemple3 +107,Bohrium,Bh,Métal de transition,Inexistant,Exemple9|Exemple8 +108,Hassium,Hs,Métal de transition,Inexistant,Exemple9|Exemple7 +109,Meitnérium,Mt,Indéfinie,Inexistant,Exemple9|Exemple6 +110,Darmstadtium,Ds,Indéfinie,Inexistant,Exemple9|Exemple5 +111,Roentgenium,Rg,Indéfinie,Inexistant,Exemple2 +112,Copernicium,Cn,Métal de transition,Inexistant,Exemple0|Exemple9|Exemple1 +113,Nihonium,Nh,Indéfinie,Inexistant,Exemple0|Exemple9|Exemple2 +114,Flérovium,Fl,Indéfinie,Inexistant,Exemple0|Exemple9|Exemple3 +115,Moscovium,Mc,Indéfinie,Inexistant,Exemple9|Exemple8 +116,Livermorium,Lv,Indéfinie,Inexistant,Exemple9|Exemple7 +117,Tennesse,Ts,Indéfinie,Inexistant,Exemple9|Exemple6 +118,Oganesson,Og,Indéfinie,Inexistant,Exemple10 \ No newline at end of file diff --git a/src/freeDatas2HTML.ts b/src/freeDatas2HTML.ts index b218d0d..268b6c6 100644 --- a/src/freeDatas2HTML.ts +++ b/src/freeDatas2HTML.ts @@ -50,6 +50,8 @@ export class freeDatas2HTML else { selectionElts[i].eltDOM=checkContainerExist; + if(selectionElts[i].separator !== undefined && selectionElts[i].separator === "") + selectionElts[i].separator=undefined; this._datasSelectors.push(selectionElts[i]); } } @@ -115,17 +117,16 @@ export class freeDatas2HTML else { let converter=this; - // Affichage initial des données du fichier + // Affichage initial de toutes les données du fichier this.datasHTML=this.createDatasHTML(this.parseMeta!.fields, this.parseDatas); this._datasViewElt.eltDOM.innerHTML=this.datasHTML; - // Si demandé, création des listes permettant de filter les données if(this._datasSelectors.length > 0) { - // Les colonnes devant servir de filtre existent-elles dans le fichier ? let selectorsHTML : string [] = []; for(let i in this._datasSelectors) { + // Les colonnes devant servir de filtre existent-elles vraiment dans le fichier ? if(this._datasSelectors[i].datasFieldNb > (this.parseMeta!.fields.length-1)) throw new Error(errors.selectorFieldNotFound); else @@ -133,14 +134,28 @@ export class freeDatas2HTML let values=[], colName=this.parseMeta!.fields[this._datasSelectors[i].datasFieldNb]; for (let row in this.parseDatas) { - if(values.indexOf(this.parseDatas[row][colName].trim()) === -1) - values.push(this.parseDatas[row][colName].trim()); - // Des espaces gauche pourraient fausser le classement alphabétique. - // Donc réutiliser le trim() lorsque l'on filtre l'affichage des données. + if(this._datasSelectors[i].separator === undefined) + { + let checkedValue=this.parseDatas[row][colName].trim(); + // On ne garde pas les données vides (prévoir possible en option pour pouvoir sélectionner les données non classées sur cette colonne ?) + if(checkedValue !== "" && values.indexOf(checkedValue) === -1) + values.push(checkedValue); + } + else + { + let checkedValues=this.parseDatas[row][colName].split(this._datasSelectors[i].separator as string); + for(let i in checkedValues) + { + + let checkedValue=checkedValues[i].trim(); + if(checkedValue !== "" && values.indexOf(checkedValue) === -1) + values.push(checkedValue); + } + } } if(values.length > 0) { - values.sort(); // à revoir, car gère mal la casse, les nombres, etc. + values.sort(); this._datasSelectors[i].name=colName; this._datasSelectors[i].values=values; selectorsHTML[i]="', selector2HTML: '', + selector1HTMLWithTags: '', datasHTMLFor1Select: '
Z (numéro atomique)ÉlémentSymboleFamilleAbondance des éléments dans la croûte terrestre (μg/k)
109MeitnériumMtIndéfinieInexistant
110DarmstadtiumDsIndéfinieInexistant
111RoentgeniumRgIndéfinieInexistant
113NihoniumNhIndéfinieInexistant
114FléroviumFlIndéfinieInexistant
115MoscoviumMcIndéfinieInexistant
116LivermoriumLvIndéfinieInexistant
117TennesseTsIndéfinieInexistant
118OganessonOgIndéfinieInexistant
', datasHTMLFor2Select:'
Z (numéro atomique)ÉlémentSymboleFamilleAbondance des éléments dans la croûte terrestre (μg/k)
2HéliumHeGaz noble> 1 et < 100 000
10NéonNeGaz noble> 1 et < 100 000
18ArgonArGaz noble> 1 et < 100 000
', datasHTMLFor2SelectNone:'
Z (numéro atomique)ÉlémentSymboleFamilleAbondance des éléments dans la croûte terrestre (μg/k)
', + datasHTMLForSelectTagsField:'
Z (numéro atomique)ÉlémentSymboleFamilleAbondance des éléments dans la croûte terrestre (μg/k)Étiquettes
118OganessonOgIndéfinieInexistantExemple10
', } \ No newline at end of file diff --git a/tests/freeDatas2HTMLSpec.ts b/tests/freeDatas2HTMLSpec.ts index f913bec..6a5ef57 100644 --- a/tests/freeDatas2HTMLSpec.ts +++ b/tests/freeDatas2HTMLSpec.ts @@ -51,6 +51,12 @@ describe("freeDatas2HTML", () => expect(converter.datasSelectors[0].id).toEqual("selector1"); }); + it("Si un séparateur vide est fourni pour un sélecteur, il doit être ignoré.", () => + { + converter.datasSelectors=[{ datasFieldNb:2, id:"selector2", separator:"" }]; + expect(converter.datasSelectors[0].separator).toBeUndefined(); + }); + it("Doit accepter tous les sélecteurs si leurs informations sont valides.", () => { converter.datasSelectors=[{ datasFieldNb:0, id:"selector1" },{ datasFieldNb:3, id:"selector2" }]; @@ -158,35 +164,41 @@ describe("freeDatas2HTML", () => it("Doit générer une erreur si au moins un des numéros de colonne fournis pour les sélecteurs ne correspond pas à une des colonne du fichier.", async () => { - converter.datasSelectors=[{ datasFieldNb:0, id:"selector1"},{ datasFieldNb:5, id:"selector2"}];// il y a bien 5 champs, mais la numérotation commence à 0 :-) + converter.datasSelectors=[{ datasFieldNb:0, id:"selector1"},{ datasFieldNb:5, id:"selector2"}]; // il y a bien 5 champs, mais la numérotation commence à 0 :-) await expectAsync(converter.run()).toBeRejectedWith(new Error(errors.selectorFieldNotFound)); }); - it("Ne doit pas pas générer d'erreur si tous les numéros de colonne des sélecteurs correspondent pas à une des colonne du fichier.", async () => + it("Ne doit pas pas générer d'erreur si tous les numéros de colonne des sélecteurs correspondent à une des colonnes du fichier.", async () => { converter.datasSelectors=[{ datasFieldNb:3, id:"selector1"},{ datasFieldNb:4, id:"selector2"}]; await expectAsync(converter.run()).not.toBeRejected(); }); - it("Pour chaque sélecteur demandé, doit générer un élement listant les valeurs distinctes du fichier, classées dans le bon ordre.", async () => { converter.datasSelectors=[{ datasFieldNb:3, id:"selector1"},{ datasFieldNb:4, id:"selector2"}]; await converter.run(); expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTML); expect(document.getElementById("selector2").innerHTML).toEqual(fixtures.selector2HTML); }); - - it("Le choix d'une option dans un des sélecteurs doit modifier le contenu du tableau pour ne garder que les données correspondantes ou les afficher toutes si sélection 0.", async () => + + it("Si des valeurs vides sont présentes dans une colonne utilisée pour un sélecteur, elles doivent être ignorées.", async () => + { + converter.datasSourceUrl="http://localhost:9876/datas/datas1-emtyinfield.csv"; + converter.datasSelectors=[{ datasFieldNb:3, id:"selector1"}]; + await converter.run(); + expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTML); + }); + + it("Le choix d'une option dans un des sélecteurs doit modifier le contenu du tableau pour ne garder que les données correspondantes et les afficher toutes si sélection 0.", async () => { converter.datasSelectors=[{ datasFieldNb:3, id:"selector1"},{ datasFieldNb:4, id:"selector2"}]; await converter.run(); - let selectElement = document.getElementById("freeDatas2HTMLSelector0") as HTMLInputElement; selectElement.value="4"; selectElement.dispatchEvent(new Event('change')); let txtDatasViewsElt=document.getElementById("datas").innerHTML; expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLFor1Select); - selectElement.value="0"; selectElement.dispatchEvent(new Event('change')); txtDatasViewsElt=document.getElementById("datas").innerHTML; @@ -197,7 +209,6 @@ describe("freeDatas2HTML", () => { converter.datasSelectors=[{ datasFieldNb:3, id:"selector1"},{ datasFieldNb:4, id:"selector2"}]; await converter.run(); - let selectElement = document.getElementById("freeDatas2HTMLSelector0") as HTMLInputElement; selectElement.value="2"; selectElement = document.getElementById("freeDatas2HTMLSelector1") as HTMLInputElement; @@ -205,12 +216,32 @@ describe("freeDatas2HTML", () => selectElement.dispatchEvent(new Event('change')); let txtDatasViewsElt=document.getElementById("datas").innerHTML; expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLFor2Select); - selectElement.value="4"; selectElement.dispatchEvent(new Event('change')); txtDatasViewsElt=document.getElementById("datas").innerHTML; expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLFor2SelectNone); }); + + // Cas particulier des champs pouvant contenir plusieurs valeurs : + it("Si un séparateur est fourni pour un sélecteur, les valeurs distinctes extraites de cette colonne doivent le prendre en compte.", async () => + { + converter.datasSourceUrl="http://localhost:9876/datas/datas1+tagsfield.csv"; + converter.datasSelectors=[{ datasFieldNb:5, id:"selector1", separator:"|"}]; + await converter.run(); + expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTMLWithTags); + }); + + it("Si un séparateur est fourni pour un sélecteur, lorsque qu'une valeur y est sélectionnée, toutes les lignes de données la contenant doivent être affichées.", async () => + { + converter.datasSourceUrl="http://localhost:9876/datas/datas1+tagsfield.csv"; + converter.datasSelectors=[{ datasFieldNb:5, id:"selector1", separator:"|"}]; + await converter.run(); + let selectElement=document.getElementById("freeDatas2HTMLSelector0") as HTMLInputElement; + selectElement.value="3"; // = "Exemple10" retournant une seule ligne + selectElement.dispatchEvent(new Event('change')); + let txtDatasViewsElt=document.getElementById("datas").innerHTML; + expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLForSelectTagsField); + }); }); }); \ No newline at end of file