2021-10-21 17:09:57 +02:00
const { compare } = require ( 'natural-orderby' ) ;
const errors = require ( "./errors.js" ) ;
2021-10-18 10:37:44 +02:00
import { DOMElement , Selectors } from "./interfaces" ;
2021-10-25 10:53:54 +02:00
import { FreeDatas2HTML } from "./FreeDatas2HTML" ;
2021-09-17 18:02:45 +02:00
export class Selector implements Selectors
{
2021-10-21 17:09:57 +02:00
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 = "" ;
2021-09-20 11:09:30 +02:00
2021-10-21 17:09:57 +02:00
// 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 )
2021-09-17 18:02:45 +02:00
{
2021-10-26 18:02:43 +02:00
if ( converter . fields . length === 0 || converter . datas . length === 0 )
2021-10-21 17:09:57 +02:00
throw new Error ( errors . filterNeedDatas ) ;
2021-09-22 17:12:00 +02:00
else if ( ! converter . checkFieldExist ( Number ( datasFieldNb ) ) )
throw new Error ( errors . selectorFieldNotFound ) ;
2021-09-17 18:02:45 +02:00
else
2021-09-22 17:12:00 +02:00
{
2021-10-21 17:09:57 +02:00
this . _datasViewElt = FreeDatas2HTML . checkInDOMById ( elt ) ;
2021-09-17 18:02:45 +02:00
this . _converter = converter ;
2021-09-22 17:12:00 +02:00
this . _datasFieldNb = datasFieldNb ;
2021-10-21 17:09:57 +02:00
// Pas de trim(), car l'espace peut être le séparateur :
if ( separator !== undefined && separator !== "" )
this . _separator = separator ;
2021-09-22 17:12:00 +02:00
}
2021-09-17 18:02:45 +02:00
}
2021-09-22 17:12:00 +02:00
2021-10-21 17:09:57 +02:00
get converter ( ) : FreeDatas2HTML
2021-09-17 18:02:45 +02:00
{
2021-10-21 17:09:57 +02:00
return this . _converter ;
2021-09-17 18:02:45 +02:00
}
get datasViewElt ( ) : DOMElement
{
return this . _datasViewElt ;
}
2021-09-22 17:12:00 +02:00
get datasFieldNb ( ) : number
2021-09-17 18:02:45 +02:00
{
return this . _datasFieldNb ;
}
2021-09-22 17:12:00 +02:00
2021-10-21 17:09:57 +02:00
get name ( ) : string
{
return this . _name ;
}
get selectedValue ( ) : number | undefined
{
return this . _selectedValue ;
}
2021-09-22 17:12:00 +02:00
get separator ( ) : string | undefined
2021-09-17 18:02:45 +02:00
{
2021-09-22 17:12:00 +02:00
return this . _separator ;
2021-09-17 18:02:45 +02:00
}
2021-10-21 17:09:57 +02:00
get values ( ) : string [ ]
2021-09-17 18:02:45 +02:00
{
2021-10-21 17:09:57 +02:00
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 )
2021-09-17 18:02:45 +02:00
{
2021-10-21 17:09:57 +02:00
let checkedValue ;
if ( this . _separator === undefined )
2021-09-17 18:02:45 +02:00
{
2021-10-21 17:09:57 +02:00
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 ) ;
2021-09-17 18:02:45 +02:00
}
2021-10-21 17:09:57 +02:00
else
2021-09-17 18:02:45 +02:00
{
2021-10-21 17:09:57 +02:00
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 ) ;
}
2021-09-17 18:02:45 +02:00
}
}
2021-10-21 17:09:57 +02:00
if ( this . _values . length === 0 ) // possible si uniquement des valeurs vides pour ce champ
throw new Error ( errors . selectorFieldIsEmpty ) ;
2021-09-17 18:02:45 +02:00
else
2021-10-21 17:09:57 +02:00
{
// 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
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 ( ) ;
} ) ;
}
2021-09-17 18:02:45 +02:00
}
2021-10-21 17:09:57 +02:00
public dataIsOk ( data : { [ index : string ] : string } ) : boolean
2021-09-20 11:09:30 +02:00
{
2021-10-21 17:09:57 +02:00
// 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 )
2021-09-17 18:02:45 +02:00
return true ;
2021-10-21 17:09:57 +02:00
if ( this . _values [ this . _selectedValue ] === undefined ) // théoriquement impossible, mais cela vient du client...
2021-09-17 18:02:45 +02:00
throw new Error ( errors . selectorSelectedIndexNotFound ) ;
2021-09-20 11:09:30 +02:00
2021-10-21 17:09:57 +02:00
// Si le champ est absent pour un enregistrement, il est refusé
if ( data [ this . _name ] === undefined )
2021-09-20 11:09:30 +02:00
return false ;
2021-09-17 18:02:45 +02:00
2021-10-21 17:09:57 +02:00
const selectedValueTxt = this . _values [ this . _selectedValue ] ;
2021-09-17 18:02:45 +02:00
if ( this . _separator === undefined )
{
2021-10-21 17:09:57 +02:00
if ( data [ this . _name ] . trim ( ) !== selectedValueTxt )
2021-09-17 18:02:45 +02:00
return false ;
else
return true ;
}
else
{
let find = false ;
2021-10-21 17:09:57 +02:00
let checkedValues = data [ this . _name ] . split ( this . _separator ) ;
2021-10-07 17:15:35 +02:00
for ( let value of checkedValues )
2021-09-17 18:02:45 +02:00
{
2021-10-21 17:09:57 +02:00
if ( value . trim ( ) === selectedValueTxt )
2021-09-17 18:02:45 +02:00
{
find = true ;
break ;
}
}
return find ;
}
}
}