FreeDatas2HTML/src/Selector.ts

166 lines
6.2 KiB
TypeScript

const { compare }=require('natural-orderby');
const errors=require("./errors.js");
import { DOMElement, Selectors } from "./interfaces";
import { FreeDatas2HTML } from "./FreeDatas2HTML";
export class Selector implements Selectors
{
private _converter: FreeDatas2HTML;
private _datasFieldNb: number;
private _datasViewElt: DOMElement={ id: "", eltDOM: undefined };
private _selectedValue: number|undefined=undefined;
private _separator: string|undefined;
private _values: string[]=[];
private _name: string="";
// Injection de la classe principale, mais uniquement si des données ont été importées.
// Le champ duquel le sélecteur tire ses données doit exister.
constructor(converter: FreeDatas2HTML, datasFieldNb: number, elt: DOMElement, separator?: string)
{
if(converter.fields.length === 0 || converter.datas.length === 0)
throw new Error(errors.filterNeedDatas);
else if(! converter.checkFieldExist(Number(datasFieldNb)))
throw new Error(errors.selectorFieldNotFound);
else
{
this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt);
this._converter=converter;
this._datasFieldNb=datasFieldNb;
// Pas de trim(), car l'espace peut être le séparateur :
if(separator !== undefined && separator !== "")
this._separator=separator;
}
}
get converter() : FreeDatas2HTML
{
return this._converter;
}
get datasViewElt() : DOMElement
{
return this._datasViewElt;
}
get datasFieldNb() : number
{
return this._datasFieldNb;
}
get name() : string
{
return this._name;
}
get selectedValue() : number|undefined
{
return this._selectedValue;
}
get separator() : string|undefined
{
return this._separator;
}
get values(): string[]
{
return this._values;
}
// Création du <select> dans le DOM correspondant au filtre
public filter2HTML(label:string="") : void
{
this._name=this._converter.fields![this._datasFieldNb]; // "!", car l'existence du champ est testé par le constructeur.
for (let row of this._converter.datas)
{
let checkedValue;
if(this._separator === undefined)
{
checkedValue=row[this._name].trim(); // trim() évite des problèmes de classement des éléments du SELECT.
if(checkedValue !== "" && this._values.indexOf(checkedValue) === -1)
this._values.push(checkedValue);
}
else
{
let checkedValues=row[this._name].split(this._separator);
for(let value of checkedValues)
{
checkedValue=value.trim();
if(checkedValue !== "" && this._values.indexOf(checkedValue) === -1)
this._values.push(checkedValue);
}
}
}
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 :
if(this._converter.getSortingFunctionForField(this._datasFieldNb) !== undefined)
this._values.sort(this._converter.getSortingFunctionForField(this._datasFieldNb)!.sort); // sans le "!" : TS2532: Object is possibly 'undefined' ???
else
this._values.sort(compare());
// Création et injection du SELECT dans le DOM :
label=(label === "") ? this._name : label;
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.
for(let i=0; i< this._values.length; i++)
selectorsHTML+="<option value='"+(i+1)+"'>"+this._values[i]+"</option>";
selectorsHTML+="</select>";
this. _datasViewElt.eltDOM!.innerHTML=selectorsHTML;// "!", car l'existence de "eltDOM" est testé par le constructeur.
// Actualisation de l'affichage lorsqu'une valeur est sélectionnée :
const selectElement=document.getElementById("freeDatas2HTML_"+this._datasViewElt.id) as HTMLInputElement, mySelector=this;
selectElement.addEventListener("change", function(e)
{
if(selectElement.value === "0")
mySelector._selectedValue=undefined;
else
mySelector._selectedValue=parseInt(selectElement.value,10)-1;
mySelector._converter.refreshView();
});
}
}
public dataIsOk(data: {[index: string]:string}) : boolean
{
// Permet de vérifier que filter2HTML() a été préalablement appelée :
if(this._name === "")
throw new Error(errors.filterCheckIsOkFail);
// Pas de valeur sélectionnée = pas de filtre sur ce champ
if(this._selectedValue === undefined)
return true;
if(this._values[this._selectedValue] === undefined) // théoriquement impossible, mais cela vient du client...
throw new Error(errors.selectorSelectedIndexNotFound);
// Si le champ est absent pour un enregistrement, il est refusé
if(data[this._name] === undefined)
return false;
const selectedValueTxt=this._values[this._selectedValue];
if(this._separator === undefined)
{
if(data[this._name].trim() !== selectedValueTxt)
return false;
else
return true;
}
else
{
let find=false;
let checkedValues=data[this._name].split(this._separator);
for(let value of checkedValues)
{
if(value.trim() === selectedValueTxt)
{
find=true;
break;
}
}
return find;
}
}
}