Ajout possibilité de fournir des fonctions spécifiques pour classer les données de certaines colonnes.
This commit is contained in:
parent
75c9efc3b1
commit
66ea27b0fb
@ -18,9 +18,9 @@ De même l'idée est de rester libre du rendu des données en n'imposant pas de
|
|||||||
|
|
||||||
La première version se contente de récupérer et parser des données présentes dans un fichier CSV via un appel Ajax.
|
La première version se contente de récupérer et parser des données présentes dans un fichier CSV via un appel Ajax.
|
||||||
Les données trouvées sont affichées dans un tableau. En option, des colonnes peuvent être indiquées par filtrer les données et/ou les classer.
|
Les données trouvées sont affichées dans un tableau. En option, des colonnes peuvent être indiquées par filtrer les données et/ou les classer.
|
||||||
|
Il est possible de fournir des fonctions spécifiques pour classer les données de certaines colonnes.
|
||||||
|
|
||||||
Il reste à ajouter :
|
Il reste à ajouter :
|
||||||
- la possibilité de fournir des fonctions spécifiques pour classer les données de certaines colonnes.
|
|
||||||
- la possibilité de paginer les données.
|
- la possibilité de paginer les données.
|
||||||
- la possibilité d'utiliser des sources/formats différents qu'un fichier CSV pour extraire les données.
|
- la possibilité d'utiliser des sources/formats différents qu'un fichier CSV pour extraire les données.
|
||||||
- la possibilité de spécifier un code HTML autre qu'un tableau pour lister les données.
|
- la possibilité de spécifier un code HTML autre qu'un tableau pour lister les données.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "freedatas2html",
|
"name": "freedatas2html",
|
||||||
"version": "0.3.5",
|
"version": "0.3.6",
|
||||||
"description": "Visualization of data from various sources (CSV, API, HTML...) with filters, classification, pagination, etc.",
|
"description": "Visualization of data from various sources (CSV, API, HTML...) with filters, classification, pagination, etc.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -7,7 +7,20 @@ const initialise = async () =>
|
|||||||
let converter=new freeDatas2HTML();
|
let converter=new freeDatas2HTML();
|
||||||
converter.datasViewElt={ id:"datas" };
|
converter.datasViewElt={ id:"datas" };
|
||||||
converter.datasSelectors=[{ datasFieldNb:3, id:"filtre1"}, { datasFieldNb:4, id:"filtre2"},{ datasFieldNb:5, id:"filtre3", separator:"," }];
|
converter.datasSelectors=[{ datasFieldNb:3, id:"filtre1"}, { datasFieldNb:4, id:"filtre2"},{ datasFieldNb:5, id:"filtre3", separator:"," }];
|
||||||
converter.datasSortingColumns=[{ datasFieldNb:0 }, { datasFieldNb:1 },{ datasFieldNb:2 }];
|
const mySort = (a: any, b: any, order: "asc"|"desc" = "asc") =>
|
||||||
|
{
|
||||||
|
const values = [ "> 100000", "> 1 et < 100 000", "≤ 1", "Traces", "Inexistant"];
|
||||||
|
if(order === "desc")
|
||||||
|
values.reverse();
|
||||||
|
if(values.indexOf(a) > values.indexOf(b))
|
||||||
|
return -1;
|
||||||
|
else if(values.indexOf(a) < values.indexOf(b))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
converter.datasSortingColumns=[{ datasFieldNb:0 }, { datasFieldNb:1 },{ datasFieldNb:2 }, { datasFieldNb:4 }];
|
||||||
|
converter.datasSortingFunctions= [{ datasFieldNb:4, sort:mySort}];
|
||||||
converter.datasSourceUrl="http://localhost:8080/datas/elements-chimiques.csv";
|
converter.datasSourceUrl="http://localhost:8080/datas/elements-chimiques.csv";
|
||||||
await converter.run();
|
await converter.run();
|
||||||
}
|
}
|
||||||
|
@ -8,18 +8,20 @@ import { domElement, selectors, sortingColumns, sortingFunctions } from "./free
|
|||||||
export class freeDatas2HTML
|
export class freeDatas2HTML
|
||||||
{
|
{
|
||||||
private _datasViewElt: domElement = { id:"", eltDOM:undefined };
|
private _datasViewElt: domElement = { id:"", eltDOM:undefined };
|
||||||
private _datasSourceUrl: string = "";
|
public datasHTML: string = "";
|
||||||
|
// Revoir car tous les attributs suivants sont liés aux colonnes/fields des données (créer une classe ?)
|
||||||
private _datasSelectors: selectors[] = [];
|
private _datasSelectors: selectors[] = [];
|
||||||
private _datasSortingColumns: sortingColumns[] = [];
|
private _datasSortingColumns: sortingColumns[] = [];
|
||||||
private _datasSortedColumn: sortingColumns|undefined;
|
private _datasSortedColumn: sortingColumns|undefined;
|
||||||
|
private _datasSortingFunctions: sortingFunctions[] = [];
|
||||||
|
// Parseur fichier :
|
||||||
|
private _datasSourceUrl: string = "";
|
||||||
public parseMeta: papaParseMeta|undefined = undefined;
|
public parseMeta: papaParseMeta|undefined = undefined;
|
||||||
public parseDatas: papaParseDatas[] = [];
|
public parseDatas: papaParseDatas[] = [];
|
||||||
public parseErrors: papaParseErrors[] = [];
|
public parseErrors: papaParseErrors[] = [];
|
||||||
public datasHTML: string = "";
|
|
||||||
public stopIfParseErrors: boolean = false;
|
public stopIfParseErrors: boolean = false;
|
||||||
|
|
||||||
public static isNaturalNumber(nb)
|
public static isNaturalNumber(nb: number)
|
||||||
{
|
{
|
||||||
return (Number.isInteger(nb) === false || nb < 0) ? false : true;
|
return (Number.isInteger(nb) === false || nb < 0) ? false : true;
|
||||||
}
|
}
|
||||||
@ -84,12 +86,36 @@ export class freeDatas2HTML
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get datasSortingColumns() : sortingColumns[]
|
get datasSortingColumns() : sortingColumns[]
|
||||||
{
|
{
|
||||||
return this._datasSortingColumns;
|
return this._datasSortingColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attention : une fonction de classement peut aussi bien servir à une colonne triable, qu'à une colonne servant à filtrer les données
|
||||||
|
set datasSortingFunctions(sortingFunctions: sortingFunctions[])
|
||||||
|
{
|
||||||
|
this._datasSortingFunctions=[];
|
||||||
|
for(let i = 0; i < sortingFunctions.length; i++)
|
||||||
|
{
|
||||||
|
if(freeDatas2HTML.isNaturalNumber(sortingFunctions[i].datasFieldNb) === false)
|
||||||
|
console.error(errors.needNaturalNumber);
|
||||||
|
else
|
||||||
|
this._datasSortingFunctions.push(sortingFunctions[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retourne la fonction spécifique de classement associée à une colonne
|
||||||
|
public getSortingFunctionForField(datasFieldNb: number) : sortingFunctions|undefined
|
||||||
|
{
|
||||||
|
for(let i in this._datasSortingFunctions)
|
||||||
|
{
|
||||||
|
if(this._datasSortingFunctions[i].datasFieldNb === datasFieldNb)
|
||||||
|
return this._datasSortingFunctions[i];
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
public async parse(): Promise<any>
|
public async parse(): Promise<any>
|
||||||
{
|
{
|
||||||
const converter=this;
|
const converter=this;
|
||||||
@ -172,7 +198,6 @@ export class freeDatas2HTML
|
|||||||
let checkedValues=this.parseDatas[row][colName].split(this._datasSelectors[i].separator as string);
|
let checkedValues=this.parseDatas[row][colName].split(this._datasSelectors[i].separator as string);
|
||||||
for(let i in checkedValues)
|
for(let i in checkedValues)
|
||||||
{
|
{
|
||||||
|
|
||||||
let checkedValue=checkedValues[i].trim();
|
let checkedValue=checkedValues[i].trim();
|
||||||
if(checkedValue !== "" && values.indexOf(checkedValue) === -1)
|
if(checkedValue !== "" && values.indexOf(checkedValue) === -1)
|
||||||
values.push(checkedValue);
|
values.push(checkedValue);
|
||||||
@ -181,7 +206,10 @@ export class freeDatas2HTML
|
|||||||
}
|
}
|
||||||
if(values.length > 0)
|
if(values.length > 0)
|
||||||
{
|
{
|
||||||
values.sort(compare());
|
if(this.getSortingFunctionForField(this._datasSelectors[i].datasFieldNb) !== undefined)
|
||||||
|
values.sort(this.getSortingFunctionForField(this._datasSelectors[i].datasFieldNb)!.sort);
|
||||||
|
else
|
||||||
|
values.sort(compare());
|
||||||
this._datasSelectors[i].name=colName;
|
this._datasSelectors[i].name=colName;
|
||||||
this._datasSelectors[i].values=values;
|
this._datasSelectors[i].values=values;
|
||||||
selectorsHTML[i]="<label for='freeDatas2HTMLSelector"+i+"'>"+colName+" : </label><select name='freeDatas2HTMLSelector"+i+"' id='freeDatas2HTMLSelector"+i+"'><option value='0'>----</option>";
|
selectorsHTML[i]="<label for='freeDatas2HTMLSelector"+i+"'>"+colName+" : </label><select name='freeDatas2HTMLSelector"+i+"' id='freeDatas2HTMLSelector"+i+"'><option value='0'>----</option>";
|
||||||
@ -220,7 +248,7 @@ export class freeDatas2HTML
|
|||||||
{
|
{
|
||||||
const converter=this;
|
const converter=this;
|
||||||
this._datasViewElt.eltDOM.innerHTML=this.datasHTML;
|
this._datasViewElt.eltDOM.innerHTML=this.datasHTML;
|
||||||
// Ici car il faut que la tableau soit déjà dans le DOM pour écouter les clics
|
// Ici, car il faut que le tableau soit déjà dans le DOM pour "mettre sous écoute" les clics
|
||||||
if(this._datasSortingColumns.length > 0)
|
if(this._datasSortingColumns.length > 0)
|
||||||
{
|
{
|
||||||
let getTableTh=document.querySelectorAll("table th");
|
let getTableTh=document.querySelectorAll("table th");
|
||||||
@ -233,7 +261,7 @@ export class freeDatas2HTML
|
|||||||
htmlContent="<a href='#freeDatas2HTMLSorting"+datasFieldNb+"' id='freeDatas2HTMLSorting"+datasFieldNb+"'>"+htmlContent+"</a>";
|
htmlContent="<a href='#freeDatas2HTMLSorting"+datasFieldNb+"' id='freeDatas2HTMLSorting"+datasFieldNb+"'>"+htmlContent+"</a>";
|
||||||
getTableTh[datasFieldNb].innerHTML=htmlContent;
|
getTableTh[datasFieldNb].innerHTML=htmlContent;
|
||||||
let sortingElement=document.getElementById("freeDatas2HTMLSorting"+datasFieldNb);
|
let sortingElement=document.getElementById("freeDatas2HTMLSorting"+datasFieldNb);
|
||||||
sortingElement!.addEventListener('click', function(e)
|
sortingElement!.addEventListener("click", function(e)
|
||||||
{
|
{
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let order=converter.datasSortingColumns[i].order ;
|
let order=converter.datasSortingColumns[i].order ;
|
||||||
@ -268,7 +296,14 @@ export class freeDatas2HTML
|
|||||||
{
|
{
|
||||||
const col=fields[this._datasSortedColumn.datasFieldNb];
|
const col=fields[this._datasSortedColumn.datasFieldNb];
|
||||||
const colOrder=this._datasSortedColumn.order;
|
const colOrder=this._datasSortedColumn.order;
|
||||||
datas.sort( (a, b) => compare( {order: colOrder} )(a[col], b[col]));
|
// Une fonction spécifique de classement a-t-elle été définie ?
|
||||||
|
if(this.getSortingFunctionForField(this._datasSortedColumn.datasFieldNb) !== undefined)
|
||||||
|
{
|
||||||
|
let myFunction=this.getSortingFunctionForField(this._datasSortedColumn.datasFieldNb);
|
||||||
|
datas.sort( (a, b) => { return myFunction!.sort(a[col], b[col], colOrder); });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
datas.sort( (a, b) => compare( {order: colOrder} )(a[col], b[col]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Création du tableau de données :
|
// Création du tableau de données :
|
||||||
|
@ -14,4 +14,9 @@ export interface sortingColumns
|
|||||||
{
|
{
|
||||||
datasFieldNb: number;
|
datasFieldNb: number;
|
||||||
order?: "asc"|"desc"|undefined;
|
order?: "asc"|"desc"|undefined;
|
||||||
|
}
|
||||||
|
export interface sortingFunctions
|
||||||
|
{
|
||||||
|
datasFieldNb: number;
|
||||||
|
sort(a: any,b: any, order?: "asc"|"desc"): number; // cf. https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
|
||||||
}
|
}
|
@ -41,7 +41,6 @@ describe("freeDatas2HTML", () =>
|
|||||||
expect(converter.datasSelectors[0].id).toEqual("selector2");
|
expect(converter.datasSelectors[0].id).toEqual("selector2");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Utile pour tester les valeurs fournies pour les numéros de colonne
|
|
||||||
it("Doit retourner un booléen indiquant si un nombre est naturel ou non.", () =>
|
it("Doit retourner un booléen indiquant si un nombre est naturel ou non.", () =>
|
||||||
{
|
{
|
||||||
expect(freeDatas2HTML.isNaturalNumber(-1)).toBeFalse();
|
expect(freeDatas2HTML.isNaturalNumber(-1)).toBeFalse();
|
||||||
@ -66,6 +65,23 @@ describe("freeDatas2HTML", () =>
|
|||||||
{
|
{
|
||||||
expect(() => { return converter.datasSourceUrl=" "; }).toThrowError(errors.needUrl);
|
expect(() => { return converter.datasSourceUrl=" "; }).toThrowError(errors.needUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Doit me retourner la fonction associée à une colonne, de manière à ce qu'elle soit utilisable pour comparer deux valeurs.", () =>
|
||||||
|
{
|
||||||
|
// Fonction volontairement basique, car ce n'est pas la fonction que l'on teste ici, mais le fait que l'on puisse l'utiliser !
|
||||||
|
const simpleSort = (a: any, b: any) =>
|
||||||
|
{
|
||||||
|
if(a < b)
|
||||||
|
return 1;
|
||||||
|
else if(a > b)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
converter.datasSortingFunctions=[{ datasFieldNb:0, sort:simpleSort }];
|
||||||
|
expect(converter.getSortingFunctionForField(0)).toBeDefined();
|
||||||
|
expect([7,9,3,5].sort(converter.getSortingFunctionForField(0).sort)).toEqual([9,7,5,3]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Parsage du fichier et création du tableau de données", () =>
|
describe("Parsage du fichier et création du tableau de données", () =>
|
||||||
|
Loading…
Reference in New Issue
Block a user