diff --git a/package.json b/package.json index 3a7b706..201fe83 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "freedatas2html", - "version": "0.4.6", + "version": "0.5.0", "description": "Visualization of data from various sources (CSV, API, HTML...) with filters, classification, pagination, etc.", "main": "index.js", "scripts": { diff --git a/public/index.html b/public/index.html index 2abf71a..13d05c8 100644 --- a/public/index.html +++ b/public/index.html @@ -25,10 +25,11 @@

\ No newline at end of file diff --git a/src/errors.js b/src/errors.js index d4265b2..1ce83f0 100644 --- a/src/errors.js +++ b/src/errors.js @@ -12,6 +12,7 @@ module.exports = parserDatasNotFound : "Aucune donnée n'a été trouvée.", parserFail: "La lecture des données du fichier a échoué.", parserNeedUrl: "Merci de fournir une url valide pour le fichier à parser.", + renderNeedDatas: "Il ne peut y avoir de pagination, si les données n'ont pas été récupérées.", 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.", selectorCheckIsOkFail: "Le test est lancé sur un filtre incorrectement initialisé ou sur un attribut absent de la donnée à tester.", selectorFieldNotFound: "Au moins un des champs devant servir à filtrer les données n'existe pas dans le fichier.", diff --git a/src/firstExample.ts b/src/firstExample.ts index 4adfd87..180094e 100644 --- a/src/firstExample.ts +++ b/src/firstExample.ts @@ -1,4 +1,4 @@ -import { FreeDatas2HTML, Pagination, Selector, SortingField } from "./freeDatas2HTML"; +import { FreeDatas2HTML, Pagination, Render, Selector, SortingField } from "./freeDatas2HTML"; const initialise = async () => { @@ -24,6 +24,21 @@ const initialise = async () => converter.datasSourceUrl="http://localhost:8080/datas/elements-chimiques.csv"; await converter.parse(); converter.datasSortingFunctions=[{ datasFieldNb:4, sort:mySort }]; + // Adaptation du rendu + if(window.innerWidth < 800) + { + converter.datasRender.settings={ + allBegining:"

Affichage petits écrans !

", + allEnding:"", + linesBegining:"", + lineBegining:"
  • ", + dataDisplaying:"
  • #FIELDNAME : #VALUE
  • ", + }; + } + else + converter.datasRender.settings.allBegining=""; // Configuration de la pagination const pagination=new Pagination(converter, { id:"pages" }, "Page à afficher :"); @@ -31,7 +46,7 @@ const initialise = async () => pagination.selectedValue=10; converter.pagination=pagination; pagination.rend2HTML(); - + // Affichage initial converter.datasCounter={ id:"compteur" }; await converter.run(); @@ -46,22 +61,21 @@ const initialise = async () => filtre3.selector2HTML(); // + Injection des filtres dans le convertisseur converter.datasSelectors=[filtre1,filtre2,filtre3]; - + // Ajout de champs permettant de classer les données - let sortingField1=new SortingField(converter, 0); - //sortingField1.datasFieldNb=0; - sortingField1.field2HTML(); - let sortingField2=new SortingField(converter, 1); - // sortingField2.datasFieldNb=1; - sortingField2.field2HTML(); - let sortingField3=new SortingField(converter, 2); - //sortingField3.datasFieldNb=2; - sortingField3.field2HTML(); - let sortingField4=new SortingField(converter, 4); - //sortingField4.datasFieldNb=4; - sortingField4.field2HTML(); - // Injection dans le convertisseur - converter.datasSortingFields=[sortingField1,sortingField2,sortingField3,sortingField4]; + // Uniquement avec un rendu tableau (grand écran), car entêtes de colonne nécessaires + if(window.innerWidth >= 800) + { + let sortingField1=new SortingField(converter, 0); + sortingField1.field2HTML(); + let sortingField2=new SortingField(converter, 1); + sortingField2.field2HTML(); + let sortingField3=new SortingField(converter, 2); + sortingField3.field2HTML(); + let sortingField4=new SortingField(converter, 4); + sortingField4.field2HTML(); + converter.datasSortingFields=[sortingField1,sortingField2,sortingField3,sortingField4]; + } } catch(e) { diff --git a/src/freeDatas2HTML.ts b/src/freeDatas2HTML.ts index 1fcd144..ce5acfc 100644 --- a/src/freeDatas2HTML.ts +++ b/src/freeDatas2HTML.ts @@ -2,8 +2,9 @@ const Papa = require("papaparse"); const errors = require("./errors.js"); const { compare }= require('natural-orderby'); -import { Counter, DOMElement, Paginations, Selectors, SortingFields, SortingFunctions } from "./freeDatas2HTMLInterfaces"; +import { Counter, DatasRenders, DOMElement, Paginations, Selectors, SortingFields, SortingFunctions } from "./freeDatas2HTMLInterfaces"; import { Pagination} from "./freeDatas2HTMLPagination"; +import { Render} from "./freeDatas2HTMLRender"; import { Selector } from "./freeDatas2HTMLSelector"; import { SortingField } from "./freeDatas2HTMLSortingField"; @@ -11,10 +12,12 @@ import { PapaParseDatas, PapaParseErrors, PapaParseMeta } from "./papaParseInter export class FreeDatas2HTML { - // L'élément HTML où doivent être affichées les données : - private _datasViewElt: DOMElement = { id:"", eltDOM:undefined }; - // Le code HTML résultant (utile ?) : - public datasHTML: string = ""; + // L'élément HTML où afficher les données. Laisser à undefined si non affichées : + private _datasViewElt: DOMElement|undefined = undefined; + // Le moteur de rendu pour préparer l'affichage des données + public datasRender: DatasRenders; + // Le code HTML résultant : + public datasHTML: string = ""; // L'url où accéder aux données : private _datasSourceUrl: string = ""; @@ -40,6 +43,12 @@ export class FreeDatas2HTML // Affichage du nombre total de lignes de données (optionnel) : private _datasCounter: Counter = {}; + // J'initialiser avec des valeurs par défaut pouvant être surchargées par les setters + constructor() + { + this.datasRender=new Render(this); + } + // Vérifie s'il y a bien un élément dans le DOM pour l'id fourni public static checkInDOMById(checkedElt: DOMElement) : DOMElement { @@ -160,8 +169,6 @@ export class FreeDatas2HTML // Lance FreeDatas2HTML suivant les données reçues : public async run(): Promise { - if (this._datasViewElt.eltDOM === undefined) - throw new Error(errors.converterNeedDatasElt); if(this._datasSourceUrl === "" ) throw new Error(errors.parserNeedUrl); @@ -181,10 +188,14 @@ export class FreeDatas2HTML refreshView() : void { - if(this.parseMetas === undefined || this.parseMetas.fields === undefined || this._datasViewElt.eltDOM === undefined) - throw new Error(errors.converterRefreshFail); - this.datasHTML=this.createDatasHTML(this.parseMetas.fields, this.parseDatas); - this._datasViewElt.eltDOM.innerHTML=this.datasHTML; + if(this.parseMetas === undefined || this.parseMetas.fields === undefined) + throw new Error(errors.converterRefreshFail); + + this.datasHTML=this.createDatas2Display(this.parseMetas.fields, this.parseDatas); + + if(this._datasViewElt !== undefined && this._datasViewElt.eltDOM !== undefined) + this._datasViewElt.eltDOM.innerHTML=this.datasHTML; + // On réactive les éventuels champs de classement for(let i in this.datasSortingFields) { @@ -193,7 +204,7 @@ export class FreeDatas2HTML } } - createDatasHTML(fields: string[], datas: any[]) : string + createDatas2Display(fields: string[], datas: any[]) : string { // Dois-je classer les données par rapport à un champ ? if(this.datasSortedField !== undefined && this.datasSortedField.datasFieldNb !==undefined) @@ -216,11 +227,8 @@ export class FreeDatas2HTML firstData=this.pagination.selectedValue*(this.pagination.pages.selectedValue-1); let maxData = (this.pagination !== undefined && this.pagination.selectedValue !== undefined) ? this.pagination.selectedValue : datas.length+1; - // Création du tableau de données : - let datasHTML="
    "; - for (let i in fields) - datasHTML+=""; - datasHTML+=""; + // Création du tableau des données à afficher : + const datas2Display=[]; let nbVisible=0, nbTotal=0; for (let row in datas) { @@ -236,21 +244,13 @@ export class FreeDatas2HTML } if(visible && nbTotal >= firstData && nbVisible < maxData) { - datasHTML+=""; - for(let field in datas[row]) - { - // 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+=""; - } - datasHTML+=""; + datas2Display.push(datas[row]); nbVisible++; nbTotal++; } else if(visible) nbTotal++; } - datasHTML+="
    "+fields[i]+"
    "+datas[row][field]+"
    "; if(this._datasCounter !== undefined && this._datasCounter.displayElement !== undefined) { this._datasCounter.value=nbTotal; @@ -259,11 +259,12 @@ export class FreeDatas2HTML // Tout réaffichage peut entraîner une modification du nombre de pages (évolution filtres, etc.) if(this.pagination !== undefined) this.pagination.creaPageSelector(nbTotal); - return datasHTML; + return this.datasRender.rend2HTML(datas2Display); } } // Permet l'appel des dépendances via un seul script -export { Pagination } from "./freeDatas2HTMLPagination"; +export { Pagination } from "./freeDatas2HTMLPagination"; +export { Render} from "./freeDatas2HTMLRender"; export { Selector } from "./freeDatas2HTMLSelector"; export { SortingField } from "./freeDatas2HTMLSortingField"; \ No newline at end of file diff --git a/src/freeDatas2HTMLInterfaces.ts b/src/freeDatas2HTMLInterfaces.ts index 002f0ca..5720c2b 100644 --- a/src/freeDatas2HTMLInterfaces.ts +++ b/src/freeDatas2HTMLInterfaces.ts @@ -3,6 +3,24 @@ export interface Counter displayElement?: DOMElement; // peut être undefined si on ne souhaite pas d'affichage automatique dans la page value?: number; // undefined jusqu'à recevoir sa première valeur } +export interface DatasRenders +{ + rend2HTML(datas: any[]): string; + settings: DatasRendersSettings; +} +export interface DatasRendersSettings +{ + allBegining: string; + allEnding: string; + fieldsBegining?: string; + fieldsEnding?: string; + fieldDisplaying?: string; + linesBegining: string; + linesEnding: string; + lineBegining: string; + lineEnding: string; + dataDisplaying: string; +} export interface DOMElement { id: string; diff --git a/src/freeDatas2HTMLRender.ts b/src/freeDatas2HTMLRender.ts new file mode 100644 index 0000000..b4371e4 --- /dev/null +++ b/src/freeDatas2HTMLRender.ts @@ -0,0 +1,61 @@ +const errors = require("./errors.js"); +import { DatasRenders, DatasRendersSettings } from "./freeDatas2HTMLInterfaces"; +import { FreeDatas2HTML } from "./freeDatas2HTML"; + +export class Render implements DatasRenders +{ + private _converter: FreeDatas2HTML; + public settings: DatasRendersSettings; + static readonly defaultSettings = + { + allBegining:"", + allEnding:"
    ", + fieldsBegining:"", + fieldsEnding:"", + fieldDisplaying:"#FIELDNAME", + linesBegining:"", + linesEnding:"", + lineBegining:"", + lineEnding:"", + dataDisplaying:"#VALUE", + }; + + // Injection de la classe principale + constructor(converter: FreeDatas2HTML, settings:DatasRendersSettings=Render.defaultSettings) + { + this._converter=converter; + this.settings=settings; + } + + // Reçoit les données à afficher et créer le HTML correspondant + public rend2HTML(datas: any[]) : string + { + if(this._converter.parseMetas === undefined || this._converter.parseMetas.fields === undefined) + throw new Error(errors.renderNeedDatas); + else + { + let datasHTML=this.settings.allBegining; + // On ne souhaite pas nécessairement afficher les noms de colonne + if(this.settings.fieldsBegining !== undefined && this.settings.fieldDisplaying !== undefined) + { + datasHTML+=this.settings.fieldsBegining; + for (let i in this._converter.parseMetas!.fields) + datasHTML+=this.settings.fieldDisplaying.replace("#FIELDNAME", this._converter.parseMetas.fields[Number(i)]); + datasHTML+=this.settings.fieldsEnding; + } + datasHTML+=this.settings.linesBegining; + for (let row in datas) + { + datasHTML+=this.settings.lineBegining; + for(let field in datas[row]) + { + if(this._converter.parseMetas.fields.indexOf(field) !== -1) + datasHTML+=this.settings.dataDisplaying.replace("#VALUE" , datas[row][field]).replace("#FIELDNAME" , field); + } + datasHTML+=this.settings.lineEnding; + } + datasHTML+=this.settings.linesEnding+this.settings.allEnding; + return datasHTML; + } + } +} \ No newline at end of file