Nouvelle version avec classe séparée pour parser le CSV.
This commit is contained in:
parent
bcc5ea66f2
commit
50b8a8fccc
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "freedatas2html",
|
"name": "freedatas2html",
|
||||||
"version": "0.5.2",
|
"version": "0.6.0",
|
||||||
"description": "Visualization of data from various sources (CSV, API, HTML...) with filters, classification, pagination, etc.",
|
"description": "Visualization of data from various sources (CSV, API, HTML...) with filters, classification, pagination, etc.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -3,6 +3,7 @@ module.exports =
|
|||||||
converterElementNotFound : "Aucun élément HTML n'a été trouvé ayant comme \"id\" : ",
|
converterElementNotFound : "Aucun élément HTML n'a été trouvé ayant comme \"id\" : ",
|
||||||
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.",
|
||||||
|
converterNeedDatas: "Merci de fournir les données à traiter.",
|
||||||
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.",
|
||||||
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.",
|
||||||
@ -10,8 +11,11 @@ module.exports =
|
|||||||
paginationNeedOptionsValues: "Vous n'avez fourni aucune options possibles pour la pagination.",
|
paginationNeedOptionsValues: "Vous n'avez fourni aucune options possibles pour la pagination.",
|
||||||
paginationNeedPositiveInteger: "Merci de fournir un nombre entier supérieur à zéro pour désigner chaque option de pagination.",
|
paginationNeedPositiveInteger: "Merci de fournir un nombre entier supérieur à zéro pour désigner chaque option de pagination.",
|
||||||
parserDatasNotFound : "Aucune donnée n'a été trouvée.",
|
parserDatasNotFound : "Aucune donnée n'a été trouvée.",
|
||||||
parserFail: "La lecture des données du fichier a échoué.",
|
parserFail: "La lecture des données a échoué.",
|
||||||
parserNeedUrl: "Merci de fournir une url valide pour le fichier à parser.",
|
parserMeetErrors : "Au moins une erreur a été rencontrée durant le traitement des données.",
|
||||||
|
parserNeedDatas: "Merci de fournir une chaîne de caractères valide à parser.",
|
||||||
|
parserNeedSource: "Merci de fournir une chaîne de caractères où une url pour les données à parser.",
|
||||||
|
parserNeedUrl: "Merci de fournir une url valide pour la source distante de données.",
|
||||||
renderNeedDatas: "Il ne peut y avoir de pagination, si les données n'ont pas été récupérées.",
|
renderNeedDatas: "Il ne peut y avoir de pagination, si les données n'ont pas été récupérées.",
|
||||||
renderUnknownField: "Un champ non attendu a été trouvé dans les données à afficher : ",
|
renderUnknownField: "Un champ non attendu a été trouvé dans les données à afficher : ",
|
||||||
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.",
|
||||||
|
@ -19,11 +19,9 @@ const initialise = async () =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Création d'un convertisseur parsant les données d'un fichier CSV "distant"
|
// Création d'un convertisseur parsant les données d'un fichier CSV "distant"
|
||||||
let converter=new FreeDatas2HTML();
|
let converter=new FreeDatas2HTML("CSV","", { url:"http://localhost:8080/datas/elements-chimiques.csv"});
|
||||||
converter.datasViewElt={ id:"datas" };
|
converter.datasViewElt={ id:"datas" };
|
||||||
converter.datasSourceUrl="http://localhost:8080/datas/elements-chimiques.csv";
|
await converter.run();
|
||||||
await converter.parse();
|
|
||||||
converter.datasSortingFunctions=[{ datasFieldNb:4, sort:mySort }];
|
|
||||||
// Adaptation du rendu suivant la taille de l'écran
|
// Adaptation du rendu suivant la taille de l'écran
|
||||||
const myRender=new Render(converter);
|
const myRender=new Render(converter);
|
||||||
if(window.innerWidth < 800)
|
if(window.innerWidth < 800)
|
||||||
@ -46,6 +44,9 @@ const initialise = async () =>
|
|||||||
converter.datasRender=myRender;
|
converter.datasRender=myRender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ajout d'une fonction de classement spécifique
|
||||||
|
converter.datasSortingFunctions=[{ datasFieldNb:4, sort:mySort }];
|
||||||
|
|
||||||
// Configuration de la pagination
|
// Configuration de la pagination
|
||||||
const pagination=new Pagination(converter, { id:"pages" }, "Page à afficher :");
|
const pagination=new Pagination(converter, { id:"pages" }, "Page à afficher :");
|
||||||
pagination.options={ displayElement: { id:"paginationOptions" }, values: [10,20,50,500] , name: "Choix de pagination :" };
|
pagination.options={ displayElement: { id:"paginationOptions" }, values: [10,20,50,500] , name: "Choix de pagination :" };
|
||||||
@ -55,7 +56,7 @@ const initialise = async () =>
|
|||||||
|
|
||||||
// Affichage initial
|
// Affichage initial
|
||||||
converter.datasCounter={ id:"compteur" };
|
converter.datasCounter={ id:"compteur" };
|
||||||
await converter.run();
|
await converter.run();
|
||||||
|
|
||||||
// Création d'outils permettant de filtrer les données des champs de données
|
// Création d'outils permettant de filtrer les données des champs de données
|
||||||
let filtre1=new Selector(converter, 3, { id:"filtre1"} );
|
let filtre1=new Selector(converter, 3, { id:"filtre1"} );
|
||||||
@ -67,7 +68,7 @@ const initialise = async () =>
|
|||||||
filtre3.selector2HTML();
|
filtre3.selector2HTML();
|
||||||
// + Injection des filtres dans le convertisseur
|
// + Injection des filtres dans le convertisseur
|
||||||
converter.datasSelectors=[filtre1,filtre2,filtre3];
|
converter.datasSelectors=[filtre1,filtre2,filtre3];
|
||||||
|
|
||||||
// Ajout de champs permettant de classer les données
|
// Ajout de champs permettant de classer les données
|
||||||
// Uniquement avec un rendu tableau (grand écran), car entêtes de colonne nécessaires
|
// Uniquement avec un rendu tableau (grand écran), car entêtes de colonne nécessaires
|
||||||
if(window.innerWidth >= 800)
|
if(window.innerWidth >= 800)
|
||||||
|
@ -1,52 +1,77 @@
|
|||||||
const Papa = require("papaparse");
|
const { compare }=require('natural-orderby');
|
||||||
const errors = require("./errors.js");
|
const errors=require("./errors.js");
|
||||||
const { compare }= require('natural-orderby');
|
|
||||||
|
|
||||||
import { Counter, DatasRenders, DOMElement, Paginations, Selectors, SortingFields, SortingFunctions } from "./freeDatas2HTMLInterfaces";
|
import { Counter, Datas, DatasRenders, DOMElement, Paginations, Parsers, ParseErrors, RemoteSource, Selectors, SortingFields, SortingFunctions } from "./freeDatas2HTMLInterfaces";
|
||||||
import { Pagination} from "./freeDatas2HTMLPagination";
|
import { Pagination} from "./freeDatas2HTMLPagination";
|
||||||
|
import { ParserForCSV} from "./freeDatas2HTMLParserForCSV";
|
||||||
import { Render} from "./freeDatas2HTMLRender";
|
import { Render} from "./freeDatas2HTMLRender";
|
||||||
import { Selector } from "./freeDatas2HTMLSelector";
|
import { Selector } from "./freeDatas2HTMLSelector";
|
||||||
import { SortingField } from "./freeDatas2HTMLSortingField";
|
import { SortingField } from "./freeDatas2HTMLSortingField";
|
||||||
|
|
||||||
import { PapaParseDatas, PapaParseErrors, PapaParseMeta } from "./papaParseInterfaces";
|
|
||||||
|
|
||||||
export class FreeDatas2HTML
|
export class FreeDatas2HTML
|
||||||
{
|
{
|
||||||
// L'élément HTML où afficher les données. Laisser à undefined si non affichées :
|
// L'élément HTML où afficher les données. Laisser à undefined si non affichées :
|
||||||
private _datasViewElt: DOMElement|undefined = undefined;
|
private _datasViewElt: DOMElement|undefined=undefined;
|
||||||
// Le moteur de rendu pour préparer l'affichage des données
|
// Le moteur de rendu pour préparer l'affichage des données
|
||||||
public datasRender: DatasRenders;
|
public datasRender: DatasRenders;
|
||||||
// Le code HTML résultant :
|
// Le code HTML résultant :
|
||||||
public datasHTML: string = "";
|
public datasHTML: string = "";
|
||||||
|
// Le parseur :
|
||||||
|
public parser: Parsers; // public pour permettre de charger un parseur tiers après instanciation
|
||||||
|
|
||||||
// L'url où accéder aux données :
|
// Données distantes :
|
||||||
private _datasSourceUrl: string = "";
|
//private _datasRemoteSource: RemoteSource|undefined=undefined;
|
||||||
// Le nom des champs (interfaces à renommer, car PapaParse = cas particulier) :
|
// Ou locales :
|
||||||
public parseMetas: PapaParseMeta|undefined = undefined;
|
//private _datas2Parse:string|undefined=undefined;
|
||||||
|
// Dans tous les cas, besoin d'un type :
|
||||||
|
public datasType: "CSV"|"HTML"|"JSON"|undefined;
|
||||||
|
|
||||||
|
// Le nom des champs trouvés dans les données :
|
||||||
|
public fields: string[]|undefined=undefined;
|
||||||
// Les données à proprement parler :
|
// Les données à proprement parler :
|
||||||
public parseDatas: PapaParseDatas[] = [];
|
public datas: []=[];
|
||||||
// Les erreurs rencontrées durant le parsage :
|
// Les erreurs rencontrées durant le traitement des données reçues :
|
||||||
public parseErrors: PapaParseErrors[] = [];
|
public parseErrors: ParseErrors[]|undefined;
|
||||||
// Doit-on tout arrêter si une erreur est rencontrée durant la parsage ?
|
// Doit-on tout arrêter si une erreur est rencontrée durant le traitement ?
|
||||||
public stopIfParseErrors: boolean = false;
|
public stopIfParseErrors: boolean = false;
|
||||||
|
|
||||||
// Les fonctions spécifiques de classement pour certains champs :
|
// Les fonctions spécifiques de classement pour certains champs :
|
||||||
private _datasSortingFunctions: SortingFunctions[] = [];
|
private _datasSortingFunctions: SortingFunctions[] = [];
|
||||||
// Les filtres possible sur certains champs
|
// Les filtres possible sur certains champs :
|
||||||
datasSelectors: Selectors[] = [];
|
datasSelectors: Selectors[] = [];
|
||||||
// Les champs pouvant être classés
|
// Les champs pouvant être classés :
|
||||||
datasSortingFields: SortingFields[] = [];
|
datasSortingFields: SortingFields[] = [];
|
||||||
// La dernier champ pour lequel le classement a été demandé
|
// La dernier champ pour lequel le classement a été demandé :
|
||||||
datasSortedField: SortingFields|undefined;
|
datasSortedField: SortingFields|undefined;
|
||||||
// La Pagination :
|
// Éventuelle pagination :
|
||||||
pagination: Paginations|undefined;
|
pagination: Paginations|undefined;
|
||||||
// Affichage du nombre total de lignes de données (optionnel) :
|
// Affichage du nombre total de lignes de données (optionnel) :
|
||||||
private _datasCounter: Counter = {};
|
private _datasCounter: Counter = {};
|
||||||
|
|
||||||
// J'initialiser avec des valeurs par défaut pouvant être surchargées par les setters
|
// J'initialiser avec des valeurs par défaut pouvant être surchargées par les setters
|
||||||
constructor()
|
constructor(datasType:"CSV"|"HTML"|"JSON", datas2Parse="", datasRemoteSource?:RemoteSource)
|
||||||
{
|
{
|
||||||
this.datasRender=new Render(this);
|
this.datasRender=new Render(this);
|
||||||
|
switch (datasType)
|
||||||
|
{
|
||||||
|
case "CSV":
|
||||||
|
this.parser=new ParserForCSV();
|
||||||
|
break;
|
||||||
|
case "HTML":
|
||||||
|
this.parser=new ParserForCSV();
|
||||||
|
console.error("Appeler le parseur HTML");
|
||||||
|
break;
|
||||||
|
case "JSON":
|
||||||
|
this.parser=new ParserForCSV();
|
||||||
|
console.error("Appeler le parseur JSON");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(datas2Parse !== "")
|
||||||
|
this.parser.datas2Parse=datas2Parse;
|
||||||
|
else if(datasRemoteSource!==undefined)
|
||||||
|
this.parser.datasRemoteSource=datasRemoteSource;
|
||||||
|
else
|
||||||
|
throw new Error(errors.converterNeedDatas);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vérifie s'il y a bien un élément dans le DOM pour l'id fourni
|
// Vérifie s'il y a bien un élément dans le DOM pour l'id fourni
|
||||||
@ -65,7 +90,7 @@ export class FreeDatas2HTML
|
|||||||
// Vérifie qu'un champ existe bien dans les données
|
// Vérifie qu'un champ existe bien dans les données
|
||||||
public checkFieldExist(nb: number) : boolean
|
public checkFieldExist(nb: number) : boolean
|
||||||
{
|
{
|
||||||
if(this.parseMetas === undefined || this.parseMetas.fields === undefined || this.parseMetas.fields[nb] === undefined)
|
if(this.fields === undefined || this.fields[nb] === undefined)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
@ -77,15 +102,6 @@ export class FreeDatas2HTML
|
|||||||
this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt);
|
this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vérifie que l'url où chercher les données n'est pas vide : inutile si données dans page ou tranmises
|
|
||||||
set datasSourceUrl(url: string)
|
|
||||||
{
|
|
||||||
if(url.trim().length === 0)
|
|
||||||
throw new Error(errors.parserNeedUrl);
|
|
||||||
else
|
|
||||||
this._datasSourceUrl=url.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifie que les numéros de champs pour lesquels il y a des fonctions de classement spécifiques sont cohérents
|
// Vérifie que les numéros de champs pour lesquels il y a des fonctions de classement spécifiques sont cohérents
|
||||||
// ! Ne peut être testé qu'après avoir reçu les données
|
// ! Ne peut être testé qu'après avoir reçu les données
|
||||||
set datasSortingFunctions(SortingFunctions: SortingFunctions[])
|
set datasSortingFunctions(SortingFunctions: SortingFunctions[])
|
||||||
@ -126,72 +142,36 @@ export class FreeDatas2HTML
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse des données distantes (url) fournies en CSV :
|
|
||||||
public async parse(): Promise<any>
|
|
||||||
{
|
|
||||||
const converter=this;
|
|
||||||
return new Promise((resolve,reject) =>
|
|
||||||
{
|
|
||||||
if(converter._datasSourceUrl !== "" )
|
|
||||||
{
|
|
||||||
Papa.parse(converter._datasSourceUrl,
|
|
||||||
{
|
|
||||||
quoteChar: '"',
|
|
||||||
header: true,
|
|
||||||
complete: function(results :any)
|
|
||||||
{
|
|
||||||
converter.parseErrors=results.errors;
|
|
||||||
converter.parseDatas=results.data;
|
|
||||||
// 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.parseMetas=results.meta;
|
|
||||||
resolve(true);
|
|
||||||
},
|
|
||||||
error:function(error :any)
|
|
||||||
{
|
|
||||||
reject(new Error(errors.parserFail));
|
|
||||||
},
|
|
||||||
download: true,
|
|
||||||
skipEmptyLines: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
reject(new Error(errors.parserNeedUrl));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lance FreeDatas2HTML suivant les données reçues :
|
// Lance FreeDatas2HTML suivant les données reçues :
|
||||||
public async run(): Promise<any>
|
public async run(): Promise<any>
|
||||||
{
|
{
|
||||||
if(this._datasSourceUrl === "" )
|
await this.parser.parse();
|
||||||
throw new Error(errors.parserNeedUrl);
|
if(this.parser.parseResults === undefined)
|
||||||
|
throw new Error(errors.parserFail);
|
||||||
await this.parse();
|
|
||||||
|
|
||||||
if(this.parseDatas.length === 0 || this.parseMetas!.fields === undefined) // je force avec "!", car l'existence de parseMetas est certaine après parse().
|
|
||||||
throw new Error(errors.parserDatasNotFound);
|
|
||||||
else if(this.stopIfParseErrors && this.parseErrors.length!==0)
|
|
||||||
console.error(this.parseErrors);
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Si tout est ok, affichage initial de toutes les données du fichier
|
this.fields=this.parser.parseResults.fields;
|
||||||
this.refreshView();
|
this.datas=this.parser.parseResults.datas;
|
||||||
return true;
|
this.parseErrors=this.parser.parseResults.errors;
|
||||||
|
if(this.fields === undefined)
|
||||||
|
throw new Error(errors.parserDatasNotFound);
|
||||||
|
else if(this.stopIfParseErrors && this.parseErrors !== undefined)
|
||||||
|
throw new Error(errors.parrserMeetErrors);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Si tout est ok, affichage initial de toutes les données du fichier
|
||||||
|
this.refreshView();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshView() : void
|
refreshView() : void
|
||||||
{
|
{
|
||||||
if(this.parseMetas === undefined || this.parseMetas.fields === undefined)
|
if(this.fields === undefined)
|
||||||
throw new Error(errors.converterRefreshFail);
|
throw new Error(errors.converterRefreshFail);
|
||||||
|
|
||||||
this.datasHTML=this.createDatas2Display(this.parseMetas.fields, this.parseDatas);
|
this.datasHTML=this.createDatas2Display(this.fields, this.datas);
|
||||||
|
|
||||||
if(this._datasViewElt !== undefined && this._datasViewElt.eltDOM !== undefined)
|
if(this._datasViewElt !== undefined && this._datasViewElt.eltDOM !== undefined)
|
||||||
this._datasViewElt.eltDOM.innerHTML=this.datasHTML;
|
this._datasViewElt.eltDOM.innerHTML=this.datasHTML;
|
||||||
|
@ -46,6 +46,36 @@ export interface PaginationsPages
|
|||||||
values?: number[];
|
values?: number[];
|
||||||
selectedValue?: number;
|
selectedValue?: number;
|
||||||
}
|
}
|
||||||
|
export interface Datas
|
||||||
|
{
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
export interface ParseErrors // erreurs non bloquantes rencontrées lors du parsage de données
|
||||||
|
{
|
||||||
|
code?: string;
|
||||||
|
message: string;
|
||||||
|
row: number;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
export interface ParseResults
|
||||||
|
{
|
||||||
|
datas: [];
|
||||||
|
errors: ParseErrors[];
|
||||||
|
fields: string[];
|
||||||
|
}
|
||||||
|
export interface Parsers
|
||||||
|
{
|
||||||
|
datasRemoteSource: RemoteSource|undefined;
|
||||||
|
datas2Parse:string|undefined;
|
||||||
|
parseResults:ParseResults|undefined;
|
||||||
|
parse(): Promise<void>;
|
||||||
|
}
|
||||||
|
export interface RemoteSource
|
||||||
|
{
|
||||||
|
url: string;
|
||||||
|
headers?: { key:string, value:string|boolean|number }[] ;// revoir types possibles pour Headers ?
|
||||||
|
withCredentials?:boolean;
|
||||||
|
}
|
||||||
export interface Selectors
|
export interface Selectors
|
||||||
{
|
{
|
||||||
datasViewElt: DOMElement;
|
datasViewElt: DOMElement;
|
||||||
|
@ -21,7 +21,7 @@ export class Pagination implements Paginations
|
|||||||
// De plus l'élément du DOM devant recevoir la liste des pages doit exister
|
// De plus l'élément du DOM devant recevoir la liste des pages doit exister
|
||||||
constructor(converter: FreeDatas2HTML, pagesElt: DOMElement, pagesName: string="Pages")
|
constructor(converter: FreeDatas2HTML, pagesElt: DOMElement, pagesName: string="Pages")
|
||||||
{
|
{
|
||||||
if(converter.parseMetas === undefined || converter.parseMetas.fields === undefined)
|
if(converter.fields === undefined)
|
||||||
throw new Error(errors.paginationNeedDatas);
|
throw new Error(errors.paginationNeedDatas);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
129
src/freeDatas2HTMLParserForCSV.ts
Normal file
129
src/freeDatas2HTMLParserForCSV.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
const Papa = require("papaparse");
|
||||||
|
const errors = require("./errors.js");
|
||||||
|
|
||||||
|
import { ParseResults, Parsers, RemoteSource } from "./freeDatas2HTMLInterfaces";
|
||||||
|
interface papaParseOptions
|
||||||
|
{
|
||||||
|
delimiter: string;
|
||||||
|
newline: string;
|
||||||
|
quoteChar: string;
|
||||||
|
escapeChar: string;
|
||||||
|
transformHeader?(field: string, index: number): string;
|
||||||
|
preview: number;
|
||||||
|
comments: false|string,
|
||||||
|
fastMode: boolean|undefined;
|
||||||
|
transform?(value: string): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ParserForCSV implements Parsers
|
||||||
|
{
|
||||||
|
private _datasRemoteSource: RemoteSource|undefined=undefined;
|
||||||
|
private _datas2Parse:string|undefined=undefined;
|
||||||
|
private _parseResults:ParseResults|undefined=undefined;
|
||||||
|
|
||||||
|
// Ouverture de certaines options de Papa Parse :
|
||||||
|
// cf. https://www.papaparse.com/docs#config
|
||||||
|
public options: papaParseOptions =
|
||||||
|
{
|
||||||
|
delimiter: "",
|
||||||
|
newline: "",
|
||||||
|
quoteChar: '"',
|
||||||
|
escapeChar: '"',
|
||||||
|
transformHeader: function(field: string, index: number): string { return field.trim() },
|
||||||
|
preview: 0,
|
||||||
|
comments: "",
|
||||||
|
fastMode: undefined,
|
||||||
|
transform: undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
set datasRemoteSource(source: RemoteSource)
|
||||||
|
{
|
||||||
|
if(source.url.trim().length === 0)
|
||||||
|
throw new Error(errors.parserNeedUrl);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.url=source.url.trim();
|
||||||
|
this._datasRemoteSource=source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set datas2Parse(datas: string)
|
||||||
|
{
|
||||||
|
if(datas.trim().length === 0)
|
||||||
|
throw new Error(errors.parserNeedDatas);
|
||||||
|
else
|
||||||
|
this._datas2Parse=datas.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
get parseResults() : ParseResults|undefined
|
||||||
|
{
|
||||||
|
return this._parseResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
// async dans le cas d'une source distante
|
||||||
|
// Et création d'une Promise car PapaParse utilise une fonction callback.
|
||||||
|
public async parse(): Promise<any>
|
||||||
|
{
|
||||||
|
const parser=this, options=this.options;
|
||||||
|
return new Promise((resolve,reject) =>
|
||||||
|
{
|
||||||
|
let parseContent="", parseDownload=false, parseDownloadRequestHeaders: any=undefined, parseWithCredentials: any=undefined;
|
||||||
|
if(parser._datasRemoteSource !== undefined)
|
||||||
|
{
|
||||||
|
parseContent=parser._datasRemoteSource.url;
|
||||||
|
parseDownload=true;
|
||||||
|
parseWithCredentials=parser._datasRemoteSource.withCredentials; // undefined ok pour PapaParse
|
||||||
|
if(parser._datasRemoteSource.headers !== undefined)
|
||||||
|
{
|
||||||
|
parseDownloadRequestHeaders={};
|
||||||
|
for (let i in parser._datasRemoteSource.headers)
|
||||||
|
parseDownloadRequestHeaders[parser._datasRemoteSource.headers[Number(i)].key]=parser._datasRemoteSource.headers[Number(i)].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(parser._datas2Parse !== undefined)
|
||||||
|
parseContent=parser._datas2Parse;
|
||||||
|
else
|
||||||
|
reject(new Error(errors.parserNeedSource));
|
||||||
|
|
||||||
|
Papa.parse(parseContent,
|
||||||
|
{
|
||||||
|
delimiter: options.delimiter,
|
||||||
|
newline: options.newline,
|
||||||
|
quoteChar: options.quoteChar,
|
||||||
|
escapeChar: options.escapeChar,
|
||||||
|
header: true, // nécessaire pour obtenir le nom des champs
|
||||||
|
transformHeader: options.transformHeader,
|
||||||
|
preview: options.preview,
|
||||||
|
comments: options.comments,
|
||||||
|
complete: function(results :any)
|
||||||
|
{
|
||||||
|
// Attention, Papa Parse peut accepter un nom de champ vide
|
||||||
|
let realFields: string[]=[];
|
||||||
|
for(let i in results.meta.fields)
|
||||||
|
{
|
||||||
|
if(results.meta.fields[i].trim() !== "")
|
||||||
|
realFields.push(results.meta.fields[i]);
|
||||||
|
}
|
||||||
|
if(realFields.length === 0)
|
||||||
|
reject(new Error(errors.parserFail));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parser._parseResults={
|
||||||
|
datas: results.data,
|
||||||
|
errors: results.errors,
|
||||||
|
fields: realFields,
|
||||||
|
};
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
download: parseDownload,
|
||||||
|
downloadRequestHeaders: parseDownloadRequestHeaders,
|
||||||
|
skipEmptyLines:"greedy",
|
||||||
|
fastMode: options.fastMode,
|
||||||
|
withCredentials: parseWithCredentials,
|
||||||
|
transform: options.transform,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -31,7 +31,7 @@ export class Render implements DatasRenders
|
|||||||
public rend2HTML(datas: any[]) : string
|
public rend2HTML(datas: any[]) : string
|
||||||
{
|
{
|
||||||
// Il peut n'y avoir aucune donnée (filtres...), mais les noms des champs doivent être connus.
|
// Il peut n'y avoir aucune donnée (filtres...), mais les noms des champs doivent être connus.
|
||||||
if(this._converter.parseMetas === undefined || this._converter.parseMetas.fields === undefined)
|
if(this._converter.fields === undefined)
|
||||||
throw new Error(errors.renderNeedDatas);
|
throw new Error(errors.renderNeedDatas);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -40,8 +40,8 @@ export class Render implements DatasRenders
|
|||||||
if(this.settings.fieldsBegining !== undefined && this.settings.fieldDisplaying !== undefined && this.settings.fieldsEnding !== undefined )
|
if(this.settings.fieldsBegining !== undefined && this.settings.fieldDisplaying !== undefined && this.settings.fieldsEnding !== undefined )
|
||||||
{
|
{
|
||||||
datasHTML+=this.settings.fieldsBegining;
|
datasHTML+=this.settings.fieldsBegining;
|
||||||
for (let i in this._converter.parseMetas.fields)
|
for (let i in this._converter.fields)
|
||||||
datasHTML+=this.settings.fieldDisplaying.replace("#FIELDNAME", this._converter.parseMetas.fields[Number(i)]);
|
datasHTML+=this.settings.fieldDisplaying.replace("#FIELDNAME", this._converter.fields[Number(i)]);
|
||||||
datasHTML+=this.settings.fieldsEnding;
|
datasHTML+=this.settings.fieldsEnding;
|
||||||
}
|
}
|
||||||
datasHTML+=this.settings.linesBegining;
|
datasHTML+=this.settings.linesBegining;
|
||||||
@ -51,7 +51,7 @@ export class Render implements DatasRenders
|
|||||||
for(let field in datas[row])
|
for(let field in datas[row])
|
||||||
{
|
{
|
||||||
// On n'affiche que les champs attendus et signale les erreurs dans la console
|
// On n'affiche que les champs attendus et signale les erreurs dans la console
|
||||||
if(this._converter.parseMetas.fields.indexOf(field) !== -1)
|
if(this._converter.fields.indexOf(field) !== -1)
|
||||||
datasHTML+=this.settings.dataDisplaying.replace("#VALUE" , datas[row][field]).replace("#FIELDNAME" , field);
|
datasHTML+=this.settings.dataDisplaying.replace("#VALUE" , datas[row][field]).replace("#FIELDNAME" , field);
|
||||||
else
|
else
|
||||||
console.log(errors.renderUnknownField+field);
|
console.log(errors.renderUnknownField+field);
|
||||||
|
@ -15,7 +15,7 @@ export class Selector implements Selectors
|
|||||||
// Injection de la classe principale, mais uniquement si les données ont été importées
|
// Injection de la classe principale, mais uniquement si les données ont été importées
|
||||||
constructor(converter: FreeDatas2HTML, datasFieldNb: number, elt: DOMElement)
|
constructor(converter: FreeDatas2HTML, datasFieldNb: number, elt: DOMElement)
|
||||||
{
|
{
|
||||||
if(converter.parseMetas === undefined || converter.parseMetas.fields === undefined || converter.parseDatas.length === 0)
|
if(converter.fields === undefined || converter.datas.length === 0)
|
||||||
throw new Error(errors.selectorNeedDatas);
|
throw new Error(errors.selectorNeedDatas);
|
||||||
else if(! converter.checkFieldExist(Number(datasFieldNb)))
|
else if(! converter.checkFieldExist(Number(datasFieldNb)))
|
||||||
throw new Error(errors.selectorFieldNotFound);
|
throw new Error(errors.selectorFieldNotFound);
|
||||||
@ -59,18 +59,18 @@ export class Selector implements Selectors
|
|||||||
throw new Error(errors.selector2HTMLFail);
|
throw new Error(errors.selector2HTMLFail);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.name=this._converter.parseMetas!.fields![this._datasFieldNb]; // this._converter.parse... ne peuvent être indéfinis si this._converter existe (cf constructeur)
|
this.name=this._converter.fields![this._datasFieldNb]; // this._converter.parse... ne peuvent être indéfinis si this._converter existe (cf constructeur)
|
||||||
for (let row in this._converter.parseDatas)
|
for (let row in this._converter.datas)
|
||||||
{
|
{
|
||||||
if(this._separator === undefined)
|
if(this._separator === undefined)
|
||||||
{
|
{
|
||||||
let checkedValue=String(this._converter.parseDatas[row][this.name]).trim(); // trim() nécessaire pour éviter problème de classement du tableau (sort)
|
let checkedValue=String(this._converter.datas[row][this.name]).trim(); // trim() nécessaire pour éviter problème de classement du tableau (sort)
|
||||||
if(checkedValue !== "" && this.values.indexOf(checkedValue) === -1)
|
if(checkedValue !== "" && this.values.indexOf(checkedValue) === -1)
|
||||||
this.values.push(checkedValue);
|
this.values.push(checkedValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
let checkedValues=String(this._converter.parseDatas[row][this.name]).split(this._separator); // String() car les données peuvent être des chiffres, etc.
|
let checkedValues=String(this._converter.datas[row][this.name]).split(this._separator); // String() car les données peuvent être des chiffres, etc.
|
||||||
for(let i in checkedValues)
|
for(let i in checkedValues)
|
||||||
{
|
{
|
||||||
let checkedValue=checkedValues[i].trim();
|
let checkedValue=checkedValues[i].trim();
|
||||||
|
@ -13,7 +13,7 @@ export class SortingField implements SortingFields
|
|||||||
// Injection de la classe principale, mais uniquement si le nom des champs ont été importés et affichés correctement
|
// Injection de la classe principale, mais uniquement si le nom des champs ont été importés et affichés correctement
|
||||||
constructor(converter: FreeDatas2HTML, datasFieldNb: number, fieldsDOMSelector: string = "th")
|
constructor(converter: FreeDatas2HTML, datasFieldNb: number, fieldsDOMSelector: string = "th")
|
||||||
{
|
{
|
||||||
if(converter.parseMetas === undefined || converter.parseMetas.fields === undefined)
|
if(converter.fields === undefined)
|
||||||
throw new Error(errors.sortingFieldNeedDatas);
|
throw new Error(errors.sortingFieldNeedDatas);
|
||||||
else if(! converter.checkFieldExist(Number(datasFieldNb)))
|
else if(! converter.checkFieldExist(Number(datasFieldNb)))
|
||||||
throw new Error(errors.sortingFieldFieldNotFound);
|
throw new Error(errors.sortingFieldFieldNotFound);
|
||||||
@ -22,7 +22,7 @@ export class SortingField implements SortingFields
|
|||||||
const fields=document.querySelectorAll(fieldsDOMSelector);
|
const fields=document.querySelectorAll(fieldsDOMSelector);
|
||||||
if(fields === undefined)
|
if(fields === undefined)
|
||||||
throw new Error(errors.sortingFieldsNotInHTML);
|
throw new Error(errors.sortingFieldsNotInHTML);
|
||||||
else if(fields.length !== converter.parseMetas.fields.length)
|
else if(fields.length !== converter.fields.length)
|
||||||
throw new Error(errors.sortingFieldsNbFail);
|
throw new Error(errors.sortingFieldsNbFail);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
// cf. https://www.papaparse.com/docs#results
|
|
||||||
|
|
||||||
export interface PapaParseDatas
|
|
||||||
{
|
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PapaParseErrors
|
|
||||||
{
|
|
||||||
type: string;
|
|
||||||
code: string;
|
|
||||||
message: string;
|
|
||||||
row: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PapaParseMeta
|
|
||||||
{
|
|
||||||
delimiter?: string;
|
|
||||||
linebreak?: string;
|
|
||||||
aborted?: boolean;
|
|
||||||
fields?: string[];
|
|
||||||
truncated?: boolean;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user