FreeDatas2HTML/src/extensions/MixedFieldsRender.ts

109 lines
4.6 KiB
TypeScript

// Alternative à Rendern pour des intégrations plus complexes.
// Le contenu des divers champs peut ici être mixé à l'affichage ou encore affiché plusieurs fois...
import { DatasRenders } from "../interfaces";
const errors=require("../errors.js");
interface DatasRendersSettings
{
allBegining: string;
allEnding: string;
linesBegining?: string,
linesEnding?: string,
fieldsNamesDisplaying?: string; // ##n## sera remplacé par le nom du nième champ, etc.
datasLinesDisplaying: string;// ##n## sera remplacé par la valeur du nième champ, etc.
}
interface FieldRender
{
name: string; // nom du champ concerné.
rend2HTML(lineValues: {[index: string]:string} ) : string; // fonction spécifique appelée avant d'injecter la valeur de ce champ dans datasLinesDisplaying
}
export class MixedFieldsRender implements DatasRenders
{
private _fields: string[]=[];
public settings: DatasRendersSettings;
public fieldRenders: FieldRender[]=[];
public datas: {[index: string]:string}[]=[];
constructor(settings: DatasRendersSettings)
{
this.settings=settings;
}
// Les données fournies au Render peuvent être vides du fait de l'action des filtres ou encore de la pagination...
// Mais les noms des champ doivent être fournis.
set fields(fields: string[])
{
if(fields.length === 0)
throw new Error(errors.renderNeedFields);
else
this._fields=fields;
}
get fields() : string[]
{
return this._fields;
}
public rend2HTML() : string
{
if(this._fields.length === 0)
throw new Error(errors.renderNeedFields);
else
{
let datasHTML=this.settings.allBegining;
// Création d'une éventuelle entête :
if(this.settings.fieldsNamesDisplaying !== undefined)
{
// Dans le cas de champs mixés, tous les champs utilisés ne sont pas forcément listés en entête.
// Il suffit alors qu'ils soient absent de fieldsNamesDisplaying.
let fieldsNamesRend=this.settings.fieldsNamesDisplaying;
for(let i=0; i< this._fields.length; i++)
fieldsNamesRend=fieldsNamesRend.replace("##"+i+"##", this._fields[i]);
datasHTML+=fieldsNamesRend;
}
if(this.settings.linesBegining !== undefined)
datasHTML+=this.settings.linesBegining;
// Suivant les objets/lignes, les champs peuvent se trouver dans un ordre différent.
// Ou encore certains peuvent manquer, être en trop...
// Mais tous les champs présents dans "fields" doivent être traités en respectant leur ordre pour être cohérent avec l'éventuelle entête créée ci-dessus.
for(let row of this.datas)
{
// Idem que l'entête : tous les champs ne sont pas forcément présents dans datasLinesDisplaying.
let lineRend=this.settings.datasLinesDisplaying;
for(let i=0; i< this._fields.length; i++)
{
const currentField=this._fields[i];
if(row[currentField] !== undefined) // champ renseigné pour cet enregistrement
{
// Par défaut, l'emplacement dans datasLinesDisplaying sera remplacé par la valeur renseignée :
let rowRend=row[currentField];
// Sauf si une fonction de pré-traitement a été fournie pour ce champ :
const render = this.fieldRenders.find(function(item)
{
return item.name === currentField;
});
if(render !== undefined)
rowRend=render.rend2HTML(row);
lineRend=lineRend.replace(new RegExp("##"+i+"##", "g"), rowRend); // RegExp, car bug TS avec replaceAll (parce que target = es5 ?).
}
else // si ce champ n'est pas renseigné, il faut tout de même supprimer l'indicateur de son emplacement :
lineRend=lineRend.replace(new RegExp("##"+i+"##", "g"), "");
}
datasHTML+=lineRend;
}
if(this.settings.linesEnding !== undefined)
datasHTML+=this.settings.linesEnding;
datasHTML+=this.settings.allEnding;
return datasHTML;
}
}
}
// Utile au script de tests :
export { FreeDatas2HTML } from "../FreeDatas2HTML";
export { errors };