/* * Copyright © 2021 Bonitasoft S.A. * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import {PropertiesInfo} from "./PropertiesInfo"; import {Property} from "./Property"; import fs from "fs"; import {Bond} from "./Bond"; import kebabCase from 'lodash.kebabcase'; export enum FwkType { AngularJS, Angular } export class HtmlTemplatesGenerator { private readonly propertiesInfo: PropertiesInfo; private static specificProperties: Array = ["readOnly", "required"]; private static toIgnoreProperties: Array = ["id"]; public static ifDirectiveAngularJS = "ng-if"; public static ifDirectiveAngular = "*ngIf"; public static AngularJsFileExtension = "tpl.html"; public static AngularFileExtension = "tpl.runtime.html"; constructor(propertiesInfo: PropertiesInfo) { this.propertiesInfo = propertiesInfo; } public generate(outputDir: string, type?: FwkType) { // General syntax: // // // Example: // -- For UID editor (AngularJS) -- -- Angular -- // [(value)]="properties.value" // // // if (type !== undefined) { this.generateTemplateFile(type, outputDir); } else { this.generateTemplateFile(FwkType.AngularJS, outputDir); this.generateTemplateFile(FwkType.Angular, outputDir); } } private generateTemplateFile(type: FwkType, outputDir: string) { this.writeFile(this.generateTemplate(type), type, outputDir); } private generateTemplate(type: FwkType): string { let ifBoolean = this.generateIfBoolean(type); let specificProps = this.generateSpecificProperties(type); let props = this.generateProperties(type); let template = []; if (ifBoolean.length > 0) { for (let ifElem of ifBoolean) { template.push(this.generateHtmlTagStart()); template.push(ifElem); template.push(specificProps); template.push(props); template.push(this.generateHtmlTagEnd()); } } else { template.push(this.generateHtmlTagStart()); template.push(specificProps); template.push(props); template.push(this.generateHtmlTagEnd()); } return template.join(''); } private generateHtmlTagStart(): string { return `<${this.getHtmlTag()} `; } private generateHtmlTagEnd(): string { return `>\n`; } /** * Generate an array of the different combinations, for boolean properties */ private generateIfBoolean(type: FwkType): Array { // e.g: // [0] ng-if="properties.labelHidden && properties.allowHTML" // label-hidden // allow-html // [1] ng-if="properties.labelHidden && !properties.allowHTML" // label-hidden // [2] ng-if="!properties.labelHidden && properties.allowHTML" // allow-html // [3] ng-if="!properties.labelHidden && !properties.allowHTML" let ifCommand; if (type === FwkType.AngularJS) { ifCommand = HtmlTemplatesGenerator.ifDirectiveAngularJS; } else if (type === FwkType.Angular) { ifCommand = HtmlTemplatesGenerator.ifDirectiveAngular; } let booleanProps = []; for (let prop of this.propertiesInfo.properties) { if (HtmlTemplatesGenerator.isSpecific(prop) || !HtmlTemplatesGenerator.isBoolean(prop)) { continue; } booleanProps.push(prop); } // Get all the possible true/false combinations let combinations = HtmlTemplatesGenerator.booleanComb(booleanProps.length); let ifArray: Array = []; for (let combIndex = 0; combIndex < combinations.length; combIndex++) { let ifElem: Array = []; // One combination of booleans, e.g. '[true, true]' let combination = combinations[combIndex]; ifElem.push(`${ifCommand}="`); for (let valIndex = 0; valIndex < combination.length; valIndex++) { // One boolean, e.g. 'true' let booleanVal = combination[valIndex]; if (valIndex !== 0) { ifElem.push(' && '); } ifElem.push(`${booleanVal ? '' : '!'}properties.${booleanProps[valIndex].name}`); } ifElem.push('"\n\t'); // Iteration to get the required boolean properties for (let valIndex = 0; valIndex < combinations[combIndex].length; valIndex++) { let combination = combinations[combIndex]; let booleanVal = combination[valIndex]; if (booleanVal) { let propName = booleanProps[valIndex].name; let kebabPropName = kebabCase(propName); ifElem.push(`${kebabPropName}\n\t`); } } ifArray.push(ifElem.join('')) } return ifArray; } private generateSpecificProperties(type: FwkType): string { let specificProps = ""; for (let prop of this.propertiesInfo.properties) { if (!HtmlTemplatesGenerator.isSpecific(prop)) { continue; } if (type === FwkType.AngularJS) { specificProps += `ng-${prop.name.toLowerCase()}="properties.${prop.name}"\n\t` } else if (type === FwkType.Angular) { specificProps += `[${prop.name.toLowerCase()}]="properties.${prop.name}"\n\t` } } return specificProps; } protected generateProperties(type: FwkType): string { let props = ""; for (let prop of this.propertiesInfo.properties) { if (HtmlTemplatesGenerator.isToIgnore(prop) || HtmlTemplatesGenerator.isSpecific(prop) || HtmlTemplatesGenerator.isBoolean(prop)) { continue; } if(type === FwkType.Angular){ if (prop.bond === Bond.Variable) { props += `[(${prop.name})]="properties.${prop.name}"\n\t`; } else if (prop.bond != Bond.Constant) { props += `[${prop.name}]="properties.${prop.name}"\n\t`; } else { props += `${prop.name}="{{properties.${prop.name}}}"\n\t`; } } else{ props += `${kebabCase(prop.name)}="{{properties.${prop.name}}}"\n\t`; } } return props; } private static isSpecific(prop: Property): boolean { return HtmlTemplatesGenerator.specificProperties.includes(prop.name); } private static isToIgnore(prop: Property): boolean { return HtmlTemplatesGenerator.toIgnoreProperties.includes(prop.name); } private static isBoolean(prop: Property) { return prop.type === "boolean"; } private static booleanComb(nb: number): Array> { let globalArray: Array> = []; if (nb === 0) { return globalArray; } for (let ii = 0; ii < (1 << nb); ii++) { let boolArr = []; for (let jj = 0; jj < nb; jj++) { boolArr.push(Boolean(ii & (1 << jj))); } globalArray.push(boolArr); } return globalArray; } private writeFile(template: string, type: FwkType, outputDir: string) { let ext; if (type === FwkType.AngularJS) { ext = HtmlTemplatesGenerator.AngularJsFileExtension; } else if (type === FwkType.Angular) { ext = HtmlTemplatesGenerator.AngularFileExtension; } let filePath = `${outputDir}/${this.propertiesInfo.id}.${ext}`; fs.writeFileSync(filePath, template); } private getHtmlTag() { return kebabCase(this.propertiesInfo.id).toLowerCase(); } }