2021-08-10 15:56:53 +02:00
|
|
|
const Papa = require("papaparse");
|
2021-08-30 16:48:48 +02:00
|
|
|
const errors = require("./errors.js");
|
2021-08-10 15:56:53 +02:00
|
|
|
|
|
|
|
import { papaParseDatas, papaParseErrors, papaParseMeta } from "./papaParseInterfaces";
|
2021-08-30 18:06:59 +02:00
|
|
|
import { domElement, selectors } from "./freeDatas2HTMLInterfaces";
|
2021-08-05 18:24:37 +02:00
|
|
|
|
2021-08-30 18:06:59 +02:00
|
|
|
export class freeDatas2HTML
|
2021-08-05 18:24:37 +02:00
|
|
|
{
|
2021-08-10 15:56:53 +02:00
|
|
|
private _datasViewElt: domElement = { id:"", eltDOM:undefined };
|
|
|
|
private _datasSourceUrl: string = "";
|
2021-08-05 18:24:37 +02:00
|
|
|
private _datasSelectors: selectors[] = [];
|
2021-08-10 15:56:53 +02:00
|
|
|
|
|
|
|
public parseMeta: papaParseMeta|undefined = undefined;
|
|
|
|
public parseDatas: papaParseDatas[] = [];
|
|
|
|
public parseErrors: papaParseErrors[] = [];
|
2021-08-12 16:05:12 +02:00
|
|
|
public datasHTML: string = "";
|
2021-08-30 17:42:09 +02:00
|
|
|
public stopIfParseErrors: boolean = false;
|
2021-08-05 18:24:37 +02:00
|
|
|
|
2021-08-10 15:56:53 +02:00
|
|
|
set datasViewElt(elt: domElement)
|
2021-08-05 18:24:37 +02:00
|
|
|
{
|
2021-08-10 15:56:53 +02:00
|
|
|
let checkContainerExist=document.getElementById(elt.id);
|
|
|
|
if(checkContainerExist === null)
|
|
|
|
throw new Error(errors.elementNotFound+elt.id);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this._datasViewElt.id=elt.id;
|
|
|
|
this._datasViewElt.eltDOM=checkContainerExist;
|
|
|
|
}
|
2021-08-05 18:24:37 +02:00
|
|
|
}
|
|
|
|
|
2021-08-10 15:56:53 +02:00
|
|
|
set datasSourceUrl(url: string)
|
2021-08-05 18:24:37 +02:00
|
|
|
{
|
2021-08-10 15:56:53 +02:00
|
|
|
if(url.trim().length === 0)
|
|
|
|
throw new Error(errors.needUrl);
|
|
|
|
else
|
|
|
|
this._datasSourceUrl=url.trim();
|
2021-08-05 18:24:37 +02:00
|
|
|
}
|
2021-08-12 16:05:12 +02:00
|
|
|
|
2021-08-11 15:24:00 +02:00
|
|
|
set datasSelectors(selectionElts: selectors[])
|
2021-08-05 18:24:37 +02:00
|
|
|
{
|
2021-08-30 17:42:09 +02:00
|
|
|
this._datasSelectors=[];
|
2021-08-10 15:56:53 +02:00
|
|
|
let checkContainerExist: HTMLElement|null;
|
2021-08-11 15:24:00 +02:00
|
|
|
for(let i = 0; i < selectionElts.length; i++)
|
2021-08-06 11:41:28 +02:00
|
|
|
{
|
2021-08-11 15:24:00 +02:00
|
|
|
checkContainerExist=document.getElementById(selectionElts[i].id);
|
2021-08-06 11:41:28 +02:00
|
|
|
if(checkContainerExist === null)
|
2021-08-12 17:43:34 +02:00
|
|
|
console.error(errors.elementNotFound+selectionElts[i].id);
|
2021-08-30 18:06:59 +02:00
|
|
|
else if(Number.isInteger( selectionElts[i].datasFielNb) === false || selectionElts[i].datasFielNb < 0)
|
2021-08-12 17:43:34 +02:00
|
|
|
console.error(errors.needNaturalNumber);
|
2021-08-06 11:41:28 +02:00
|
|
|
else
|
2021-08-12 17:43:34 +02:00
|
|
|
{
|
|
|
|
selectionElts[i].eltDOM=checkContainerExist;
|
|
|
|
this._datasSelectors.push(selectionElts[i]);
|
|
|
|
}
|
2021-08-06 11:41:28 +02:00
|
|
|
}
|
2021-08-05 18:24:37 +02:00
|
|
|
}
|
|
|
|
|
2021-08-12 17:43:34 +02:00
|
|
|
get datasSelectors() : selectors[]
|
|
|
|
{
|
|
|
|
return this._datasSelectors;
|
|
|
|
}
|
|
|
|
|
2021-08-10 15:56:53 +02:00
|
|
|
public async parse(): Promise<any>
|
|
|
|
{
|
2021-08-11 15:24:00 +02:00
|
|
|
const converter=this;
|
2021-08-10 15:56:53 +02:00
|
|
|
return new Promise((resolve,reject) =>
|
|
|
|
{
|
2021-08-11 15:24:00 +02:00
|
|
|
if(converter._datasSourceUrl !== "" )
|
2021-08-10 15:56:53 +02:00
|
|
|
{
|
2021-08-11 15:24:00 +02:00
|
|
|
Papa.parse(converter._datasSourceUrl,
|
2021-08-10 15:56:53 +02:00
|
|
|
{
|
2021-08-11 15:24:00 +02:00
|
|
|
quoteChar: '"',
|
|
|
|
header: true,
|
|
|
|
complete: function(results :any)
|
2021-08-10 15:56:53 +02:00
|
|
|
{
|
2021-08-12 16:05:12 +02:00
|
|
|
converter.parseErrors=results.errors;
|
2021-08-10 15:56:53 +02:00
|
|
|
converter.parseDatas=results.data;
|
2021-08-12 18:38:09 +02:00
|
|
|
// Attention, papaParse peut accepter un nom de colonne vide
|
|
|
|
let realFields: string[]=[];
|
|
|
|
for(let i in results.meta.fields)
|
|
|
|
{
|
|
|
|
if(results.meta.fields[i].trim() !== "")
|
|
|
|
realFields.push(results.meta.fields[i]);
|
|
|
|
}
|
|
|
|
results.meta.fields=realFields;
|
|
|
|
converter.parseMeta=results.meta;
|
2021-08-10 15:56:53 +02:00
|
|
|
resolve(true);
|
|
|
|
},
|
|
|
|
error:function(error :any)
|
|
|
|
{
|
|
|
|
reject(new Error(errors.parserFail));
|
|
|
|
},
|
|
|
|
download: true,
|
2021-08-11 15:24:00 +02:00
|
|
|
skipEmptyLines: true,
|
2021-08-10 15:56:53 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
2021-08-11 15:24:00 +02:00
|
|
|
reject(new Error(errors.needUrl));
|
2021-08-10 15:56:53 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public async run(): Promise<any>
|
|
|
|
{
|
|
|
|
if (this._datasViewElt.eltDOM === undefined)
|
|
|
|
throw new Error(errors.needDatasElt);
|
2021-08-12 16:05:12 +02:00
|
|
|
if(this._datasSourceUrl === "" )
|
2021-08-10 15:56:53 +02:00
|
|
|
throw new Error(errors.needUrl);
|
2021-08-12 17:43:34 +02:00
|
|
|
|
2021-08-11 15:24:00 +02:00
|
|
|
await this.parse();
|
|
|
|
|
2021-08-30 17:42:09 +02:00
|
|
|
if(this.parseDatas.length === 0 || this.parseMeta!.fields === undefined) // je force avec "!", car l'existence de parseMeta est certaine après parse().
|
2021-08-12 17:57:05 +02:00
|
|
|
throw new Error(errors.datasNotFound);
|
2021-08-12 18:38:09 +02:00
|
|
|
else if(this.stopIfParseErrors && this.parseErrors.length!==0)
|
|
|
|
console.error(this.parseErrors);
|
2021-08-11 15:24:00 +02:00
|
|
|
else
|
2021-08-10 15:56:53 +02:00
|
|
|
{
|
2021-08-12 16:05:12 +02:00
|
|
|
let converter=this;
|
2021-08-11 15:24:00 +02:00
|
|
|
// Affichage initial des données du fichier
|
2021-08-12 18:38:09 +02:00
|
|
|
this.datasHTML=this.createDatasHTML(this.parseMeta!.fields, this.parseDatas);
|
2021-08-11 15:24:00 +02:00
|
|
|
this._datasViewElt.eltDOM.innerHTML=this.datasHTML;
|
|
|
|
|
|
|
|
// Si demandé, création des listes permettant de filter les données
|
|
|
|
if(this._datasSelectors.length > 0)
|
2021-08-10 15:56:53 +02:00
|
|
|
{
|
2021-08-11 15:24:00 +02:00
|
|
|
// Les colonnes devant servir de filtre existent-elles dans le fichier ?
|
|
|
|
let selectorsHTML : string [] = [];
|
|
|
|
for(let i in this._datasSelectors)
|
2021-08-10 15:56:53 +02:00
|
|
|
{
|
2021-08-30 18:06:59 +02:00
|
|
|
if(this._datasSelectors[i].datasFielNb > (this.parseMeta!.fields.length-1))
|
2021-08-11 15:24:00 +02:00
|
|
|
throw new Error(errors.selectorFieldNotFound);
|
|
|
|
else
|
2021-08-10 15:56:53 +02:00
|
|
|
{
|
2021-08-30 18:06:59 +02:00
|
|
|
let values=[], colName=this.parseMeta!.fields[this._datasSelectors[i].datasFielNb];
|
2021-08-11 15:24:00 +02:00
|
|
|
for (let row in this.parseDatas)
|
|
|
|
{
|
2021-08-12 16:05:12 +02:00
|
|
|
if(values.indexOf(this.parseDatas[row][colName].trim()) === -1)
|
|
|
|
values.push(this.parseDatas[row][colName].trim());
|
|
|
|
// Des espaces gauche pourraient fausser le classement alphabétique.
|
|
|
|
// Donc réutiliser le trim() lorsque l'on filtre l'affichage des données.
|
2021-08-11 15:24:00 +02:00
|
|
|
}
|
|
|
|
if(values.length > 0)
|
|
|
|
{
|
2021-08-30 17:42:09 +02:00
|
|
|
values.sort(); // à revoir, car gère mal la casse, les nombres, etc.
|
|
|
|
this._datasSelectors[i].name=colName;
|
2021-08-11 15:24:00 +02:00
|
|
|
this._datasSelectors[i].values=values;
|
2021-08-30 18:06:59 +02:00
|
|
|
selectorsHTML[i]="<label for='freeDatas2HTMLSelector"+i+"'>"+colName+" : </label><select name='freeDatas2HTMLSelector"+i+"' id='freeDatas2HTMLSelector"+i+"'><option value='0'>----</option>";
|
2021-08-11 15:24:00 +02:00
|
|
|
for(let j in values)
|
|
|
|
selectorsHTML[i]+="<option value='"+(Number(j)+1)+"'>"+values[j]+"</option>";
|
|
|
|
selectorsHTML[i]+="</select>";
|
2021-08-12 16:05:12 +02:00
|
|
|
this._datasSelectors[i].eltDOM!.innerHTML=selectorsHTML[i];
|
2021-08-30 18:06:59 +02:00
|
|
|
let selectElement = document.getElementById("freeDatas2HTMLSelector"+i) as HTMLInputElement;
|
2021-08-11 17:25:56 +02:00
|
|
|
selectElement.addEventListener('change', function(e)
|
|
|
|
{
|
|
|
|
converter.datasHTML=converter.createDatasHTML(converter.parseMeta!.fields as string[], converter.parseDatas);
|
|
|
|
converter._datasViewElt.eltDOM!.innerHTML=converter.datasHTML;
|
|
|
|
});
|
2021-08-11 15:24:00 +02:00
|
|
|
}
|
2021-08-10 15:56:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-11 15:24:00 +02:00
|
|
|
return true;
|
2021-08-11 17:25:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private createDatasHTML(fields: string[], datas: any[]) : string
|
|
|
|
{
|
2021-08-12 16:05:12 +02:00
|
|
|
// Je vérifie si des valeurs ont été sélectionnées pour filter les données.
|
|
|
|
let checkSelectorExist: HTMLSelectElement|null, filters: any[] = [];
|
2021-08-11 17:25:56 +02:00
|
|
|
for(let i in this._datasSelectors)
|
|
|
|
{
|
2021-08-12 16:05:12 +02:00
|
|
|
// Attention : je peux avoir des _datasSelectors fournis, mais pas de liste dans le DOM si aucune donnée ou autre problème.
|
|
|
|
checkSelectorExist=document.querySelector("#"+ this._datasSelectors[i].id+" select");
|
|
|
|
if(checkSelectorExist != null && checkSelectorExist.value != "0")
|
|
|
|
filters.push({ field: this._datasSelectors[i].name, value: this._datasSelectors[i].values![checkSelectorExist.selectedIndex-1] });
|
2021-08-30 17:42:09 +02:00
|
|
|
// Attention : si on récupère innerHTML du select, certains caractères peuvent être modifiés !
|
2021-08-12 16:05:12 +02:00
|
|
|
}
|
|
|
|
// Création du tableau de données :
|
2021-08-11 17:25:56 +02:00
|
|
|
let datasHTML="<table><thead>";
|
|
|
|
for (let i in fields)
|
|
|
|
datasHTML+="<th>"+fields[i]+"</th>";
|
|
|
|
datasHTML+="</thead><tbody>";
|
|
|
|
for (let row in datas)
|
|
|
|
{
|
2021-08-12 16:05:12 +02:00
|
|
|
let visible=true;
|
2021-08-11 17:25:56 +02:00
|
|
|
if(filters.length !== 0)
|
|
|
|
{
|
|
|
|
for(let i in filters)
|
|
|
|
{
|
2021-08-12 16:05:12 +02:00
|
|
|
if(datas[row][filters[i].field].trim() != filters[i].value)
|
|
|
|
visible=false;
|
2021-08-11 17:25:56 +02:00
|
|
|
}
|
|
|
|
}
|
2021-08-12 16:05:12 +02:00
|
|
|
if(visible)
|
2021-08-11 17:25:56 +02:00
|
|
|
{
|
|
|
|
datasHTML+="<tr>";
|
|
|
|
for(let field in datas[row])
|
|
|
|
{
|
2021-08-12 16:05:12 +02:00
|
|
|
// Attention : si les erreurs papaParse ne sont pas bloquantes, il peut y avoir des données en trop, avec comme nom de colonne : "__parsed_extra"
|
|
|
|
if(fields.indexOf(field) !== -1)
|
|
|
|
datasHTML+="<td>"+datas[row][field]+"</td>";
|
2021-08-11 17:25:56 +02:00
|
|
|
}
|
|
|
|
datasHTML+="</tr>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
datasHTML+="</tbody></table>";
|
|
|
|
return datasHTML;
|
2021-08-10 15:56:53 +02:00
|
|
|
}
|
2021-08-12 16:05:12 +02:00
|
|
|
}
|