Nouvelle fonctionnalité permettant d'adapter le rendu HTML.
This commit is contained in:
parent
1b84eb8192
commit
f55f897bea
@ -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": {
|
||||
|
@ -25,10 +25,11 @@
|
||||
</article>
|
||||
<p id="pages"></p>
|
||||
<aside><p>Les données affichées viennent d'<a href="datas/elements-chimiques.csv">un fichier CSV</a> reprenant une partie des informations trouvées <a href="https://fr.wikipedia.org/wiki/%C3%89l%C3%A9ment_chimique#Caract%C3%A9ristiques_des_diff%C3%A9rents_%C3%A9l%C3%A9ments" target="_blank">sur Wikipédia</a>.</p>
|
||||
<p>La dernière colonne permet de montrer la possibilité d'<b>extraire des données d'une colonne ayant plusieurs valeurs par ligne</b>, ici séparées par une virgule.<br>Ce choix de la virgule comme séparateur ne pose pas de problème, tant le fichier CSV est correctement conçu.<br>Elle ne doit par contre pas être présente dans les expressions à extraire de la colonne, sachant que l'on peut désigner n'importe quel autre caractère séparateur.</p>
|
||||
<p>Toujours en option, certaines peuvent être désignées comme permettant de <b>classer les données</b> : un 1ᵉʳ clic lance un classement par ordre croissant, le 2ᵉ pour ordre décroissant et ainsi de suite.</p>
|
||||
<p>Le dernier filtre (Mots-clés) permet de montrer la possibilité d'<b>extraire des données d'un champ ayant plusieurs valeurs par ligne</b>, ici séparées par une virgule, sachant que l'on peut désigner n'importe quel autre caractère séparateur.</p>
|
||||
<p>Certains champs (=colonnes) peuvent être désignées comme devant permettre de <b>classer les données</b> : un 1ᵉʳ clic lance un classement par ordre croissant, le 2ᵉ pour ordre décroissant et ainsi de suite.</p>
|
||||
<p>Il est également possible d'afficher le nombre total de résultats, avec prise en compte des éventuels filtres.</p>
|
||||
<p>Enfin, une dernière option permet de <b>paginer les résultats</b>.</p>
|
||||
<p>Une autre option permet de <b>paginer les résultats</b>.</p>
|
||||
<p>Enfin il est possible d'<b>afficher les données autrement que sous forme de tableau HTML</b>. Si vous affichez cette page sur un écran large de moins de 800 px, les données seront simplement listées.<br>Si vous avez un grand écran, visualiser le résultat en faisant "Alt+"Maj"+"M", puis "F5". Appuyez de nouveau sur "F5", une fois de retour sur grand écran.</p>
|
||||
<p>Design basé sur <a href="https://www.getpapercss.com" target="_blank">PaperCSS</a></p></aside>
|
||||
</body>
|
||||
</html>
|
@ -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.",
|
||||
|
@ -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:"<h3>Affichage petits écrans !</h3>",
|
||||
allEnding:"",
|
||||
linesBegining:"<ul>",
|
||||
linesEnding:"</ul>",
|
||||
lineBegining:"<li><ul>",
|
||||
lineEnding:"</ul></li>",
|
||||
dataDisplaying:"<li><b>#FIELDNAME :</b> #VALUE</li>",
|
||||
};
|
||||
}
|
||||
else
|
||||
converter.datasRender.settings.allBegining="<table class='table-hover'>";
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -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<any>
|
||||
{
|
||||
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="<table><thead>";
|
||||
for (let i in fields)
|
||||
datasHTML+="<th>"+fields[i]+"</th>";
|
||||
datasHTML+="</thead><tbody>";
|
||||
// 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+="<tr>";
|
||||
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+="<td>"+datas[row][field]+"</td>";
|
||||
}
|
||||
datasHTML+="</tr>";
|
||||
datas2Display.push(datas[row]);
|
||||
nbVisible++;
|
||||
nbTotal++;
|
||||
}
|
||||
else if(visible)
|
||||
nbTotal++;
|
||||
}
|
||||
datasHTML+="</tbody></table>";
|
||||
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";
|
@ -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;
|
||||
|
61
src/freeDatas2HTMLRender.ts
Normal file
61
src/freeDatas2HTMLRender.ts
Normal file
@ -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:"<table>",
|
||||
allEnding:"</table>",
|
||||
fieldsBegining:"<thead><tr>",
|
||||
fieldsEnding:"</tr><thead>",
|
||||
fieldDisplaying:"<th>#FIELDNAME</th>",
|
||||
linesBegining:"<tbody>",
|
||||
linesEnding:"</tbody>",
|
||||
lineBegining:"<tr>",
|
||||
lineEnding:"</tr>",
|
||||
dataDisplaying:"<td>#VALUE</td>",
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user