Nouvelle version classe des filtres/sélecteurs + revue des tests associés.
This commit is contained in:
parent
8a129d169b
commit
a58c7da008
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "freedatas2html",
|
"name": "freedatas2html",
|
||||||
"version": "0.8.9",
|
"version": "0.9.0",
|
||||||
"description": "Conversion and display of data in different formats (CSV, JSON, HTML) with the possibility of filtering, classifying and paginating the results.",
|
"description": "Conversion and display of data in different formats (CSV, JSON, HTML) with the possibility of filtering, classifying and paginating the results.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
131
src/Selector.ts
131
src/Selector.ts
@ -5,36 +5,36 @@ import { FreeDatas2HTML } from "./freeDatas2HTML";
|
|||||||
|
|
||||||
export class Selector implements Selectors
|
export class Selector implements Selectors
|
||||||
{
|
{
|
||||||
_converter: FreeDatas2HTML;
|
private _converter: FreeDatas2HTML;
|
||||||
_datasViewElt: DOMElement= { id:"", eltDOM:undefined }; // élément du DOM dans lequel afficher le "select"
|
private _datasFieldNb: number;
|
||||||
_datasFieldNb: number; // numéro du champ dont les données serviront au filtre
|
private _datasViewElt: DOMElement={ id: "", eltDOM: undefined };
|
||||||
_separator: string|undefined; // séparateur éventuel pour les données du champ
|
private _selectedValue: number|undefined=undefined;
|
||||||
name: string = ""; // nom à afficher dans le DOM comme "label" du "select"
|
private _separator: string|undefined;
|
||||||
values: string[]=[]; // données proposées par le filtre, après traitement des données reçues
|
private _values: string[]=[];
|
||||||
|
private _name: string="";
|
||||||
|
|
||||||
// Injection de la classe principale, mais uniquement si les données ont été importées
|
// Injection de la classe principale, mais uniquement si des données ont été importées
|
||||||
constructor(converter: FreeDatas2HTML, datasFieldNb: number, elt: DOMElement)
|
// Le champ duquel le sélecteur tire ses données doit exister ?
|
||||||
|
constructor(converter: FreeDatas2HTML, datasFieldNb: number, elt: DOMElement, separator?: string)
|
||||||
{
|
{
|
||||||
if(converter.fields === undefined || converter.datas.length === 0)
|
if(converter.fields === undefined || converter.datas.length === 0)
|
||||||
throw new Error(errors.selectorNeedDatas);
|
throw new Error(errors.filterNeedDatas);
|
||||||
else if(! converter.checkFieldExist(Number(datasFieldNb)))
|
else if(! converter.checkFieldExist(Number(datasFieldNb)))
|
||||||
throw new Error(errors.selectorFieldNotFound);
|
throw new Error(errors.selectorFieldNotFound);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt); // provoque une erreur, si élement non trouvé dans DOM
|
this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt);
|
||||||
this._converter=converter;
|
this._converter=converter;
|
||||||
this._datasFieldNb=datasFieldNb;
|
this._datasFieldNb=datasFieldNb;
|
||||||
|
// Pas de trim(), car l'espace peut être le séparateur :
|
||||||
|
if(separator !== undefined && separator !== "")
|
||||||
|
this._separator=separator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore un séparateur de données vide
|
get converter() : FreeDatas2HTML
|
||||||
// Attention : pas de trim(), car l'espace peut être un séparateur
|
|
||||||
set separator(separator: string|undefined)
|
|
||||||
{
|
{
|
||||||
if(separator === "")
|
return this._converter;
|
||||||
this._separator=undefined;
|
|
||||||
else
|
|
||||||
this._separator=separator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get datasViewElt() : DOMElement
|
get datasViewElt() : DOMElement
|
||||||
@ -47,91 +47,102 @@ export class Selector implements Selectors
|
|||||||
return this._datasFieldNb;
|
return this._datasFieldNb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get name() : string
|
||||||
|
{
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get selectedValue() : number|undefined
|
||||||
|
{
|
||||||
|
return this._selectedValue;
|
||||||
|
}
|
||||||
|
|
||||||
get separator() : string|undefined
|
get separator() : string|undefined
|
||||||
{
|
{
|
||||||
return this._separator;
|
return this._separator;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Création du <select> dans le HTML correspondant au filtre
|
get values(): string[]
|
||||||
public filter2HTML() : void
|
|
||||||
{
|
{
|
||||||
if(this._converter === undefined || this._datasViewElt.eltDOM === undefined || this._datasFieldNb === undefined)
|
return this._values;
|
||||||
throw new Error(errors.filter2HTMLFail);
|
}
|
||||||
else
|
|
||||||
|
// Création du <select> dans le DOM correspondant au filtre
|
||||||
|
public filter2HTML(label:string="") : void
|
||||||
{
|
{
|
||||||
this.name=this._converter.fields![this._datasFieldNb]; // this._converter.parse... ne peuvent être indéfinis si this._converter existe (cf constructeur)
|
this._name=this._converter.fields![this._datasFieldNb]; // "!" car l'existence du champ est testé par le constructeur
|
||||||
for (let row of this._converter.datas)
|
for (let row of this._converter.datas)
|
||||||
{
|
{
|
||||||
|
let checkedValue;
|
||||||
if(this._separator === undefined)
|
if(this._separator === undefined)
|
||||||
{
|
{
|
||||||
if(row[this.name] !== "" && this.values.indexOf(row[this.name]) === -1)
|
checkedValue=row[this._name].trim(); // trim() évite des problèmes de classement des éléments du SELECT
|
||||||
this.values.push(row[this.name]);
|
if(checkedValue !== "" && this._values.indexOf(checkedValue) === -1)
|
||||||
|
this._values.push(checkedValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
let checkedValues=row[this.name].split(this._separator);
|
let checkedValues=row[this._name].split(this._separator);
|
||||||
for(let value of checkedValues)
|
for(let value of checkedValues)
|
||||||
{
|
{
|
||||||
if(value !== "" && this.values.indexOf(value) === -1)
|
checkedValue=value.trim();
|
||||||
this.values.push(value);
|
if(checkedValue !== "" && this._values.indexOf(checkedValue) === -1)
|
||||||
|
this._values.push(checkedValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(this.values.length > 0)
|
|
||||||
|
if(this._values.length === 0) // possible si uniquement des valeurs vides pour ce champ
|
||||||
|
throw new Error(errors.selectorFieldIsEmpty);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// Classement des données à l'aide (ou non) d'une fonction spécifique :
|
// Classement des données à l'aide (ou non) d'une fonction spécifique :
|
||||||
if(this._converter.getSortingFunctionForField(this._datasFieldNb) !== undefined)
|
if(this._converter.getSortingFunctionForField(this._datasFieldNb) !== undefined)
|
||||||
this.values.sort(this._converter.getSortingFunctionForField(this._datasFieldNb)!.sort); // sans le "!" : TS2532: Object is possibly 'undefined' ??
|
this._values.sort(this._converter.getSortingFunctionForField(this._datasFieldNb)!.sort); // sans le "!" : TS2532: Object is possibly 'undefined' ???
|
||||||
else
|
else
|
||||||
this.values.sort(compare());
|
this._values.sort(compare());
|
||||||
|
|
||||||
// Création et injection du SELECT dans le DOM
|
// Création et injection du SELECT dans le DOM
|
||||||
let selectorsHTML="<label for='freeDatas2HTML_"+this._datasViewElt.id+"'>"+this.name+" : </label><select name='freeDatas2HTML_"+this._datasViewElt.id+"' id='freeDatas2HTML_"+this._datasViewElt.id+"'><option value='0'>----</option>"; // l'option zéro permet d'actualiser l'affichage en ignorant ce filtre
|
label=(label === "") ? this._name : label;
|
||||||
for(let i=0; i< this.values.length; i++)
|
let selectorsHTML="<label for='freeDatas2HTML_"+this._datasViewElt.id+"'>"+label+" :</label><select name='freeDatas2HTML_"+this._datasViewElt.id+"' id='freeDatas2HTML_"+this._datasViewElt.id+"'><option value='0'>----</option>"; // l'option zéro permet d'actualiser l'affichage en ignorant ce filtre
|
||||||
selectorsHTML+="<option value='"+(i+1)+"'>"+this.values[i]+"</option>";
|
for(let i=0; i< this._values.length; i++)
|
||||||
|
selectorsHTML+="<option value='"+(i+1)+"'>"+this._values[i]+"</option>";
|
||||||
selectorsHTML+="</select>";
|
selectorsHTML+="</select>";
|
||||||
this. _datasViewElt.eltDOM.innerHTML=selectorsHTML;
|
this. _datasViewElt.eltDOM!.innerHTML=selectorsHTML;// "!" car l'existence de "eltDOM" est testé par le constructeur
|
||||||
|
|
||||||
const selectElement=document.getElementById("freeDatas2HTML_"+this._datasViewElt.id) as HTMLInputElement, mySelector=this;
|
const selectElement=document.getElementById("freeDatas2HTML_"+this._datasViewElt.id) as HTMLInputElement, mySelector=this;
|
||||||
selectElement.addEventListener("change", function(e)
|
selectElement.addEventListener("change", function(e)
|
||||||
{
|
{
|
||||||
|
if(selectElement.value === "0")
|
||||||
|
mySelector._selectedValue=undefined;
|
||||||
|
else
|
||||||
|
mySelector._selectedValue=parseInt(selectElement.value,10)-1;
|
||||||
mySelector._converter.refreshView();
|
mySelector._converter.refreshView();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifie si une valeur est sélectionnée dans la liste et, si oui, la retourne
|
public dataIsOk(data: {[index: string]:string}) : boolean
|
||||||
public getSelectionnedId() : number
|
|
||||||
{
|
{
|
||||||
const selectElement=document.getElementById("freeDatas2HTML_"+this._datasViewElt.id) as HTMLInputElement;
|
// Permet de vérifier que filter2HTML() a été préalablement appelée :
|
||||||
if(selectElement === undefined)
|
if(this._name === "")
|
||||||
return 0;
|
throw new Error(errors.filterCheckIsOkFail);
|
||||||
else
|
|
||||||
return parseInt(selectElement.value,10);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifie sur l'enregistrement passé correspond à la valeur sélectionnée par l'utilisateur dans le filtre
|
// Pas de valeur sélectionnée = pas de filtre sur ce champ
|
||||||
public dataIsOk(data: any) : boolean
|
if(this._selectedValue === undefined)
|
||||||
{
|
|
||||||
if(this.name === undefined || this.name === "")
|
|
||||||
throw new Error(errors.selectorCheckIsOkFail);
|
|
||||||
|
|
||||||
let selectedValue = this.getSelectionnedId();
|
|
||||||
if(selectedValue === 0) // = pas de valeur sélectionnée = pas de filtre sur ce champ
|
|
||||||
return true;
|
return true;
|
||||||
else
|
|
||||||
selectedValue=selectedValue-1;
|
|
||||||
|
|
||||||
if(this.values[selectedValue] === undefined)
|
if(this._values[this._selectedValue] === undefined) // théoriquement impossible, mais cela vient du client...
|
||||||
throw new Error(errors.selectorSelectedIndexNotFound);
|
throw new Error(errors.selectorSelectedIndexNotFound);
|
||||||
|
|
||||||
if(data[this.name] === undefined) // champ absent pour cet enregistrement, qui est donc refusé
|
// Si le champ est absent pour un enregistrement, il est refusé
|
||||||
|
if(data[this._name] === undefined)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const selectedValueTxt=this.values[selectedValue] ;
|
const selectedValueTxt=this._values[this._selectedValue];
|
||||||
if(this._separator === undefined)
|
if(this._separator === undefined)
|
||||||
{
|
{
|
||||||
if(data[this.name] !== selectedValueTxt)
|
if(data[this._name].trim() !== selectedValueTxt)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
@ -139,10 +150,10 @@ export class Selector implements Selectors
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
let find=false;
|
let find=false;
|
||||||
let checkedValues=data[this.name].split(this._separator);
|
let checkedValues=data[this._name].split(this._separator);
|
||||||
for(let value of checkedValues)
|
for(let value of checkedValues)
|
||||||
{
|
{
|
||||||
if(value === selectedValueTxt)
|
if(value.trim() === selectedValueTxt)
|
||||||
{
|
{
|
||||||
find=true;
|
find=true;
|
||||||
break;
|
break;
|
||||||
|
@ -4,6 +4,8 @@ module.exports =
|
|||||||
converterFieldNotFound : "Le champ n'existe pas dans les données ou les données n'ont pas encore été chargées.",
|
converterFieldNotFound : "Le champ n'existe pas dans les données ou les données n'ont pas encore été chargées.",
|
||||||
converterNeedDatasElt: "Merci de fournir un id valide pour l'élément où afficher les données.",
|
converterNeedDatasElt: "Merci de fournir un id valide pour l'élément où afficher les données.",
|
||||||
converterRefreshFail: "Le nom des champs et l'élement du DOM receveur sont nécessaires à l'affichage des données.",
|
converterRefreshFail: "Le nom des champs et l'élement du DOM receveur sont nécessaires à l'affichage des données.",
|
||||||
|
filterCheckIsOkFail: "Le test est lancé sur un filtre incorrectement initialisé ou sur un attribut absent de la donnée à tester.",
|
||||||
|
filterNeedDatas: "Le création d'un filtre nécessite la présence des données à filtrer.",
|
||||||
pagination2HTMLFail : "Toutes les donnée nécessaires à la création des sélecteurs de pagination n'ont pas été fournies.",
|
pagination2HTMLFail : "Toutes les donnée nécessaires à la création des sélecteurs de pagination n'ont pas été fournies.",
|
||||||
paginationNeedByfaultValueBeInOptions: "La valeur de pagination par défaut doit faire partie des options proposées.",
|
paginationNeedByfaultValueBeInOptions: "La valeur de pagination par défaut doit faire partie des options proposées.",
|
||||||
paginationNeedDatas: "Il ne peut y avoir de pagination, si les données n'ont pas été récupérées.",
|
paginationNeedDatas: "Il ne peut y avoir de pagination, si les données n'ont pas été récupérées.",
|
||||||
@ -28,11 +30,9 @@ module.exports =
|
|||||||
remoteSourceUrlFail: "L'url fournie ne semble pas valide.",
|
remoteSourceUrlFail: "L'url fournie ne semble pas valide.",
|
||||||
renderNeedFields: "Les noms de champs doivent être fournis avant de demander l'affichage des données.",
|
renderNeedFields: "Les noms de champs doivent être fournis avant de demander l'affichage des données.",
|
||||||
selector2HTMLFail: "Le création d'un filtre dans le DOM nécessite l'initialisation de l'élément HTML et du numéro du champs à filter.",
|
selector2HTMLFail: "Le création d'un filtre dans le DOM nécessite l'initialisation de l'élément HTML et du numéro du champs à filter.",
|
||||||
selectorCheckIsOkFail: "Le test est lancé sur un filtre incorrectement initialisé ou sur un attribut absent de la donnée à tester.",
|
selectorFieldIsEmpty: "Aucune donnée trouvée pour le champ du filtre",
|
||||||
selectorFieldNotFound: "Au moins un des champs devant servir à filtrer les données n'existe pas dans le fichier.",
|
selectorFieldNotFound: "Au moins un des champs devant servir à filtrer les données n'existe pas dans le fichier.",
|
||||||
selectorNeedDatas: "Le création d'un filtre nécessite la transmission des données à filtrer.",
|
|
||||||
selectorSelectedIndexNotFound: "La valeur sélectionnée n'a pas été trouvée dans la liste des champs.",
|
selectorSelectedIndexNotFound: "La valeur sélectionnée n'a pas été trouvée dans la liste des champs.",
|
||||||
sortingField2HTMLFail: "Toutes les donnée nécessaires à la création du lien de classement n'ont pas été fournies.",
|
|
||||||
sortingFieldNeedDatas: "Le création d'un champ de classement nécessite la transmission de la liste des champs.",
|
sortingFieldNeedDatas: "Le création d'un champ de classement nécessite la transmission de la liste des champs.",
|
||||||
sortingFieldNotFound: "Au moins un des champs devant permettre de classer les données n'existe pas dans le fichier.",
|
sortingFieldNotFound: "Au moins un des champs devant permettre de classer les données n'existe pas dans le fichier.",
|
||||||
sortingFieldsNbFail: "Le nombre de champs trouvés dans le DOM ne correspond pas à celui des données à classer.",
|
sortingFieldsNbFail: "Le nombre de champs trouvés dans le DOM ne correspond pas à celui des données à classer.",
|
||||||
|
@ -31,7 +31,7 @@ export interface Filters
|
|||||||
{
|
{
|
||||||
datasViewElt: DOMElement;
|
datasViewElt: DOMElement;
|
||||||
filter2HTML() : void;
|
filter2HTML() : void;
|
||||||
dataIsOk(data: any) : boolean;
|
dataIsOk(data: {[index: string]:string}) : boolean;
|
||||||
}
|
}
|
||||||
export interface Paginations
|
export interface Paginations
|
||||||
{
|
{
|
||||||
@ -54,10 +54,6 @@ export interface PaginationsPages
|
|||||||
values?: number[];
|
values?: number[];
|
||||||
selectedValue?: number;
|
selectedValue?: number;
|
||||||
}
|
}
|
||||||
export interface Datas
|
|
||||||
{
|
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
export interface ParseErrors
|
export interface ParseErrors
|
||||||
{
|
{
|
||||||
code?: string;
|
code?: string;
|
||||||
@ -93,9 +89,10 @@ export interface RemoteSources extends RemoteSourceSettings
|
|||||||
export interface Selectors extends Filters
|
export interface Selectors extends Filters
|
||||||
{
|
{
|
||||||
datasFieldNb: number;
|
datasFieldNb: number;
|
||||||
separator?: string|undefined;
|
name: string;
|
||||||
name?: string;
|
selectedValue: number|undefined;
|
||||||
values?: string[];
|
separator: string|undefined;
|
||||||
|
values: string[];
|
||||||
}
|
}
|
||||||
export interface SortingFields
|
export interface SortingFields
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,11 @@ module.exports =
|
|||||||
datasViewEltHTML: '<div id="fixture"><div id="selector1"></div><div id="selector2"></div><div id="paginationOptions"></div><div id="counter"></div><div id="datas"></div><div id="pages"></div></div>',
|
datasViewEltHTML: '<div id="fixture"><div id="selector1"></div><div id="selector2"></div><div id="paginationOptions"></div><div id="counter"></div><div id="datas"></div><div id="pages"></div></div>',
|
||||||
selector1HTML: '<label for="freeDatas2HTML_selector1">Famille :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Actinide</option><option value="2">Gaz noble</option><option value="3">gaz rare</option><option value="4">Halogène</option><option value="5">Indéfinie</option><option value="6">Lanthanide</option><option value="7">Métal alcalin</option><option value="8">Métal alcalino-terreux</option><option value="9">Métal de transition</option><option value="10">Métal pauvre</option><option value="11">Métalloïde</option><option value="12">Non-métal</option></select>',
|
selector1HTML: '<label for="freeDatas2HTML_selector1">Famille :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Actinide</option><option value="2">Gaz noble</option><option value="3">gaz rare</option><option value="4">Halogène</option><option value="5">Indéfinie</option><option value="6">Lanthanide</option><option value="7">Métal alcalin</option><option value="8">Métal alcalino-terreux</option><option value="9">Métal de transition</option><option value="10">Métal pauvre</option><option value="11">Métalloïde</option><option value="12">Non-métal</option></select>',
|
||||||
selector2HTML: '<label for="freeDatas2HTML_selector2">Abondance des éléments dans la croûte terrestre (μg/k) :</label><select name="freeDatas2HTML_selector2" id="freeDatas2HTML_selector2"><option value="0">----</option><option value="1">> 1 et < 100 000</option><option value="2">> 100000</option><option value="3">≤ 1</option><option value="4">Inexistant</option><option value="5">Traces</option></select>',
|
selector2HTML: '<label for="freeDatas2HTML_selector2">Abondance des éléments dans la croûte terrestre (μg/k) :</label><select name="freeDatas2HTML_selector2" id="freeDatas2HTML_selector2"><option value="0">----</option><option value="1">> 1 et < 100 000</option><option value="2">> 100000</option><option value="3">≤ 1</option><option value="4">Inexistant</option><option value="5">Traces</option></select>',
|
||||||
|
selector2HTMLWithLabel: '<label for="freeDatas2HTML_selector2">Abondance des éléments :</label><select name="freeDatas2HTML_selector2" id="freeDatas2HTML_selector2"><option value="0">----</option><option value="1">> 1 et < 100 000</option><option value="2">> 100000</option><option value="3">≤ 1</option><option value="4">Inexistant</option><option value="5">Traces</option></select>',
|
||||||
selector1HTMLWithSeparator: '<label for="freeDatas2HTML_selector1">Étiquettes :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Exemple0</option><option value="2">Exemple1</option><option value="3">Exemple2</option><option value="4">Exemple3</option><option value="5">Exemple4</option><option value="6">Exemple5</option><option value="7">Exemple6</option><option value="8">Exemple7</option><option value="9">Exemple8</option><option value="10">Exemple9</option><option value="11">Exemple10</option></select>',
|
selector1HTMLWithSeparator: '<label for="freeDatas2HTML_selector1">Étiquettes :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Exemple0</option><option value="2">Exemple1</option><option value="3">Exemple2</option><option value="4">Exemple3</option><option value="5">Exemple4</option><option value="6">Exemple5</option><option value="7">Exemple6</option><option value="8">Exemple7</option><option value="9">Exemple8</option><option value="10">Exemple9</option><option value="11">Exemple10</option></select>',
|
||||||
|
selectorHTMLWithTrim: '<label for="freeDatas2HTML_selector1">Famille :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Gaz noble</option><option value="2">Métal alcalin</option><option value="3">Métal alcalino-terreux</option><option value="4">Métalloïde</option><option value="5">Non-métal</option></select>',
|
||||||
selector1HTMLWithFunction: '<label for="freeDatas2HTML_selector1">Abondance des éléments dans la croûte terrestre (μg/k) :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Inexistant</option><option value="2">Traces</option><option value="3">≤ 1</option><option value="4">> 1 et < 100 000</option><option value="5">> 100000</option></select>',
|
selector1HTMLWithFunction: '<label for="freeDatas2HTML_selector1">Abondance des éléments dans la croûte terrestre (μg/k) :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Inexistant</option><option value="2">Traces</option><option value="3">≤ 1</option><option value="4">> 1 et < 100 000</option><option value="5">> 100000</option></select>',
|
||||||
|
selectorHTMLWithFakeItem: '<label for="freeDatas2HTML_selector1">Famille :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Actinide</option><option value="2">Gaz noble</option><option value="3">gaz rare</option><option value="4">Halogène</option><option value="5">Indéfinie</option><option value="6">Lanthanide</option><option value="7">Métal alcalin</option><option value="8">Métal alcalino-terreux</option><option value="9">Métal de transition</option><option value="10">Métal pauvre</option><option value="11">Métalloïde</option><option value="12">Non-métal</option><option value="13">Je suis un gros fake !</option></select>',
|
||||||
sortingColumn1HTML: '<a href="#freeDatas2HTMLSorting0" id="freeDatas2HTMLSorting0">Z (numéro atomique)</a>',
|
sortingColumn1HTML: '<a href="#freeDatas2HTMLSorting0" id="freeDatas2HTMLSorting0">Z (numéro atomique)</a>',
|
||||||
sortingColumn2HTML: '<a href="#freeDatas2HTMLSorting2" id="freeDatas2HTMLSorting2">Symbole</a>',
|
sortingColumn2HTML: '<a href="#freeDatas2HTMLSorting2" id="freeDatas2HTMLSorting2">Symbole</a>',
|
||||||
selectorForPagination: '<label for="freeDatas2HTMLPaginationSelector">Choix de pagination : </label><select name="freeDatas2HTMLPaginationSelector" id="freeDatas2HTMLPaginationSelector"><option value="0">----</option><option value="1">10</option><option value="2">20</option><option value="3">50</option><option value="4">500</option></select>',
|
selectorForPagination: '<label for="freeDatas2HTMLPaginationSelector">Choix de pagination : </label><select name="freeDatas2HTMLPaginationSelector" id="freeDatas2HTMLPaginationSelector"><option value="0">----</option><option value="1">10</option><option value="2">20</option><option value="3">50</option><option value="4">500</option></select>',
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { FreeDatas2HTML, Selector } from "../src/freeDatas2HTML";
|
import { FreeDatas2HTML, Selector } from "../src/freeDatas2HTML";
|
||||||
|
|
||||||
const errors=require("../src/errors.js");
|
const errors=require("../src/errors.js");
|
||||||
const fixtures=require("./fixtures.js");
|
const fixtures=require("./fixtures.js");
|
||||||
|
|
||||||
describe("Test des filtres de données", () =>
|
describe("Test des sélecteurs de données", () =>
|
||||||
{
|
{
|
||||||
let converter: FreeDatas2HTML;
|
let converter: FreeDatas2HTML;
|
||||||
let selector: Selector;
|
let selector: Selector;
|
||||||
|
let selectElement : HTMLInputElement;
|
||||||
|
|
||||||
beforeEach( async () =>
|
beforeEach( async () =>
|
||||||
{
|
{
|
||||||
@ -22,13 +22,18 @@ describe("Test des filtres de données", () =>
|
|||||||
document.body.removeChild(document.getElementById("fixture"));
|
document.body.removeChild(document.getElementById("fixture"));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Test des données reçues pour configurer un filtre.", () =>
|
describe("Test des données de configuration.", () =>
|
||||||
{
|
{
|
||||||
it("Doit générer une erreur, si initialisé sans fournir la liste des champs servant à classer les données.", () =>
|
it("Doit générer une erreur, si initialisé sans avoir au préalable charger des données.", async () =>
|
||||||
{
|
{
|
||||||
|
// Convertisseur non lancé :
|
||||||
converter=new FreeDatas2HTML("CSV");
|
converter=new FreeDatas2HTML("CSV");
|
||||||
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
|
expect(() => { return new Selector(converter, 0, { id:"selector1" }); }).toThrowError(errors.filterNeedDatas);
|
||||||
expect(() => { return new Selector(converter, 0, { id:"selector1" }); }).toThrowError(errors.selectorNeedDatas);
|
// Note : les parseurs vont générer une erreur en amont s'ils ne trouvent pas de noms de champs.
|
||||||
|
// Par contre, ils acceptent de ne pas trouver de données :
|
||||||
|
converter.parser.datas2Parse="Z (numéro atomique),Élément,Symbole,Famille,Abondance des éléments dans la croûte terrestre (μg/k)";
|
||||||
|
await converter.run();
|
||||||
|
expect(() => { return new Selector(converter, 0, { id:"selector1" }); }).toThrowError(errors.filterNeedDatas);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Doit générer une erreur, si le numéro de champ fourni n'existe pas dans les données.", () =>
|
it("Doit générer une erreur, si le numéro de champ fourni n'existe pas dans les données.", () =>
|
||||||
@ -40,24 +45,20 @@ describe("Test des filtres de données", () =>
|
|||||||
|
|
||||||
it("Si un séparateur vide est fourni pour un filtre, il doit être ignoré.", () =>
|
it("Si un séparateur vide est fourni pour un filtre, il doit être ignoré.", () =>
|
||||||
{
|
{
|
||||||
selector=new Selector(converter, 0, { id:"selector1" });
|
selector=new Selector(converter, 0, { id:"selector1" }, "");
|
||||||
selector.separator="";
|
|
||||||
expect(selector.separator).toBeUndefined();
|
expect(selector.separator).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Si toutes les paramètres sont correctes, ils doivent être acceptés.", () =>
|
it("Si toutes les paramètres sont correctes, ils doivent être acceptés.", () =>
|
||||||
{
|
{
|
||||||
const elt=document.getElementById("selector1");
|
expect(() => { selector=new Selector(converter, 2, { id:"selector1" }, ","); return true; }).not.toThrowError();
|
||||||
const selector=new Selector(converter, 2, { id:"selector1" });
|
|
||||||
selector.separator=",";
|
|
||||||
expect(selector.datasFieldNb).toEqual(2);
|
expect(selector.datasFieldNb).toEqual(2);
|
||||||
expect(selector.datasViewElt).toEqual({ id:"selector1", eltDOM:elt });
|
expect(selector.datasViewElt).toEqual({ id:"selector1", eltDOM:document.getElementById("selector1") });
|
||||||
expect(selector.separator).toEqual(",");
|
expect(selector.separator).toEqual(",");
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Création et action des sélecteurs permettant de filter les données affichées.", () =>
|
describe("Création des sélecteurs.", () =>
|
||||||
{
|
{
|
||||||
beforeEach( async () =>
|
beforeEach( async () =>
|
||||||
{
|
{
|
||||||
@ -73,22 +74,34 @@ describe("Test des filtres de données", () =>
|
|||||||
expect(document.getElementById("selector2").innerHTML).toEqual(fixtures.selector2HTML);
|
expect(document.getElementById("selector2").innerHTML).toEqual(fixtures.selector2HTML);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Doit prendre en compte l'éventuel label fourni pour le SELECT.", () =>
|
||||||
|
{
|
||||||
|
selector=new Selector(converter, 4, { id:"selector2" });
|
||||||
|
selector.filter2HTML("Abondance des éléments");
|
||||||
|
expect(document.getElementById("selector2").innerHTML).toEqual(fixtures.selector2HTMLWithLabel);
|
||||||
|
});
|
||||||
|
|
||||||
it("Si des valeurs vides sont présentes dans une champ utilisé pour un sélecteur, elles doivent être ignorées.", async () =>
|
it("Si des valeurs vides sont présentes dans une champ utilisé pour un sélecteur, elles doivent être ignorées.", async () =>
|
||||||
{
|
{
|
||||||
converter=new FreeDatas2HTML("CSV");
|
selector.converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1-emtyinfield.csv" });
|
||||||
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1-emtyinfield.csv" });
|
await selector.converter.run();
|
||||||
await converter.run();
|
|
||||||
selector.filter2HTML();
|
selector.filter2HTML();
|
||||||
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTML);
|
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTML);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Si des espaces entourent certaines valeurs pour ce champ, ils doivent être supprimés.", async () =>
|
||||||
|
{
|
||||||
|
selector.converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datasNeedTrim.csv" });
|
||||||
|
await selector.converter.run();
|
||||||
|
selector.filter2HTML();
|
||||||
|
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selectorHTMLWithTrim);
|
||||||
|
});
|
||||||
|
|
||||||
it("Si un séparateur est fourni, les valeurs distinctes extraites de ce champ doivent le prendre en compte.", async () =>
|
it("Si un séparateur est fourni, les valeurs distinctes extraites de ce champ doivent le prendre en compte.", async () =>
|
||||||
{
|
{
|
||||||
converter=new FreeDatas2HTML("CSV");
|
|
||||||
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1+tagsfield.csv" });
|
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1+tagsfield.csv" });
|
||||||
await converter.run();
|
await converter.run();
|
||||||
selector=new Selector(converter, 5, { id:"selector1" });
|
selector=new Selector(converter, 5, { id:"selector1" }, "|");
|
||||||
selector.separator="|";
|
|
||||||
selector.filter2HTML();
|
selector.filter2HTML();
|
||||||
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTMLWithSeparator);
|
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTMLWithSeparator);
|
||||||
});
|
});
|
||||||
@ -109,93 +122,130 @@ describe("Test des filtres de données", () =>
|
|||||||
};
|
};
|
||||||
converter.datasSortingFunctions=[{ datasFieldNb: 4, sort:mySort }];
|
converter.datasSortingFunctions=[{ datasFieldNb: 4, sort:mySort }];
|
||||||
selector=new Selector(converter, 4, { id:"selector1" });
|
selector=new Selector(converter, 4, { id:"selector1" });
|
||||||
selector.separator="|";
|
|
||||||
selector.filter2HTML();
|
selector.filter2HTML();
|
||||||
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTMLWithFunction);
|
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTMLWithFunction);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Doit générer une erreur si une donnée est testée pour un sélecteur non correctement initialisé.", () =>
|
it("Doit générer une erreur, si aucune donnée n'a été trouvée pour créer le <SELECT>.", async () =>
|
||||||
{
|
{
|
||||||
let data2Test= {
|
selector.converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datasEmptyField.csv" });
|
||||||
"Z (numéro atomique)" : "53",
|
await selector.converter.run();
|
||||||
"Élément": "Iode",
|
expect(() => { return selector.filter2HTML(); }).toThrowError(errors.selectorFieldIsEmpty);
|
||||||
"Symbole": "I",
|
});
|
||||||
"Famille": "Halogène",
|
});
|
||||||
"Abondance des éléments dans la croûte terrestre (μg/k)": "> 1 et < 100 000",
|
|
||||||
};
|
describe("Manipulation des sélecteurs et filtre des données.", () =>
|
||||||
expect(() => { selector.dataIsOk(data2Test); }).toThrowError(errors.selectorCheckIsOkFail);
|
{
|
||||||
|
beforeEach( async () =>
|
||||||
|
{
|
||||||
|
selector=new Selector(converter, 3, { id:"selector1" }); // filtre sur le champ "famille"
|
||||||
|
selector.filter2HTML();
|
||||||
|
selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("La manipulation d'un sélecteur doit enregistrer la valeur sélectionnée et appeler la fonction actualisant l'affichage.", () =>
|
||||||
|
{
|
||||||
|
spyOn(converter, "refreshView");
|
||||||
|
|
||||||
|
selectElement.value="4";
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
expect(selector.selectedValue).toEqual(3);
|
||||||
|
expect(converter.refreshView).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
selectElement.value="0"; // 0 = annulation de ce filtre, puisqu'aucune valeur choisie
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
expect(selector.selectedValue).toBeUndefined();
|
||||||
|
expect(converter.refreshView).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit générer une erreur si une donnée est testée sur un sélecteur non affiché dans la page.", () =>
|
||||||
|
{
|
||||||
|
selector=new Selector(converter, 3, { id:"selector1" });
|
||||||
|
expect(() => { selector.dataIsOk({ "nom" : "oui" }); }).toThrowError(errors.filterCheckIsOkFail);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit toujours retourner true si aucune des valeurs du filtre n'est sélectionnée.", () =>
|
||||||
|
{
|
||||||
|
// Le filtre est sur 0 par défaut
|
||||||
|
expect(selector.dataIsOk({ "nom" : "oui" })).toBeTrue();
|
||||||
|
// Même comportement après un retour :
|
||||||
|
selectElement.value="2";
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
selectElement.value="0";
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
expect(selector.dataIsOk({ "nom" : "oui" })).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit générer une erreur si la valeur sélectionnée n'est pas trouvé dans la liste des valeurs connues.", () =>
|
||||||
|
{
|
||||||
|
selectElement.innerHTML=fixtures.selectorHTMLWithFakeItem;
|
||||||
|
selectElement.value="13";
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
expect(() => { selector.dataIsOk({ "nom" : "oui" }); }).toThrowError(errors.selectorSelectedIndexNotFound);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Doit retourner false, si la donnée testée ne possède pas le champ sur lequel les données sont filtrées.", () =>
|
it("Doit retourner false, si la donnée testée ne possède pas le champ sur lequel les données sont filtrées.", () =>
|
||||||
{
|
{
|
||||||
selector.filter2HTML();
|
selectElement.value="2";
|
||||||
let selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
selectElement.value="4";
|
expect(selector.dataIsOk({ "nom" : "rémi sans famille" })).toBeFalse();
|
||||||
let data2Test= { // le champ à filtrer ("Famille") est manquant
|
|
||||||
"Z (numéro atomique)" : "53",
|
|
||||||
"Élément": "Iode",
|
|
||||||
"Symbole": "I",
|
|
||||||
"Abondance des éléments dans la croûte terrestre (μg/k)": "> 1 et < 100 000",
|
|
||||||
};
|
|
||||||
expect(selector.dataIsOk(data2Test)).toBeFalse();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Doit retourner false, si une donnée testée ne correspond pas à la valeur sélectionnée pour le filtre.", () =>
|
it("Doit retourner false, si une donnée testée ne correspond pas à la valeur sélectionnée pour le filtre.", async () =>
|
||||||
{
|
{
|
||||||
selector.filter2HTML();
|
selectElement.value="4"; // = Halogène
|
||||||
let selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
selectElement.value="4";
|
expect(selector.dataIsOk({ "Famille": "Hallo Eugène !" })).toBeFalse();
|
||||||
let data2Test= {
|
|
||||||
"Z (numéro atomique)" : "53",
|
|
||||||
"Élément": "Iode",
|
|
||||||
"Symbole": "I",
|
|
||||||
"Famille": "Halogene", // manque un accent :)
|
|
||||||
"Abondance des éléments dans la croûte terrestre (μg/k)": "> 1 et < 100 000",
|
|
||||||
};
|
|
||||||
expect(selector.dataIsOk(data2Test)).toBeFalse();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Doit retourner true, si une donnée testée correspond pas à la valeur sélectionnée pour ce filtre.", () =>
|
it("Doit retourner true, si une donnée testée correspond pas à la valeur sélectionnée pour ce filtre.", () =>
|
||||||
{
|
{
|
||||||
selector.filter2HTML();
|
|
||||||
let selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
|
||||||
selectElement.value="4";
|
|
||||||
let data2Test= {
|
|
||||||
"Z (numéro atomique)" : "53",
|
|
||||||
"Élément": "Iode",
|
|
||||||
"Symbole": "I",
|
|
||||||
"Famille": "Halogène",
|
|
||||||
"Abondance des éléments dans la croûte terrestre (μg/k)": "> 1 et < 100 000",
|
|
||||||
};
|
|
||||||
expect(selector.dataIsOk(data2Test)).toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Doit toujours retourner true, si aucune valeur sélectionnée dans la liste.", () =>
|
|
||||||
{
|
|
||||||
selector.filter2HTML();
|
|
||||||
let data2Test= {
|
|
||||||
"Z (numéro atomique)" : "530",
|
|
||||||
"Élément": "Yode",
|
|
||||||
"Symbole": "L",
|
|
||||||
"Famille": "Halogene",
|
|
||||||
"Abondance des éléments": "> 1 et < 100 000",
|
|
||||||
};
|
|
||||||
expect(selector.dataIsOk(data2Test)).toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("La manipulation d'un sélecteur doit appeler la fonction actualisant l'affichage, y compris pour supprimer ce filtre (0).", () =>
|
|
||||||
{
|
|
||||||
selector=new Selector(converter, 3, { id:"selector1" });
|
|
||||||
selector.filter2HTML();
|
|
||||||
converter.datasFilters=[selector];
|
|
||||||
spyOn(converter, "refreshView");
|
|
||||||
let selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
|
||||||
selectElement.value="4";
|
selectElement.value="4";
|
||||||
selectElement.dispatchEvent(new Event('change'));
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
expect(converter.refreshView).toHaveBeenCalledTimes(1);
|
expect(selector.dataIsOk({ "Famille": "Halogène" })).toBeTrue();
|
||||||
selectElement.value="0";
|
// Y compris si entouré d'espaces :
|
||||||
|
expect(selector.dataIsOk({ "Famille": " Halogène " })).toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Manipulation des sélecteurs avec séparateur.", () =>
|
||||||
|
{
|
||||||
|
beforeEach( async () =>
|
||||||
|
{
|
||||||
|
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1+tagsfield.csv" });
|
||||||
|
await converter.run();
|
||||||
|
selector=new Selector(converter, 5, { id:"selector1" }, "|"); // filtre sur le champ "Étiquettes"
|
||||||
|
selector.filter2HTML();
|
||||||
|
selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit retourner false, si la donnée testée ne possède pas le champ sur lequel les données sont filtrées.", () =>
|
||||||
|
{
|
||||||
|
selectElement.value="2";
|
||||||
selectElement.dispatchEvent(new Event('change'));
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
expect(converter.refreshView).toHaveBeenCalledTimes(2);
|
expect(selector.dataIsOk({ "nom" : "oui" })).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit retourner false, si une donnée testée ne correspond pas à la valeur sélectionnée pour le filtre.", () =>
|
||||||
|
{
|
||||||
|
selectElement.value="4"; // = Exemple3
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
expect(selector.dataIsOk({ "Étiquettes": "Mauvais exemple" })).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Doit retourner true, si une donnée testée correspond pas à la valeur sélectionnée pour ce filtre.", () =>
|
||||||
|
{
|
||||||
|
selectElement.value="4";
|
||||||
|
selectElement.dispatchEvent(new Event('change'));
|
||||||
|
expect(selector.dataIsOk({ "Étiquettes": "Exemple3" })).toBeTrue();
|
||||||
|
// Même pas seule :
|
||||||
|
expect(selector.dataIsOk({ "Étiquettes": "Exemple3|Exemple1|Exemple9" })).toBeTrue();
|
||||||
|
expect(selector.dataIsOk({ "Étiquettes": "Exemple0|Exemple3|Exemple2" })).toBeTrue();
|
||||||
|
expect(selector.dataIsOk({ "Étiquettes": "Exemple0|Exemple4|Exemple3" })).toBeTrue();
|
||||||
|
// Y compris si entourée d'espaces :
|
||||||
|
expect(selector.dataIsOk({ "Étiquettes": "Exemple0|Exemple4| Exemple3 " })).toBeTrue();
|
||||||
|
expect(selector.dataIsOk({ "Étiquettes": " Exemple3 " })).toBeTrue();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user