Ajout fonctionnalité pagination des données.
This commit is contained in:
parent
66ea27b0fb
commit
a4b7e7af4a
@ -19,13 +19,15 @@ 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 est possible de fournir des fonctions spécifiques pour classer les données de certaines colonnes.
|
||||||
|
Il est également possible de paginer les résultats.
|
||||||
|
|
||||||
|
Le tout **en options**, le développeur final devant pouvoir adapter le module à son besoin.
|
||||||
|
|
||||||
Il reste à ajouter :
|
Il reste à ajouter :
|
||||||
- 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/récupérer les données.
|
||||||
|
|
||||||
Le tout en options, le développeur final devant pouvoir adapter le module à son besoin.
|
Mais avant toute chose, il me faut maintenant **remanier le code, le script approchant les 500 lignes** !
|
||||||
|
|
||||||
Bref, il reste beaucoup de choses à faire !
|
Bref, il reste beaucoup de choses à faire !
|
||||||
|
|
||||||
|
@ -11,15 +11,23 @@
|
|||||||
</head>
|
</head>
|
||||||
<body class="paper container">
|
<body class="paper container">
|
||||||
<h1>freeDatas2HTML</h1>
|
<h1>freeDatas2HTML</h1>
|
||||||
<p id="filtre1"></p>
|
|
||||||
<p id="filtre2"></p>
|
<div class="row">
|
||||||
<p id="filtre3"></p>
|
<div id="filtre1" class="sm-12 md-6 lg-4 col"></div>
|
||||||
|
<div id="filtre2" class="sm-12 md-6 lg-4 col"></div>
|
||||||
|
<div id="filtre3" class="sm-12 md-6 lg-4 col"></div>
|
||||||
|
<div id="paginationOptions" class="col-12 col"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<article id="datas">
|
<article id="datas">
|
||||||
<p>Si tout se passe bien, ce texte sera remplacé par un tableau de données extraites du fichier csv.</p>
|
<p>Si tout se passe bien, ce texte sera remplacé par un tableau de données extraites du fichier csv.</p>
|
||||||
</article>
|
</article>
|
||||||
|
<p id="pages"></p>
|
||||||
<aside><p>Les données affichées viennent d'<a href="datas/elements-chimiques.csv">un fichier CSV</a> reprenant une partie des informations trouvées <a href="https://fr.wikipedia.org/wiki/%C3%89l%C3%A9ment_chimique#Caract%C3%A9ristiques_des_diff%C3%A9rents_%C3%A9l%C3%A9ments" target="_blank">sur Wikipédia</a>.</p>
|
<aside><p>Les données affichées viennent d'<a href="datas/elements-chimiques.csv">un fichier CSV</a> reprenant une partie des informations trouvées <a href="https://fr.wikipedia.org/wiki/%C3%89l%C3%A9ment_chimique#Caract%C3%A9ristiques_des_diff%C3%A9rents_%C3%A9l%C3%A9ments" target="_blank">sur Wikipédia</a>.</p>
|
||||||
<p>La dernière colonne permet de montrer la possibilité d'<b>extraire des données d'une colonne ayant plusieurs valeurs par ligne</b>, ici séparées par une virgule.<br>Ce choix de la virgule comme séparateur ne pose pas de problème, tant le fichier CSV est correctement conçu.<br>Elle ne doit par contre pas être présente dans les expressions à extraire de la colonne, sachant que l'on peut désigner n'importe quel autre caractère séparateur.</p>
|
<p>La dernière colonne permet de montrer la possibilité d'<b>extraire des données d'une colonne ayant plusieurs valeurs par ligne</b>, ici séparées par une virgule.<br>Ce choix de la virgule comme séparateur ne pose pas de problème, tant le fichier CSV est correctement conçu.<br>Elle ne doit par contre pas être présente dans les expressions à extraire de la colonne, sachant que l'on peut désigner n'importe quel autre caractère séparateur.</p>
|
||||||
<p>Toujours en option, certaines peuvent être désignées comme permettant de classer les données : un 1ᵉʳ clic lance un classement par ordre croissant, le 2ᵉ pour ordre décroissant et ainsi de suite.</p>
|
<p>Toujours en option, certaines peuvent être désignées comme permettant de classer les données : un 1ᵉʳ clic lance un classement par ordre croissant, le 2ᵉ pour ordre décroissant et ainsi de suite.</p>
|
||||||
|
<p>Enfin, une dernière option permet de <b>paginer les résultat</b>.</p>
|
||||||
<p>Design basé sur <a href="https://www.getpapercss.com" target="_blank">PaperCSS</a></p></aside>
|
<p>Design basé sur <a href="https://www.getpapercss.com" target="_blank">PaperCSS</a></p></aside>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -4,6 +4,9 @@ module.exports =
|
|||||||
elementNotFound : "Aucun élément HTML n'a été trouvé ayant comme \"id\" : ",
|
elementNotFound : "Aucun élément HTML n'a été trouvé ayant comme \"id\" : ",
|
||||||
needDatasElt: "Merci de fournir un id valide pour l'élément où afficher les données.",
|
needDatasElt: "Merci de fournir un id valide pour l'élément où afficher les données.",
|
||||||
needNaturalNumber: "Merci de fournir un nombre entier supérieur ou égal à zéro pour désigner chaque colonne.",
|
needNaturalNumber: "Merci de fournir un nombre entier supérieur ou égal à zéro pour désigner chaque colonne.",
|
||||||
|
needPagesSelectorElt: "Merci de fournir l'id de l'élément où afficher le sélecteur de pages.",
|
||||||
|
needPaginationByDefaultBeInOptions: "La valeur de pagination par défaut doit faire partie des options proposées.",
|
||||||
|
needPositiveInteger: "Merci de fournir un nombre entier supérieur à zéro pour désigner chaque option de pagination.",
|
||||||
needUrl: "Merci de fournir une url valide pour le fichier CSV à parser.",
|
needUrl: "Merci de fournir une url valide pour le fichier CSV à parser.",
|
||||||
parserFail: "La lecture des données du fichier a échoué.",
|
parserFail: "La lecture des données du fichier a échoué.",
|
||||||
selectorFieldNotFound: "Au moins une des colonnes devant servir à filtrer les données n'existe pas dans le fichier.",
|
selectorFieldNotFound: "Au moins une des colonnes devant servir à filtrer les données n'existe pas dans le fichier.",
|
||||||
|
@ -7,6 +7,7 @@ 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:"," }];
|
||||||
|
|
||||||
const mySort = (a: any, b: any, order: "asc"|"desc" = "asc") =>
|
const mySort = (a: any, b: any, order: "asc"|"desc" = "asc") =>
|
||||||
{
|
{
|
||||||
const values = [ "> 100000", "> 1 et < 100 000", "≤ 1", "Traces", "Inexistant"];
|
const values = [ "> 100000", "> 1 et < 100 000", "≤ 1", "Traces", "Inexistant"];
|
||||||
@ -21,6 +22,21 @@ const initialise = async () =>
|
|||||||
};
|
};
|
||||||
converter.datasSortingColumns=[{ datasFieldNb:0 }, { datasFieldNb:1 },{ datasFieldNb:2 }, { datasFieldNb:4 }];
|
converter.datasSortingColumns=[{ datasFieldNb:0 }, { datasFieldNb:1 },{ datasFieldNb:2 }, { datasFieldNb:4 }];
|
||||||
converter.datasSortingFunctions= [{ datasFieldNb:4, sort:mySort}];
|
converter.datasSortingFunctions= [{ datasFieldNb:4, sort:mySort}];
|
||||||
|
converter.pagination=
|
||||||
|
{
|
||||||
|
selectedValue:10,
|
||||||
|
options:
|
||||||
|
{
|
||||||
|
displayElement : { id:"paginationOptions" },
|
||||||
|
values: [10,20,50,500],
|
||||||
|
name: "Choix de pagination :"
|
||||||
|
},
|
||||||
|
pages:
|
||||||
|
{
|
||||||
|
displayElement : { id:"pages" },
|
||||||
|
name: "Page à afficher :"
|
||||||
|
}
|
||||||
|
}
|
||||||
converter.datasSourceUrl="http://localhost:8080/datas/elements-chimiques.csv";
|
converter.datasSourceUrl="http://localhost:8080/datas/elements-chimiques.csv";
|
||||||
await converter.run();
|
await converter.run();
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ const errors = require("./errors.js");
|
|||||||
const { compare }= require('natural-orderby');
|
const { compare }= require('natural-orderby');
|
||||||
|
|
||||||
import { papaParseDatas, papaParseErrors, papaParseMeta } from "./papaParseInterfaces";
|
import { papaParseDatas, papaParseErrors, papaParseMeta } from "./papaParseInterfaces";
|
||||||
import { domElement, selectors, sortingColumns, sortingFunctions } from "./freeDatas2HTMLInterfaces";
|
import { domElement, pagination, selectors, sortingColumns, sortingFunctions } from "./freeDatas2HTMLInterfaces";
|
||||||
|
|
||||||
export class freeDatas2HTML
|
export class freeDatas2HTML
|
||||||
{
|
{
|
||||||
@ -20,6 +20,13 @@ export class freeDatas2HTML
|
|||||||
public parseDatas: papaParseDatas[] = [];
|
public parseDatas: papaParseDatas[] = [];
|
||||||
public parseErrors: papaParseErrors[] = [];
|
public parseErrors: papaParseErrors[] = [];
|
||||||
public stopIfParseErrors: boolean = false;
|
public stopIfParseErrors: boolean = false;
|
||||||
|
// Pagination :
|
||||||
|
private _pagination: pagination|undefined;
|
||||||
|
|
||||||
|
public static isPositiveInteger(nb: number)
|
||||||
|
{
|
||||||
|
return (Number.isInteger(nb) === false || nb <= 0) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
public static isNaturalNumber(nb: number)
|
public static isNaturalNumber(nb: number)
|
||||||
{
|
{
|
||||||
@ -50,7 +57,7 @@ export class freeDatas2HTML
|
|||||||
{
|
{
|
||||||
this._datasSelectors=[];
|
this._datasSelectors=[];
|
||||||
let checkContainerExist: HTMLElement|null;
|
let checkContainerExist: HTMLElement|null;
|
||||||
for(let i = 0; i < selectionElts.length; i++)
|
for(let i in selectionElts)
|
||||||
{
|
{
|
||||||
checkContainerExist=document.getElementById(selectionElts[i].id);
|
checkContainerExist=document.getElementById(selectionElts[i].id);
|
||||||
if(checkContainerExist === null)
|
if(checkContainerExist === null)
|
||||||
@ -116,6 +123,69 @@ export class freeDatas2HTML
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Long et tortueux ! créer une classe dédiée ?
|
||||||
|
set pagination(config: pagination)
|
||||||
|
{
|
||||||
|
this._pagination={};
|
||||||
|
// Si une valeur par défaut est fournie ou des valeurs en option, un id valide doit être aussi fourni pour recueillir le sélecteur de pages :
|
||||||
|
if(config.selectedValue !== undefined || config.options !== undefined)
|
||||||
|
{
|
||||||
|
if(config.pages === undefined)
|
||||||
|
throw new Error(errors.needPagesSelectorElt);
|
||||||
|
let checkContainerExist=document.getElementById(config.pages.displayElement.id);
|
||||||
|
if(checkContainerExist === null)
|
||||||
|
throw new Error(errors.elementNotFound+config.pages.displayElement.id);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.pagination.pages=
|
||||||
|
{
|
||||||
|
displayElement:
|
||||||
|
{
|
||||||
|
id:config.pages.displayElement.id,
|
||||||
|
eltDOM: checkContainerExist
|
||||||
|
},
|
||||||
|
name: (config.pages.name) ? config.pages.name : "Pages :",
|
||||||
|
selectedValue:1,// 1ère page affichée par défaut
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(config.options !== undefined)
|
||||||
|
{
|
||||||
|
let checkContainerExist=document.getElementById(config.options.displayElement.id);
|
||||||
|
if(checkContainerExist === null)
|
||||||
|
throw new Error(errors.elementNotFound+config.options.displayElement.id);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(let i = 0; i < config.options.values.length; i++)
|
||||||
|
{
|
||||||
|
if(freeDatas2HTML.isPositiveInteger(config.options.values[i]) === false)
|
||||||
|
throw new Error(errors.needPositiveInteger);
|
||||||
|
}
|
||||||
|
this._pagination.options =
|
||||||
|
{
|
||||||
|
displayElement: { id:config.options.displayElement.id, eltDOM:checkContainerExist },
|
||||||
|
name: (config.options.name) ? config.options.name : "Pagination :",
|
||||||
|
values:config.options.values
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Valeur de pagination par défaut qui peut être différente de celles éventuellement proposées en option :
|
||||||
|
if(config.selectedValue !== undefined)
|
||||||
|
{
|
||||||
|
if(config.options !== undefined && (config.options.values.indexOf(config.selectedValue) === -1))
|
||||||
|
throw new Error(errors.needPaginationByDefaultBeInOptions);
|
||||||
|
if(freeDatas2HTML.isPositiveInteger(config.selectedValue))
|
||||||
|
this._pagination.selectedValue=config.selectedValue;
|
||||||
|
else
|
||||||
|
throw new Error(errors.needPositiveInteger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get pagination(): pagination
|
||||||
|
{
|
||||||
|
return <pagination>this._pagination;
|
||||||
|
}
|
||||||
|
|
||||||
public async parse(): Promise<any>
|
public async parse(): Promise<any>
|
||||||
{
|
{
|
||||||
const converter=this;
|
const converter=this;
|
||||||
@ -228,6 +298,34 @@ export class freeDatas2HTML
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Si demandé, création d'une liste de paginations possibles
|
||||||
|
if(converter.pagination !==undefined && converter.pagination.options !==undefined && converter.pagination.options.values.length > 0)
|
||||||
|
{
|
||||||
|
const values=converter.pagination.options.values!;
|
||||||
|
let selectorsHTML="<label for='freeDatas2HTMLPaginationSelector'>"+converter.pagination.options.name+" </label><select name='freeDatas2HTMLPaginationSelector' id='freeDatas2HTMLPaginationSelector'><option value='0'>----</option>";
|
||||||
|
for(let j in values)
|
||||||
|
selectorsHTML+="<option value='"+(Number(j)+1)+"'>"+values[j]+"</option>";
|
||||||
|
selectorsHTML+="</select>";
|
||||||
|
converter.pagination.options.displayElement.eltDOM!.innerHTML=selectorsHTML;
|
||||||
|
let selectElement = document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
|
||||||
|
// Si une pagination par défaut existe et la sélectionne :
|
||||||
|
if(converter.pagination.selectedValue !== undefined)
|
||||||
|
{
|
||||||
|
let indexSelectedValue=converter.pagination.options.values.indexOf(converter.pagination.selectedValue)+1;
|
||||||
|
selectElement.value=""+indexSelectedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectElement.addEventListener('change', function(e)
|
||||||
|
{
|
||||||
|
if(selectElement.value === "0")
|
||||||
|
converter.pagination.selectedValue=undefined;
|
||||||
|
else
|
||||||
|
converter.pagination.selectedValue=values[Number(selectElement.value)-1];
|
||||||
|
converter.datasHTML=converter.createDatasHTML(converter.parseMeta!.fields as string[], converter.parseDatas);
|
||||||
|
converter.refreshView();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Je teste aussi les colonnes devant servir à classer les données.
|
// Je teste aussi les colonnes devant servir à classer les données.
|
||||||
for(let i in this._datasSortingColumns)
|
for(let i in this._datasSortingColumns)
|
||||||
{
|
{
|
||||||
@ -306,41 +404,50 @@ export class freeDatas2HTML
|
|||||||
datas.sort( (a, b) => compare( {order: colOrder} )(a[col], b[col]));
|
datas.sort( (a, b) => compare( {order: colOrder} )(a[col], b[col]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dois-je prendre en compte une pagination ?
|
||||||
|
let firstData=0;
|
||||||
|
if (this.pagination !== undefined && this.pagination.selectedValue !== undefined && this.pagination.pages !== undefined && this.pagination.pages.selectedValue !== undefined)
|
||||||
|
firstData=this.pagination.selectedValue*(this.pagination.pages.selectedValue-1);
|
||||||
|
let maxData = (this.pagination !== undefined && this.pagination.selectedValue !== undefined) ? this.pagination.selectedValue : datas.length+1;
|
||||||
|
|
||||||
// Création du tableau de données :
|
// Création du tableau de données :
|
||||||
let datasHTML="<table><thead>";
|
let datasHTML="<table><thead>";
|
||||||
for (let i in fields)
|
for (let i in fields)
|
||||||
datasHTML+="<th>"+fields[i]+"</th>";
|
datasHTML+="<th>"+fields[i]+"</th>";
|
||||||
datasHTML+="</thead><tbody>";
|
datasHTML+="</thead><tbody>";
|
||||||
|
let nbVisible=0, nbTotal=0;
|
||||||
for (let row in datas)
|
for (let row in datas)
|
||||||
{
|
{
|
||||||
let visible=true;
|
let visible=true;
|
||||||
if(filters.length !== 0)
|
if(filters.length !== 0)
|
||||||
{
|
{
|
||||||
for(let i in filters)
|
let i=0;
|
||||||
|
while(filters[i] !== undefined && visible===true)
|
||||||
{
|
{
|
||||||
// Il faut réutiliser le trim() utilisé pour créer les filtres, sinon on risque de ne pas retrouver certaines valeurs
|
// Il faut réutiliser le trim() utilisé pour créer les filtres, sinon on risque de ne pas retrouver certaines valeurs
|
||||||
if(filters[i].separator === undefined)
|
if(filters[i].separator === undefined)
|
||||||
{
|
{
|
||||||
if(datas[row][filters[i].field].trim() != filters[i].value)
|
if(datas[row][filters[i].field].trim() !== filters[i].value)
|
||||||
visible=false;
|
visible=false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
let checkedValues=datas[row][filters[i].field].split(filters[i].separator as string), finded=false;
|
visible=false;
|
||||||
|
let checkedValues=datas[row][filters[i].field].split(filters[i].separator as string);
|
||||||
for(let j in checkedValues)
|
for(let j in checkedValues)
|
||||||
{
|
{
|
||||||
if(checkedValues[j].trim() === filters[i].value)
|
if(checkedValues[j].trim() === filters[i].value)
|
||||||
{
|
{
|
||||||
finded=true;
|
visible=true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!finded)
|
}
|
||||||
visible=false;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(visible)
|
if(visible && nbTotal >= firstData && nbVisible < maxData)
|
||||||
{
|
{
|
||||||
datasHTML+="<tr>";
|
datasHTML+="<tr>";
|
||||||
for(let field in datas[row])
|
for(let field in datas[row])
|
||||||
@ -350,9 +457,42 @@ export class freeDatas2HTML
|
|||||||
datasHTML+="<td>"+datas[row][field]+"</td>";
|
datasHTML+="<td>"+datas[row][field]+"</td>";
|
||||||
}
|
}
|
||||||
datasHTML+="</tr>";
|
datasHTML+="</tr>";
|
||||||
|
nbVisible++;
|
||||||
|
nbTotal++;
|
||||||
}
|
}
|
||||||
|
else if(visible)
|
||||||
|
nbTotal++;
|
||||||
}
|
}
|
||||||
datasHTML+="</tbody></table>";
|
datasHTML+="</tbody></table>";
|
||||||
|
|
||||||
|
// Si pagination définie et tous les enregistrements n'ont pas été affichés, alors création d'un sélecteur de pages
|
||||||
|
if (this.pagination !== undefined && this.pagination.selectedValue !== undefined && this.pagination.pages !== undefined && nbTotal > this.pagination.selectedValue)
|
||||||
|
{
|
||||||
|
let nbPages=Math.ceil(nbTotal/this.pagination.selectedValue);
|
||||||
|
let selectorsHTML="<label for='freeDatas2HTMLPagesSelector'>"+this.pagination.pages.name+" </label><select name='freeDatas2HTMLPagesSelector' id='freeDatas2HTMLPagesSelector'><option value='1'>1</option>";
|
||||||
|
this.pagination.pages.values=[1];
|
||||||
|
for(let j=2; j <= nbPages; j++)
|
||||||
|
{
|
||||||
|
selectorsHTML+="<option value='"+j+"'>"+j+"</option>";
|
||||||
|
this.pagination.pages.values.push(j);
|
||||||
|
}
|
||||||
|
selectorsHTML+="</select>";
|
||||||
|
this.pagination.pages.displayElement.eltDOM!.innerHTML=selectorsHTML;
|
||||||
|
let selectElement = document.getElementById("freeDatas2HTMLPagesSelector") as HTMLInputElement;
|
||||||
|
if(this.pagination.pages.selectedValue !== undefined)
|
||||||
|
selectElement.value=""+this.pagination.pages.selectedValue;
|
||||||
|
let converter=this;
|
||||||
|
this.pagination.pages.selectedValue=1;
|
||||||
|
selectElement.addEventListener('change', function(e)
|
||||||
|
{
|
||||||
|
converter.pagination.pages!.selectedValue=Number(selectElement.value);
|
||||||
|
converter.datasHTML=converter.createDatasHTML(converter.parseMeta!.fields as string[], converter.parseDatas);
|
||||||
|
converter.refreshView();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if(this.pagination !== undefined && this.pagination.pages !== undefined)
|
||||||
|
this.pagination.pages.displayElement.eltDOM!.innerHTML="";
|
||||||
|
|
||||||
return datasHTML;
|
return datasHTML;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ export interface domElement
|
|||||||
id: string;
|
id: string;
|
||||||
eltDOM?: HTMLElement;
|
eltDOM?: HTMLElement;
|
||||||
}
|
}
|
||||||
export interface selectors extends domElement
|
export interface selectors extends domElement // revoir pour donner un autre nom
|
||||||
{
|
{
|
||||||
datasFieldNb: number;
|
datasFieldNb: number;
|
||||||
separator?: string;
|
separator?: string;
|
||||||
@ -20,3 +20,20 @@ export interface sortingFunctions
|
|||||||
datasFieldNb: number;
|
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
|
sort(a: any,b: any, order?: "asc"|"desc"): number; // cf. https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
|
||||||
}
|
}
|
||||||
|
export interface pagination
|
||||||
|
{
|
||||||
|
options?:
|
||||||
|
{
|
||||||
|
displayElement: domElement;
|
||||||
|
name?: string; // rendre obligatoire ?
|
||||||
|
values: number[];
|
||||||
|
};
|
||||||
|
selectedValue?: number; // on peut utiliser une pagination sans proposer d'options à l'utilisateur.
|
||||||
|
pages?:
|
||||||
|
{
|
||||||
|
displayElement: domElement;
|
||||||
|
name?: string; // rendre obligatoire ?
|
||||||
|
values?: number[];
|
||||||
|
selectedValue?: number;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -34,11 +34,9 @@ describe("freeDatas2HTML", () =>
|
|||||||
expect(() => { return converter.datasViewElt={ id:"datas" }; }).not.toThrowError();
|
expect(() => { return converter.datasViewElt={ id:"datas" }; }).not.toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Ne doit accepter que les sélecteurs pour lesquels un élément a été trouvé dans la page pour l'id fourni.", () =>
|
it("Doit générer une erreur si l'url fournie pour le fichier de données est vide.", () =>
|
||||||
{
|
{
|
||||||
converter.datasSelectors=[{ datasFieldNb:2, id:"selector2" },{ datasFieldNb:3, id:"selector3" }];
|
expect(() => { return converter.datasSourceUrl=" "; }).toThrowError(errors.needUrl);
|
||||||
expect(converter.datasSelectors.length).toEqual(1);
|
|
||||||
expect(converter.datasSelectors[0].id).toEqual("selector2");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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.", () =>
|
||||||
@ -49,6 +47,22 @@ describe("freeDatas2HTML", () =>
|
|||||||
expect(freeDatas2HTML.isNaturalNumber(1)).toBeTrue();
|
expect(freeDatas2HTML.isNaturalNumber(1)).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Doit retourner un booléen indiquant si un nombre est un entier positif ou non.", () =>
|
||||||
|
{
|
||||||
|
expect(freeDatas2HTML.isPositiveInteger(-1)).toBeFalse();
|
||||||
|
expect(freeDatas2HTML.isPositiveInteger(1.25)).toBeFalse();
|
||||||
|
expect(freeDatas2HTML.isPositiveInteger(0)).toBeFalse();
|
||||||
|
expect(freeDatas2HTML.isPositiveInteger(1)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filtres :
|
||||||
|
it("Ne doit accepter que les sélecteurs pour lesquels un élément a été trouvé dans la page pour l'id fourni.", () =>
|
||||||
|
{
|
||||||
|
converter.datasSelectors=[{ datasFieldNb:2, id:"selector2" },{ datasFieldNb:3, id:"selector3" }];
|
||||||
|
expect(converter.datasSelectors.length).toEqual(1);
|
||||||
|
expect(converter.datasSelectors[0].id).toEqual("selector2");
|
||||||
|
});
|
||||||
|
|
||||||
it("Si un séparateur vide est fourni pour un sélecteur, il doit être ignoré.", () =>
|
it("Si un séparateur vide est fourni pour un sélecteur, il doit être ignoré.", () =>
|
||||||
{
|
{
|
||||||
converter.datasSelectors=[{ datasFieldNb:2, id:"selector2", separator:"" }];
|
converter.datasSelectors=[{ datasFieldNb:2, id:"selector2", separator:"" }];
|
||||||
@ -61,11 +75,7 @@ describe("freeDatas2HTML", () =>
|
|||||||
expect(converter.datasSelectors.length).toEqual(2);
|
expect(converter.datasSelectors.length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Doit générer une erreur si l'url fournie pour le fichier de données est vide.", () =>
|
// Classement des données :
|
||||||
{
|
|
||||||
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.", () =>
|
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 !
|
// Fonction volontairement basique, car ce n'est pas la fonction que l'on teste ici, mais le fait que l'on puisse l'utiliser !
|
||||||
@ -82,6 +92,58 @@ describe("freeDatas2HTML", () =>
|
|||||||
expect(converter.getSortingFunctionForField(0)).toBeDefined();
|
expect(converter.getSortingFunctionForField(0)).toBeDefined();
|
||||||
expect([7,9,3,5].sort(converter.getSortingFunctionForField(0).sort)).toEqual([9,7,5,3]);
|
expect([7,9,3,5].sort(converter.getSortingFunctionForField(0).sort)).toEqual([9,7,5,3]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Pagination :
|
||||||
|
it("Doit générer une erreur quand aucun élément n'est fourni pour recevoir le sélecteur de pages, alors que cela est nécessaire.", () =>
|
||||||
|
{
|
||||||
|
expect(() => { return converter.pagination={ selectedValue:10 }; }).toThrowError(errors.needPagesSelectorElt);
|
||||||
|
expect(() => { return converter.pagination={ options: { displayElement: { id:"paginationOptions" }, values: [10,20] }}; }).toThrowError(errors.needPagesSelectorElt);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit générer une erreur si l'élément fourni pour recevoir le sélecteur de pages n'existe pas dans le DOM.", () =>
|
||||||
|
{
|
||||||
|
expect(() => { return converter.pagination={ selectedValue:10, pages: { displayElement: { id:"dontExist" }} }; }).toThrowError(errors.elementNotFound+"dontExist");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit générer une erreur si l'élément fourni pour recevoir le sélecteur de pagination n'existe pas dans le DOM.", () =>
|
||||||
|
{
|
||||||
|
expect(() => { return converter.pagination={ options: { displayElement: { id:"dontExist" }, values: [10,20] }, pages: { displayElement: { id:"pages" }}}; }).toThrowError(errors.elementNotFound+"dontExist");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit générer une erreur si au moins une des options de pagination proposée n'est pas un entier positif.", () =>
|
||||||
|
{
|
||||||
|
expect(() => { return converter.pagination={ options: { displayElement: { id:"paginationOptions" }, values:[0,10,20] }, pages: { displayElement: { id:"pages" }}}; }).toThrowError(errors.needPositiveInteger);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit générer une erreur si la pagination par défaut n'est pas un entier positif.", () =>
|
||||||
|
{
|
||||||
|
expect(() => { return converter.pagination={ selectedValue:0, pages: { displayElement: { id:"pages" }} }; }).toThrowError(errors.needPositiveInteger);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit générer une erreur si la pagination par défaut ne fait pas partie des valeurs proposées en option.", () =>
|
||||||
|
{
|
||||||
|
expect(() => { return converter.pagination={ selectedValue:15, options: { displayElement: { id:"paginationOptions" }, values:[10,20,50] }, pages: { displayElement: { id:"pages" }}}; }).toThrowError(errors.needPaginationByDefaultBeInOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit accepter une configuration correcte pour la pagination.", () =>
|
||||||
|
{
|
||||||
|
let paginationOk =
|
||||||
|
{
|
||||||
|
selectedValue:10,
|
||||||
|
options:
|
||||||
|
{
|
||||||
|
displayElement : { id:"paginationOptions" },
|
||||||
|
values: [10,20,50],
|
||||||
|
name: "Choix de pagination :"
|
||||||
|
},
|
||||||
|
pages:
|
||||||
|
{
|
||||||
|
displayElement : { id:"pages" },
|
||||||
|
name: "Page à afficher :"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(() => { return converter.pagination=paginationOk; }).not.toThrowError();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Parsage du fichier et création du tableau de données", () =>
|
describe("Parsage du fichier et création du tableau de données", () =>
|
||||||
@ -257,6 +319,25 @@ describe("freeDatas2HTML", () =>
|
|||||||
let txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
let txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||||
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLForSelectTagsField);
|
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLForSelectTagsField);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Les sélecteurs basés sur un séparateur peuvent fonctionner avec un autre filtre.", async () =>
|
||||||
|
{
|
||||||
|
converter.datasSourceUrl="http://localhost:9876/datas/datas1+tagsfield.csv";
|
||||||
|
converter.datasSelectors=[{ datasFieldNb:4, id:"selector1"}, { datasFieldNb:5, id:"selector2", separator:"|"}];
|
||||||
|
await converter.run();
|
||||||
|
|
||||||
|
let selectElement=document.getElementById("freeDatas2HTMLSelector1") as HTMLInputElement;
|
||||||
|
selectElement.value="11"; // = "Exemple10" retournant une seule ligne
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
let txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||||
|
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLForSelectTagsField);
|
||||||
|
|
||||||
|
selectElement=document.getElementById("freeDatas2HTMLSelector0") as HTMLInputElement;
|
||||||
|
selectElement.value="3"; // doit supprimer la ligne restant
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||||
|
expect(txtDatasViewsElt).toEqual("<table><thead><tr><th>Z (numéro atomique)</th><th>Élément</th><th>Symbole</th><th>Famille</th><th>Abondance des éléments dans la croûte terrestre (μg/k)</th><th>Étiquettes</th></tr></thead><tbody></tbody></table>");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Création et action des colonnes permettant de classer les données affichées.", () =>
|
describe("Création et action des colonnes permettant de classer les données affichées.", () =>
|
||||||
@ -283,9 +364,9 @@ describe("freeDatas2HTML", () =>
|
|||||||
{
|
{
|
||||||
converter.datasSortingColumns=[{ datasFieldNb:0 },{ datasFieldNb:2 }];
|
converter.datasSortingColumns=[{ datasFieldNb:0 },{ datasFieldNb:2 }];
|
||||||
await converter.run();
|
await converter.run();
|
||||||
let getTableTh=document.querySelectorAll("table th");
|
let getTableTr=document.querySelectorAll("table th");
|
||||||
expect(getTableTh[0].innerHTML).toEqual(fixtures.sortingColumn1HTML);
|
expect(getTableTr[0].innerHTML).toEqual(fixtures.sortingColumn1HTML);
|
||||||
expect(getTableTh[2].innerHTML).toEqual(fixtures.sortingColumn2HTML);
|
expect(getTableTr[2].innerHTML).toEqual(fixtures.sortingColumn2HTML);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Le 1er click sur l'entête d'une des colonnes doit classer les données dans le sens ascendant, puis descendant et ainsi de suite, en prenant en compte les éventuels filtres.", async () =>
|
it("Le 1er click sur l'entête d'une des colonnes doit classer les données dans le sens ascendant, puis descendant et ainsi de suite, en prenant en compte les éventuels filtres.", async () =>
|
||||||
@ -298,16 +379,97 @@ describe("freeDatas2HTML", () =>
|
|||||||
selectElement = document.getElementById("freeDatas2HTMLSelector1") as HTMLInputElement;
|
selectElement = document.getElementById("freeDatas2HTMLSelector1") as HTMLInputElement;
|
||||||
selectElement.value="1";
|
selectElement.value="1";
|
||||||
selectElement.dispatchEvent(new Event('change'));
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
let getTableThLink=document.querySelector("table th a") as HTMLElement;
|
let getTableTrLink=document.querySelector("table th a") as HTMLElement;
|
||||||
getTableThLink.click();// tri ascendant
|
getTableTrLink.click();// tri ascendant
|
||||||
let txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
let txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||||
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLFor2Select1Clic);
|
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLFor2Select1Clic);
|
||||||
getTableThLink.click();// tri descendant
|
getTableTrLink.click();// tri descendant
|
||||||
txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||||
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLFor2Select2Clic);
|
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLFor2Select2Clic);
|
||||||
getTableThLink.click();// de nouveau ascendant
|
getTableTrLink.click();// de nouveau ascendant
|
||||||
txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||||
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLFor2Select1Clic);
|
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLFor2Select1Clic);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Création et action des options permettant de paginer les données affichées.", () =>
|
||||||
|
{
|
||||||
|
beforeEach( () =>
|
||||||
|
{
|
||||||
|
converter.datasViewElt={ id:"datas" };
|
||||||
|
converter.datasSourceUrl="http://localhost:9876/datas/datas1.csv";
|
||||||
|
converter.pagination=
|
||||||
|
{
|
||||||
|
selectedValue:10,
|
||||||
|
options:
|
||||||
|
{
|
||||||
|
displayElement : { id:"paginationOptions" },
|
||||||
|
values: [10,20,50,500],
|
||||||
|
name: "Choix de pagination :"
|
||||||
|
},
|
||||||
|
pages:
|
||||||
|
{
|
||||||
|
displayElement : { id:"pages" },
|
||||||
|
name: "Page à afficher :"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Si des options de pagination sont fournies, doit générer un élement <select> listant les valeurs possibles.", async () =>
|
||||||
|
{
|
||||||
|
await converter.run();
|
||||||
|
expect(document.getElementById("paginationOptions").innerHTML).toEqual(fixtures.selectorForPagination);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Si une valeur de pagination par défaut fournie, ne doit pas afficher plus de données.", async () =>
|
||||||
|
{
|
||||||
|
await converter.run();
|
||||||
|
let getTableTr=document.querySelectorAll("tr");// attention, un tr sert aux titres
|
||||||
|
expect(getTableTr.length).toEqual(converter.pagination.selectedValue+1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Si une des options de pagination fournies est sélectionnée, doit afficher la première page de résultats correspondants.", async () =>
|
||||||
|
{
|
||||||
|
await converter.run();
|
||||||
|
let selectElement = document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
|
||||||
|
selectElement.value="2"; // = 20 éléments / page
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
let getTableTr=document.querySelectorAll("tr");
|
||||||
|
expect(getTableTr.length).toEqual(21);
|
||||||
|
selectElement.value="3"; // = 50 éléments / page
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
getTableTr=document.querySelectorAll("tr");
|
||||||
|
expect(getTableTr.length).toEqual(51);
|
||||||
|
selectElement.value="0"; // = pas de pagination, on affiche les 118 lignes du fichier
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
getTableTr=document.querySelectorAll("tr");
|
||||||
|
expect(getTableTr.length).toEqual(119);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Si il y a plus de données que le nombre de lignes autorisées par page, un <select> listant les pages doit être affichés.", async () =>
|
||||||
|
{
|
||||||
|
await converter.run();
|
||||||
|
let btnPaginationElt=document.getElementById("pages").innerHTML;
|
||||||
|
expect(btnPaginationElt).toEqual(fixtures.selectorForPages);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Si l'utilisateur sélectionne une des pages proposées, l'affichage des résultats doit s'adapter en prenant en compte la pagination sélectionnée.", async () =>
|
||||||
|
{
|
||||||
|
await converter.run();
|
||||||
|
let selectElement = document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
|
||||||
|
selectElement.value="3"; // = 50 éléments / page
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
selectElement=document.getElementById("freeDatas2HTMLPagesSelector") as HTMLInputElement;
|
||||||
|
selectElement.value="2";
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
let getTableTr=document.getElementsByTagName("tr");
|
||||||
|
expect(getTableTr[1].innerHTML).toEqual(fixtures.firstLineForPageSelection1);
|
||||||
|
expect(getTableTr[50].innerHTML).toEqual(fixtures.lastLineForPageSelection1);
|
||||||
|
selectElement.value="3"; // troisième page = incomplèet (18 enregistrements)
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
getTableTr=document.getElementsByTagName("tr");
|
||||||
|
expect(getTableTr[1].innerHTML).toEqual(fixtures.firstLineForPageSelection2);
|
||||||
|
expect(getTableTr[18].innerHTML).toEqual(fixtures.lastLineForPageSelection2);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user