FreeDatas2HTML/src/SearchEngine.ts

131 lines
5.1 KiB
TypeScript

const errors=require("./errors.js");
import { DOMElement, Filters } from "./interfaces";
import { FreeDatas2HTML } from "./FreeDatas2HTML";
export class SearchEngine implements Filters
{
private _converter: FreeDatas2HTML;
private _datasViewElt: DOMElement={ id: "", eltDOM: undefined };
private _btnTxt: string="Search";
private _fields2Search: string[]=[];
public label: string="";
public nbCharsForSearch : number=0;
public placeholder: string="";
public automaticSearch: boolean=false;
private _inputValue: string="";
// Injection de la classe principale, mais uniquement si des données ont été importées
constructor(converter: FreeDatas2HTML, elt: DOMElement, fields?: number[])
{
if(converter.fields.length === 0 || converter.datas.length === 0)
throw new Error(errors.filterNeedDatas);
else
{
this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt);
this._converter=converter;
// Les champs sur lesquels les recherches seront lancées.
// Ils doivent se trouver dans les données parsées, mais peuvent ne pas être affichés dans les données.
// Un tableau vide est accepté et signifie que les recherches se feront sur tous les champs.
if(fields !== undefined && fields.length !== 0)
{
for(let field of fields)
{
if(! this._converter.checkFieldExist(field))
throw new Error(errors.searchFieldNotFound);
else
this._fields2Search.push(this.converter.fields[field]);
}
}
else
this._fields2Search=this._converter.fields;
}
}
get converter() : FreeDatas2HTML
{
return this._converter;
}
get datasViewElt() : DOMElement
{
return this._datasViewElt;
}
set btnTxt(txt: string)
{
if(txt.trim() !== "" && txt.length <= 30)
this._btnTxt=txt;
}
get btnTxt(): string
{
return this._btnTxt;
}
get inputValue() : string
{
return this._inputValue;
}
get fields2Search() : string[]
{
return this._fields2Search;
}
// Création du champ de recherche dans le DOM.
public filter2HTML() : void
{
if(this.nbCharsForSearch >0 && this.placeholder === "")
this.placeholder="Please enter at least NB characters."
// Pas de minlength ou de required, car l'envoi d'une recherche vide doit permettre d'annuler le filtre.
let html=`<form id="freeDatas2HTMLSearch">`;
if(this.label !== "")
html+=`<label for="freeDatas2HTMLSearchTxt">${this.label}</label>`;
html+=`<input type="search" id="freeDatas2HTMLSearchTxt" name="freeDatas2HTMLSearchTxt"`;
if(this.nbCharsForSearch > 0)
html+=` placeholder="${this.placeholder.replace("NB", ""+this.nbCharsForSearch)}"`;
else if(this.placeholder !== "")
html+=` placeholder="${this.placeholder}"`;
html+=`>&nbsp;<input type="submit" id="freeDatas2HTMLSearchBtn" value="${this._btnTxt}"></form>`;
this. _datasViewElt.eltDOM!.innerHTML=html;// "!" car l'existence de "eltDOM" est testé par le constructeur
// L'affichage est actualisé quand l'éventuel nombre de caractères est atteint ou quand le champ est vide, car cela permet d'annuler ce filtre.
const searchInput=document.getElementById("freeDatas2HTMLSearchTxt") as HTMLInputElement, mySearch=this;
searchInput.addEventListener("input", function(e)
{
e.preventDefault();
mySearch._inputValue=searchInput.value;
let searchLength=searchInput.value.length;
if(mySearch.automaticSearch && (mySearch.nbCharsForSearch === 0 || ( searchLength === 0) || (searchLength >= mySearch.nbCharsForSearch)))
mySearch._converter.refreshView();
});
/// Afficher un message quand le nombre de caractères n'est pas atteint ?
const searchBtn=document.getElementById("freeDatas2HTMLSearchBtn") as HTMLInputElement;
searchBtn.addEventListener("click", function(e)
{
e.preventDefault();
let searchLength=searchInput.value.length;
if((mySearch.nbCharsForSearch === 0 || ( searchLength === 0) || (searchLength >= mySearch.nbCharsForSearch)))
mySearch._converter.refreshView();
});
}
public dataIsOk(data: {[index: string]:string}) : boolean
{
// Pas de valeur sélectionnée = pas de filtre sur ce champ
if(this._inputValue.length === 0)
return true;
// Sinon, on cherche la valeur saisie dans les champs définis :
for(let field in data)
{
if(this._fields2Search.indexOf(field) !== -1)
{
// Attention, recherche insensible à la casse, mais aux accents, etc.
if(data[field].toLowerCase().indexOf(this._inputValue.toLowerCase()) !== -1)
return true;
}
}
return false;
}
}